From 57a691a82168178a18fa89fb639935a5133270c0 Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Tue, 26 Sep 2023 15:15:53 -0700 Subject: [PATCH 01/86] chore: fix formatting for welcome action (#7545) * chore: fix formatting for welcome action * chore: format --- .../workflows/welcome_new_contributors.yml | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/workflows/welcome_new_contributors.yml b/.github/workflows/welcome_new_contributors.yml index 6e598ee4a..37ca9ef89 100644 --- a/.github/workflows/welcome_new_contributors.yml +++ b/.github/workflows/welcome_new_contributors.yml @@ -16,22 +16,21 @@ jobs: Welcome! It looks like this is your first pull request in Blockly, so here are a couple of tips: - - You can find tips about contributing to Blockly and how to - validate your changes on our - [developer site](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change). + - You can find tips about contributing to Blockly and how to + validate your changes on our + [developer site](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change). - - All contributors must sign the Google Contributor License - Agreement (CLA). If the google-cla bot leaves a comment on this - PR, make sure you follow the instructions. + - All contributors must sign the Google Contributor License + Agreement (CLA). If the google-cla bot leaves a comment on this + PR, make sure you follow the instructions. - - We use [conventional commits](https://www.conventionalcommits.org/) - to make versioning the package easier. Make sure your commit - message is in the [proper format](https://developers.google.com/blockly/guides/contribute/get-started/commits) - or [learn how to fix it](https://developers.google.com/blockly/guides/contribute/get-started/commits#fixing_non-conventional_commits). - - - If any of the other checks on this PR fail, you can click on - them to learn why. It might be that your change caused a test - failure, or that you need to double-check the - [style guide](https://developers.google.com/blockly/guides/contribute/core/style_guide). + - We use conventional commits to make versioning the package easier. Make sure your commit + message is in the [proper format](https://developers.google.com/blockly/guides/contribute/get-started/commits) + or [learn how to fix it](https://developers.google.com/blockly/guides/contribute/get-started/commits#fixing_non-conventional_commits). + + - If any of the other checks on this PR fail, you can click on + them to learn why. It might be that your change caused a test + failure, or that you need to double-check the + [style guide](https://developers.google.com/blockly/guides/contribute/core/style_guide). Thank you for opening this PR! A member of the Blockly team will review it soon. From 8b20f5321b4ffc2080cfb820b0c355e990c066cc Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Wed, 27 Sep 2023 18:52:06 +0200 Subject: [PATCH 02/86] fix(build): Fix broken npm install of Closure Compiler (#7547) --- package-lock.json | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 3fffb4e8f..6450f8eb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5839,6 +5839,35 @@ "linux" ] }, + "node_modules/google-closure-compiler-osx": { + "version": "20230802.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20230802.0.0.tgz", + "integrity": "sha512-ANAi/ux92Tt+Na7vFDLeK2hRzotjC5j+nxoPtE0OcuNcbjji5dREKoJxkq7r0YwRTCzAFZszK5ip/NPdTOdCEg==", + "cpu": [ + "x32", + "x64", + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/google-closure-compiler-windows": { + "version": "20230802.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20230802.0.0.tgz", + "integrity": "sha512-ZQPujoNiiUyTGl8zEGR/0yAygWnbMtX/NQ/S/EHVgq5nmYkvDEVuiVbgpPAmO9lzBTq0hvUTRRATZbTU2ISxgA==", + "cpu": [ + "x32", + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/got": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", @@ -11854,7 +11883,7 @@ "node_modules/vinyl-sourcemaps-apply": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, "dependencies": { "source-map": "^0.5.1" From cd6b14e99406ede628102b7effd56d42f632f963 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Thu, 28 Sep 2023 17:35:27 +0200 Subject: [PATCH 03/86] fix(build): Fix sourcemaps, re-update metadata (#7550) * fix(build): Revert "refactor: Remove $build$src infix from munged paths" This is a mostly-manual revert of commit 06d78af6a403370ed933d75fbe523860c15b8aec to fix an issue where the generated sourcemaps are missing the inline copies of the original .ts source files. * chore: Update metadata for 2020 Q3 release This is being done a second time as the revert of 06d78af causes a significant increase in the size of the build products. --- scripts/gulpfiles/build_tasks.js | 5 +++-- tests/scripts/check_metadata.sh | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/gulpfiles/build_tasks.js b/scripts/gulpfiles/build_tasks.js index cc95fec7f..8775f6918 100644 --- a/scripts/gulpfiles/build_tasks.js +++ b/scripts/gulpfiles/build_tasks.js @@ -163,7 +163,8 @@ for (let i = 1; i < chunks.length; i++) { * as munged by Closure Compiler. */ function modulePath(chunk) { - return 'module$' + chunk.entry.replace(/\.js$/, '').replaceAll('/', '$'); + const entryPath = path.posix.join(TSC_OUTPUT_DIR_POSIX, chunk.entry); + return 'module$' + entryPath.replace(/\.js$/, '').replaceAll('/', '$'); } const licenseRegex = `\\/\\*\\* @@ -555,7 +556,7 @@ function buildCompiled() { }; // Fire up compilation pipline. - return gulp.src(chunkOptions.js, {base: TSC_OUTPUT_DIR_POSIX}) + return gulp.src(chunkOptions.js, {base: './'}) .pipe(stripApacheLicense()) .pipe(gulp.sourcemaps.init()) .pipe(compile(options)) diff --git a/tests/scripts/check_metadata.sh b/tests/scripts/check_metadata.sh index 72d8f6512..d9b7326f1 100755 --- a/tests/scripts/check_metadata.sh +++ b/tests/scripts/check_metadata.sh @@ -35,8 +35,8 @@ readonly RELEASE_DIR='dist' # Q4 2022 9.1.1 903357 # Q1 2023 9.2.1 909181 # Q2 2023 9.3.3 887618 -# Q3 2023 10.1.3 818138 -readonly BLOCKLY_SIZE_EXPECTED=818138 +# Q3 2023 10.1.3 898859 +readonly BLOCKLY_SIZE_EXPECTED=898859 # Size of blocks_compressed.js # Q2 2019 2.20190722.0 75618 @@ -57,8 +57,8 @@ readonly BLOCKLY_SIZE_EXPECTED=818138 # Q4 2022 9.1.1 102190 # Q1 2023 9.2.1 101114 # Q2 2023 9.3.3 91848 -# Q3 2023 10.1.3 84772 -readonly BLOCKS_SIZE_EXPECTED=84772 +# Q3 2023 10.1.3 90150 +readonly BLOCKS_SIZE_EXPECTED=90150 # Size of blockly_compressed.js.gz # Q2 2019 2.20190722.0 180925 @@ -80,8 +80,8 @@ readonly BLOCKS_SIZE_EXPECTED=84772 # Q4 2022 9.1.1 179306 # Q1 2023 9.2.1 179814 # Q2 2023 9.3.3 175206 -# Q3 2023 10.1.3 177241 -readonly BLOCKLY_GZ_SIZE_EXPECTED=177241 +# Q3 2023 10.1.3 180553 +readonly BLOCKLY_GZ_SIZE_EXPECTED=180553 # Size of blocks_compressed.js.gz # Q2 2019 2.20190722.0 14552 @@ -102,8 +102,8 @@ readonly BLOCKLY_GZ_SIZE_EXPECTED=177241 # Q4 2022 9.1.1 17182 # Q1 2023 9.2.1 17262 # Q2 2023 9.3.3 16736 -# Q3 2023 10.1.3 16299 -readonly BLOCKS_GZ_SIZE_EXPECTED=16299 +# Q3 2023 10.1.3 16508 +readonly BLOCKS_GZ_SIZE_EXPECTED=16508 # ANSI colors readonly BOLD_GREEN='\033[1;32m' From e50d4f9fb0a8fe1afa50c23bcadb421eacf662ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 19:07:23 +0100 Subject: [PATCH 04/86] chore(deps): Bump @microsoft/api-extractor from 7.35.4 to 7.37.0 (#7510) Bumps [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) from 7.35.4 to 7.37.0. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.37.0/apps/api-extractor) --- updated-dependencies: - dependency-name: "@microsoft/api-extractor" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 252 +++++++++++----------------------------------- 1 file changed, 57 insertions(+), 195 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6450f8eb5..9e0d8fe62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -777,20 +777,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/@microsoft/api-documenter/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/@microsoft/api-documenter/node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -804,55 +790,22 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@microsoft/api-documenter/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@microsoft/api-documenter/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-documenter/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/@microsoft/api-extractor": { - "version": "7.35.4", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.35.4.tgz", - "integrity": "sha512-E/DIIlgu1ZW+AD+Y0UuVe/30rO+Km0CRkDU1aOKQntwKtv/+FodtRAUvzU/vAxq5lQHSsy6jJErLiXR6G3fupA==", + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.37.0.tgz", + "integrity": "sha512-df/wffWpDhYRw7kzdxeHGsCpim+dC8aFiZlsJb4uFvVPWhBZpDzOhQxSUTFx3Df1ORY+/JjuPR3fDE9Hq+PHzQ==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.27.3", + "@microsoft/api-extractor-model": "7.28.0", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.59.4", - "@rushstack/rig-package": "0.3.21", - "@rushstack/ts-command-line": "4.15.1", + "@rushstack/node-core-library": "3.60.0", + "@rushstack/rig-package": "0.5.0", + "@rushstack/ts-command-line": "4.16.0", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.22.1", - "semver": "~7.3.0", + "semver": "~7.5.4", "source-map": "~0.6.1", "typescript": "~5.0.4" }, @@ -861,14 +814,14 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.27.3.tgz", - "integrity": "sha512-fSFvw7otYHduOkyshjTbapKKgwF8bgquVHvgF8VgeKtMYvqXkoaj7W6VcM7PNY7E2bbblhUgC4XNdqZLD4SJGw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.0.tgz", + "integrity": "sha512-QIMtUVm1tqiKG+M6ciFgRShcDoovyltaeg+CbyOnyr7SMrp6gg0ojK5/nToMqR9kAvsTS4QVgW4Twl50EoAjcw==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.59.4" + "@rushstack/node-core-library": "3.60.0" } }, "node_modules/@microsoft/api-extractor/node_modules/source-map": { @@ -1031,9 +984,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "3.59.4", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.59.4.tgz", - "integrity": "sha512-YAKJDC6Mz/KA1D7bvB88WaRX3knt/ZuLzkRu5G9QADGSjLtvTWzCNCytRF2PCSaaHOZaZsWul4F1KQdgFgUDqA==", + "version": "3.60.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.60.0.tgz", + "integrity": "sha512-PcyrqhILvzU+65wMFybQ2VeGNnU5JzhDq2OvUi3j6jPUxyllM7b2hrRUwCuVaYboewYzIbpzXFzgxe2K7ii1nw==", "dev": true, "dependencies": { "colors": "~1.2.1", @@ -1041,7 +994,7 @@ "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", - "semver": "~7.3.0", + "semver": "~7.5.4", "z-schema": "~5.0.2" }, "peerDependencies": { @@ -1053,42 +1006,10 @@ } } }, - "node_modules/@rushstack/node-core-library/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/@rushstack/rig-package": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.21.tgz", - "integrity": "sha512-6KPBuZYP/b9U0Qwy1J4vjYtXvLavdmVT7mMelErfqqZ3P/ywoxlFITGr9ZbqD1zmfIVrIfC2jrM6gfm7OHPRhQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.0.tgz", + "integrity": "sha512-bGnOW4DWHOePDiABKy6qyqYJl9i7fKn4bRucExRVt5QzyPxuVHMl8CMmCabtoNSpXzgG3qymWOrMoa/W2PpJrw==", "dev": true, "dependencies": { "resolve": "~1.22.1", @@ -1096,9 +1017,9 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.15.1.tgz", - "integrity": "sha512-EL4jxZe5fhb1uVL/P/wQO+Z8Rc8FMiWJ1G7VgnPDvdIt5GVjRfK7vwzder1CZQiX3x0PY6uxENYLNGTFd1InRQ==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.0.tgz", + "integrity": "sha512-WJKhdR9ThK9Iy7t78O3at7I3X4Ssp5RRZay/IQa8NywqkFy/DQbT3iLouodMMdUwLZD9n8n++xLubVd3dkmpkg==", "dev": true, "dependencies": { "@types/argparse": "1.0.38", @@ -1363,21 +1284,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/parser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.1.0.tgz", @@ -1509,21 +1415,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/types": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.1.0.tgz", @@ -1566,22 +1457,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "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, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.6.0.tgz", @@ -1681,21 +1556,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.1.0.tgz", @@ -4193,21 +4053,6 @@ "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -5002,6 +4847,38 @@ "node": ">=0.10.0" } }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-extra/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -9096,21 +8973,6 @@ "rimraf": "bin.js" } }, - "node_modules/patch-package/node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/patch-package/node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -10259,9 +10121,9 @@ "dev": true }, "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" From cc47c3a8afe5e7aec72cefe8969c5842999c3f39 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Thu, 28 Sep 2023 21:19:04 +0200 Subject: [PATCH 05/86] chore(tests): Fix whitespace inconsistency (#7553) --- tests/scripts/check_metadata.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/scripts/check_metadata.sh b/tests/scripts/check_metadata.sh index d9b7326f1..15e3cdb85 100755 --- a/tests/scripts/check_metadata.sh +++ b/tests/scripts/check_metadata.sh @@ -29,10 +29,10 @@ readonly RELEASE_DIR='dist' # Q3 2021 6.20210701.0 808807 (late-quarter goog.module conversion) # Q4 2021 7.20211209.0-beta.0 920002 # Q4 2021 7.20211209.0 929665 -# Q2 2022 8.0.0 928056 +# Q2 2022 8.0.0 928056 # Q3 2022 8.0.0 1040413 (mid-quarter typescript conversion) -# Q4 2022 8.0.0 870104 -# Q4 2022 9.1.1 903357 +# Q4 2022 8.0.0 870104 +# Q4 2022 9.1.1 903357 # Q1 2023 9.2.1 909181 # Q2 2023 9.3.3 887618 # Q3 2023 10.1.3 898859 @@ -51,10 +51,10 @@ readonly BLOCKLY_SIZE_EXPECTED=898859 # Q3 2021 6.20210701.0 76669 # Q4 2021 7.20211209.0-beta.0 82054 # Q4 2021 7.20211209.0 86966 -# Q2 2022 8.0.0 90769 +# Q2 2022 8.0.0 90769 # Q3 2022 8.0.0 102176 (mid-quarter typescript conversion) -# Q4 2022 8.0.0 102213 -# Q4 2022 9.1.1 102190 +# Q4 2022 8.0.0 102213 +# Q4 2022 9.1.1 102190 # Q1 2023 9.2.1 101114 # Q2 2023 9.3.3 91848 # Q3 2023 10.1.3 90150 @@ -74,10 +74,10 @@ readonly BLOCKS_SIZE_EXPECTED=90150 # Q3 2021 6.20210701.0 152025 (late-quarter goog.module conversion) # Q4 2021 7.20211209.0-beta.0 169863 # Q4 2021 7.20211209.0 171759 -# Q2 2022 8.0.0 173997 +# Q2 2022 8.0.0 173997 # Q3 2022 8.0.0 185766 (mid-quarter typescript conversion) -# Q4 2022 8.0.0 175140 -# Q4 2022 9.1.1 179306 +# Q4 2022 8.0.0 175140 +# Q4 2022 9.1.1 179306 # Q1 2023 9.2.1 179814 # Q2 2023 9.3.3 175206 # Q3 2023 10.1.3 180553 @@ -96,10 +96,10 @@ readonly BLOCKLY_GZ_SIZE_EXPECTED=180553 # Q3 2021 6.20210701.0 15284 # Q4 2021 7.20211209.0-beta.0 16616 # Q4 2021 7.20211209.0 15760 -# Q2 2022 8.0.0 16192 +# Q2 2022 8.0.0 16192 # Q3 2022 8.0.0 17016 (mid-quarter typescript conversion) -# Q4 2022 8.0.0 17188 -# Q4 2022 9.1.1 17182 +# Q4 2022 8.0.0 17188 +# Q4 2022 9.1.1 17182 # Q1 2023 9.2.1 17262 # Q2 2023 9.3.3 16736 # Q3 2023 10.1.3 16508 From ca4fa7e4fb75b0f9ae8b1d878a2b18354ed5a82f Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Thu, 28 Sep 2023 15:21:26 -0700 Subject: [PATCH 06/86] fix: style attribute for xml in ws factory (#7554) --- demos/blockfactory/workspacefactory/wfactory_generator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/blockfactory/workspacefactory/wfactory_generator.js b/demos/blockfactory/workspacefactory/wfactory_generator.js index 9f115c40b..ca1a47b09 100644 --- a/demos/blockfactory/workspacefactory/wfactory_generator.js +++ b/demos/blockfactory/workspacefactory/wfactory_generator.js @@ -45,7 +45,7 @@ WorkspaceFactoryGenerator.prototype.generateToolboxXml = function() { // Create DOM for XML. var xmlDom = Blockly.utils.xml.createElement('xml'); xmlDom.id = 'toolbox'; - xmlDom.style.display = 'none'; + xmlDom.setAttribute('style', 'display: none'); if (!this.model.hasElements()) { // Toolbox has no categories. Use XML directly from workspace. @@ -111,7 +111,7 @@ WorkspaceFactoryGenerator.prototype.generateWorkspaceXml = function() { // Generate XML and set attributes. var xmlDom = Blockly.Xml.workspaceToDom(this.hiddenWorkspace); xmlDom.id = 'workspaceBlocks'; - xmlDom.style.display = 'none'; + xmlDom.setAttribute('style', 'display: none'); return xmlDom; }; From cf5d9985c72b8a4fdb719941737b2a51bb5d2baf Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 29 Sep 2023 10:29:41 -0700 Subject: [PATCH 07/86] fix: include loaders in gh-pages commits (#7559) --- scripts/gulpfiles/git_tasks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gulpfiles/git_tasks.js b/scripts/gulpfiles/git_tasks.js index ebf9bb356..7c320cd87 100644 --- a/scripts/gulpfiles/git_tasks.js +++ b/scripts/gulpfiles/git_tasks.js @@ -25,6 +25,7 @@ const EXTRAS = [ 'build/msg', 'dist/*_compressed.js*', 'node_modules/@blockly', + 'build/*.loader.mjs', ]; let upstream = null; From 971bc1107bbe352c2bc6558970ff49b7fc69ef67 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 29 Sep 2023 10:57:58 -0700 Subject: [PATCH 08/86] fix: missing loaders for appengine deployment (#7560) --- scripts/gulpfiles/appengine_tasks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gulpfiles/appengine_tasks.js b/scripts/gulpfiles/appengine_tasks.js index 1f08ca3d5..ddbd2f45f 100644 --- a/scripts/gulpfiles/appengine_tasks.js +++ b/scripts/gulpfiles/appengine_tasks.js @@ -51,7 +51,7 @@ function copyStaticSrc(done) { * Prerequisite: clean, build. */ function copyBuilt(done) { - return gulp.src(['build/msg/*', 'dist/*_compressed.js*'], {base: '.'}) + return gulp.src(['build/msg/*', 'dist/*_compressed.js*', 'build/*.loader.mjs'], {base: '.'}) .pipe(gulp.dest(demoStaticTmpDir)); } From 04fa7996503d74ece151d9b19f62c7776621f82f Mon Sep 17 00:00:00 2001 From: Sanskar Mundhra <118104021+SunMoon97@users.noreply.github.com> Date: Sat, 30 Sep 2023 03:28:05 +0530 Subject: [PATCH 09/86] chore: remove bump script from package.json (#7548) * Removed bump script from package.json #7543 * chore: remove bump script from package.json * chore: remove bump script from package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index d0c8d2718..1d572d31e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "build:compressed": "exit 1 # Deprecated; use \"npm run minify\" instead.", "build:js": "exit 1 # Deprecated; use \"npm run tsc\" instead.", "build:langfiles": "exit 1 # Deprecated; use \"npm run langfiles\" instead.", - "bump": "npm --no-git-tag-version version 4.$(date +'%Y%m%d').0", "clean": "gulp clean", "deployDemos": "npm ci && gulp deployDemos", "deployDemos:beta": "npm ci && gulp deployDemosBeta", From 787ac1bc367fd6051be7caff9e410fdb448dcff8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:26:42 -0700 Subject: [PATCH 10/86] chore(deps): Bump @typescript-eslint/eslint-plugin from 6.6.0 to 6.7.3 (#7563) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.6.0 to 6.7.3. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.3/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 130 +++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index e815f17a8..62e87f663 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1144,9 +1144,9 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, "node_modules/@types/node": { @@ -1162,9 +1162,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", "dev": true }, "node_modules/@types/vinyl": { @@ -1203,16 +1203,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.6.0.tgz", - "integrity": "sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz", + "integrity": "sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.6.0", - "@typescript-eslint/type-utils": "6.6.0", - "@typescript-eslint/utils": "6.6.0", - "@typescript-eslint/visitor-keys": "6.6.0", + "@typescript-eslint/scope-manager": "6.7.3", + "@typescript-eslint/type-utils": "6.7.3", + "@typescript-eslint/utils": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1238,13 +1238,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.6.0.tgz", - "integrity": "sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", + "integrity": "sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", - "@typescript-eslint/visitor-keys": "6.6.0" + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1255,9 +1255,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.6.0.tgz", - "integrity": "sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", + "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1268,12 +1268,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.6.0.tgz", - "integrity": "sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", + "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/types": "6.7.3", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1332,13 +1332,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.6.0.tgz", - "integrity": "sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz", + "integrity": "sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.6.0", - "@typescript-eslint/utils": "6.6.0", + "@typescript-eslint/typescript-estree": "6.7.3", + "@typescript-eslint/utils": "6.7.3", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1359,9 +1359,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.6.0.tgz", - "integrity": "sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", + "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1372,13 +1372,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.6.0.tgz", - "integrity": "sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz", + "integrity": "sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", - "@typescript-eslint/visitor-keys": "6.6.0", + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1399,12 +1399,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.6.0.tgz", - "integrity": "sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", + "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/types": "6.7.3", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1458,17 +1458,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.6.0.tgz", - "integrity": "sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.3.tgz", + "integrity": "sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.6.0", - "@typescript-eslint/types": "6.6.0", - "@typescript-eslint/typescript-estree": "6.6.0", + "@typescript-eslint/scope-manager": "6.7.3", + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/typescript-estree": "6.7.3", "semver": "^7.5.4" }, "engines": { @@ -1483,13 +1483,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.6.0.tgz", - "integrity": "sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", + "integrity": "sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", - "@typescript-eslint/visitor-keys": "6.6.0" + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1500,9 +1500,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.6.0.tgz", - "integrity": "sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", + "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1513,13 +1513,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.6.0.tgz", - "integrity": "sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz", + "integrity": "sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", - "@typescript-eslint/visitor-keys": "6.6.0", + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1540,12 +1540,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.6.0.tgz", - "integrity": "sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", + "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/types": "6.7.3", "eslint-visitor-keys": "^3.4.1" }, "engines": { From bf53b3a053875c8adcc40882016c21569252ba75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:27:15 -0700 Subject: [PATCH 11/86] chore(deps): Bump glob from 10.3.4 to 10.3.10 (#7565) Bumps [glob](https://github.com/isaacs/node-glob) from 10.3.4 to 10.3.10. - [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md) - [Commits](https://github.com/isaacs/node-glob/compare/v10.3.4...v10.3.10) --- updated-dependencies: - dependency-name: glob dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 62e87f663..5b60606c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -673,9 +673,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { "ansi-regex": "^6.0.1" @@ -5216,19 +5216,19 @@ } }, "node_modules/glob": { - "version": "10.3.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz", - "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", + "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { - "glob": "dist/cjs/src/bin.js" + "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7105,9 +7105,9 @@ } }, "node_modules/jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" From 761c24c9227245dab8ce29dc71e04607dec151c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:27:35 -0700 Subject: [PATCH 12/86] chore(deps): Bump @microsoft/api-extractor from 7.37.0 to 7.38.0 (#7564) Bumps [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) from 7.37.0 to 7.38.0. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.38.0/apps/api-extractor) --- updated-dependencies: - dependency-name: "@microsoft/api-extractor" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b60606c4..1e35c9d78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -791,17 +791,17 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.37.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.37.0.tgz", - "integrity": "sha512-df/wffWpDhYRw7kzdxeHGsCpim+dC8aFiZlsJb4uFvVPWhBZpDzOhQxSUTFx3Df1ORY+/JjuPR3fDE9Hq+PHzQ==", + "version": "7.38.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.38.0.tgz", + "integrity": "sha512-e1LhZYnfw+JEebuY2bzhw0imDCl1nwjSThTrQqBXl40hrVo6xm3j/1EpUr89QyzgjqmAwek2ZkIVZbrhaR+cqg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.0", + "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.60.0", - "@rushstack/rig-package": "0.5.0", - "@rushstack/ts-command-line": "4.16.0", + "@rushstack/node-core-library": "3.61.0", + "@rushstack/rig-package": "0.5.1", + "@rushstack/ts-command-line": "4.16.1", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.22.1", @@ -814,14 +814,14 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.0.tgz", - "integrity": "sha512-QIMtUVm1tqiKG+M6ciFgRShcDoovyltaeg+CbyOnyr7SMrp6gg0ojK5/nToMqR9kAvsTS4QVgW4Twl50EoAjcw==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.2.tgz", + "integrity": "sha512-vkojrM2fo3q4n4oPh4uUZdjJ2DxQ2+RnDQL/xhTWSRUNPF6P4QyrvY357HBxbnltKcYu+nNNolVqc6TIGQ73Ig==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.60.0" + "@rushstack/node-core-library": "3.61.0" } }, "node_modules/@microsoft/api-extractor/node_modules/source-map": { @@ -984,9 +984,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "3.60.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.60.0.tgz", - "integrity": "sha512-PcyrqhILvzU+65wMFybQ2VeGNnU5JzhDq2OvUi3j6jPUxyllM7b2hrRUwCuVaYboewYzIbpzXFzgxe2K7ii1nw==", + "version": "3.61.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.61.0.tgz", + "integrity": "sha512-tdOjdErme+/YOu4gPed3sFS72GhtWCgNV9oDsHDnoLY5oDfwjKUc9Z+JOZZ37uAxcm/OCahDHfuu2ugqrfWAVQ==", "dev": true, "dependencies": { "colors": "~1.2.1", @@ -1007,9 +1007,9 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.0.tgz", - "integrity": "sha512-bGnOW4DWHOePDiABKy6qyqYJl9i7fKn4bRucExRVt5QzyPxuVHMl8CMmCabtoNSpXzgG3qymWOrMoa/W2PpJrw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", + "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", "dev": true, "dependencies": { "resolve": "~1.22.1", @@ -1017,9 +1017,9 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.0.tgz", - "integrity": "sha512-WJKhdR9ThK9Iy7t78O3at7I3X4Ssp5RRZay/IQa8NywqkFy/DQbT3iLouodMMdUwLZD9n8n++xLubVd3dkmpkg==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.1.tgz", + "integrity": "sha512-+OCsD553GYVLEmz12yiFjMOzuPeCiZ3f8wTiFHL30ZVXexTyPmgjwXEhg2K2P0a2lVf+8YBy7WtPoflB2Fp8/A==", "dev": true, "dependencies": { "@types/argparse": "1.0.38", From c455e0c1e5bb2ab9b1ce47ee89df2822393811d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:28:15 -0700 Subject: [PATCH 13/86] chore(deps): Bump eslint-plugin-jsdoc from 46.6.0 to 46.8.2 (#7512) Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 46.6.0 to 46.8.2. - [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases) - [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc) - [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.6.0...v46.8.2) --- updated-dependencies: - dependency-name: eslint-plugin-jsdoc dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e35c9d78..0ac6b98d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4031,9 +4031,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "46.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.6.0.tgz", - "integrity": "sha512-T/1gzsvnX45qABzyPEonEhFDttkTn7Igm/X89TXIkTLBOsNl2GYtyBqQPZGXZZ8J5VBzEhiCMvI2P2kXX4dnFw==", + "version": "46.8.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz", + "integrity": "sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ==", "dev": true, "dependencies": { "@es-joy/jsdoccomment": "~0.40.1", From 6b023b3a32725437ff3cf0a8e7c01db33de100ad Mon Sep 17 00:00:00 2001 From: Trey Pisano <126501514+treypisano@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:14:12 -0400 Subject: [PATCH 14/86] fix: comment change event fires block change event (#7505) * add fire event to comment change * change variable names to make readable * add oldtext field to commenticon * remove debugger * remove oldtext field * add firing block change event to setText * add fire to setText * fix: setCommentText fire block change when icon removed * remove whitespace * NOT PASSING TESTS: fix block test fails * fix: remove duplicate events so tests pass * fix: remove whitespace * fix: run format * refactor: add early returns to onTextChange for readability * remove console.log * disable events temporarily when setText called in setCommentText * refactor: move fire event to original position * fix: run format * fix: move fire event so it happpens after events are enabled and disabled --- core/block.ts | 22 ++++++++++++---------- core/icons/comment_icon.ts | 28 +++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/core/block.ts b/core/block.ts index 927d74b0c..578015d3a 100644 --- a/core/block.ts +++ b/core/block.ts @@ -2208,6 +2208,18 @@ export class Block implements IASTNodeLocation, IDeletable { const comment = this.getIcon(CommentIcon.TYPE) as CommentIcon | null; const oldText = comment?.getText() ?? null; if (oldText === text) return; + if (text !== null) { + let comment = this.getIcon(CommentIcon.TYPE) as CommentIcon | undefined; + if (!comment) { + comment = this.addIcon(new CommentIcon(this)); + } + eventUtils.disable(); + comment.setText(text); + eventUtils.enable(); + } else { + this.removeIcon(CommentIcon.TYPE); + } + eventUtils.fire( new (eventUtils.get(eventUtils.BLOCK_CHANGE))( this, @@ -2217,16 +2229,6 @@ export class Block implements IASTNodeLocation, IDeletable { text, ), ); - - if (text !== null) { - let comment = this.getIcon(CommentIcon.TYPE) as CommentIcon | undefined; - if (!comment) { - comment = this.addIcon(new CommentIcon(this)); - } - comment.setText(text); - } else { - this.removeIcon(CommentIcon.TYPE); - } } /** diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index d52782437..d99588fe6 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -155,6 +155,16 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { /** Sets the text of this comment. Updates any bubbles if they are visible. */ setText(text: string) { + const oldText = this.text; + eventUtils.fire( + new (eventUtils.get(eventUtils.BLOCK_CHANGE))( + this.sourceBlock, + 'comment', + null, + oldText, + text, + ), + ); this.text = text; this.textInputBubble?.setText(this.text); this.textBubble?.setText(this.text); @@ -217,9 +227,21 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { * the input bubble. */ onTextChange(): void { - if (this.textInputBubble) { - this.text = this.textInputBubble.getText(); - } + if (!this.textInputBubble) return; + + const newText = this.textInputBubble.getText(); + if (this.text === newText) return; + + eventUtils.fire( + new (eventUtils.get(eventUtils.BLOCK_CHANGE))( + this.sourceBlock, + 'comment', + null, + this.text, + newText, + ), + ); + this.text = newText; } /** From 5151b28e7dc5bb1cf8ad7e620e8eb1ff5bfcc716 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 2 Oct 2023 13:16:03 -0700 Subject: [PATCH 15/86] fix: color field sizing being incorrect (#7566) --- core/field_colour.ts | 26 +++++++++----------------- core/renderers/zelos/constants.ts | 4 ++-- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/core/field_colour.ts b/core/field_colour.ts index 1b022b64c..de771c9af 100644 --- a/core/field_colour.ts +++ b/core/field_colour.ts @@ -262,28 +262,20 @@ export class FieldColour extends Field { */ protected updateSize_(margin?: number) { const constants = this.getConstants(); - const xOffset = - margin !== undefined - ? margin - : !this.isFullBlockField() - ? constants!.FIELD_BORDER_RECT_X_PADDING - : 0; - let totalWidth = xOffset * 2; - let contentWidth = 0; - if (!this.isFullBlockField()) { - contentWidth = constants!.FIELD_COLOUR_DEFAULT_WIDTH; - totalWidth += contentWidth; - } - - let totalHeight = constants!.FIELD_TEXT_HEIGHT; - if (!this.isFullBlockField()) { - totalHeight = Math.max(totalHeight, constants!.FIELD_BORDER_RECT_HEIGHT); + let totalWidth; + let totalHeight; + if (this.isFullBlockField()) { + const xOffset = margin ?? 0; + totalWidth = xOffset * 2; + totalHeight = constants!.FIELD_TEXT_HEIGHT; + } else { + totalWidth = constants!.FIELD_COLOUR_DEFAULT_WIDTH; + totalHeight = constants!.FIELD_COLOUR_DEFAULT_HEIGHT; } this.size_.height = totalHeight; this.size_.width = totalWidth; - this.positionTextElement_(xOffset, contentWidth); this.positionBorderRect_(); } diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index e13a57e52..73a600c58 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -217,9 +217,9 @@ export class ConstantProvider extends BaseConstantProvider { this.FIELD_DROPDOWN_SVG_ARROW_PADDING = this.FIELD_BORDER_RECT_X_PADDING; - this.FIELD_COLOUR_DEFAULT_WIDTH = 2 * this.GRID_UNIT; + this.FIELD_COLOUR_DEFAULT_WIDTH = 6 * this.GRID_UNIT; - this.FIELD_COLOUR_DEFAULT_HEIGHT = 4 * this.GRID_UNIT; + this.FIELD_COLOUR_DEFAULT_HEIGHT = 8 * this.GRID_UNIT; this.FIELD_CHECKBOX_X_OFFSET = 1 * this.GRID_UNIT; From 5ad6a587ec9453df4b6ab8aa0324bbb1a4798f6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:11:18 -0700 Subject: [PATCH 16/86] chore(deps): Bump rimraf from 5.0.1 to 5.0.5 (#7578) Bumps [rimraf](https://github.com/isaacs/rimraf) from 5.0.1 to 5.0.5. - [Changelog](https://github.com/isaacs/rimraf/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/rimraf/compare/v5.0.1...v5.0.5) --- updated-dependencies: - dependency-name: rimraf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49cf4fe23..9b71c9c17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10017,15 +10017,15 @@ "dev": true }, "node_modules/rimraf": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", - "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", "dev": true, "dependencies": { - "glob": "^10.2.5" + "glob": "^10.3.7" }, "bin": { - "rimraf": "dist/cjs/src/bin.js" + "rimraf": "dist/esm/bin.mjs" }, "engines": { "node": ">=14" From 5dbde561be617b6220779f18be2d6591be1fc115 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:17:11 -0700 Subject: [PATCH 17/86] chore(deps): Bump @microsoft/api-documenter from 7.22.33 to 7.23.9 (#7577) Bumps [@microsoft/api-documenter](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-documenter) from 7.22.33 to 7.23.9. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-documenter/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-documenter_v7.23.9/apps/api-documenter) --- updated-dependencies: - dependency-name: "@microsoft/api-documenter" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 58 +++++------------------------------------------ 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b71c9c17..5d9c8ed49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -705,15 +705,15 @@ } }, "node_modules/@microsoft/api-documenter": { - "version": "7.22.33", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.22.33.tgz", - "integrity": "sha512-9UUe5Z/vbTlMQy3kbSqPaJN7e3CT4LsfNFyP8szfdQEHXiO6BV2ZwwYIUtbQObgaKt7foL4A/cqRMKqhRIi7VQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.9.tgz", + "integrity": "sha512-CvOy3JF0oCDm3GDqce3uFS9QGO72lfOEgVbvpje32O+ug/WoL8ITOg2jZszMtowuClasPbpEcEoVsHJJLePirg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.27.6", + "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.59.7", - "@rushstack/ts-command-line": "4.15.2", + "@rushstack/node-core-library": "3.61.0", + "@rushstack/ts-command-line": "4.16.1", "colors": "~1.2.1", "js-yaml": "~3.13.1", "resolve": "~1.22.1" @@ -722,52 +722,6 @@ "api-documenter": "bin/api-documenter" } }, - "node_modules/@microsoft/api-documenter/node_modules/@microsoft/api-extractor-model": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.27.6.tgz", - "integrity": "sha512-eiCnlayyum1f7fS2nA9pfIod5VCNR1G+Tq84V/ijDrKrOFVa598BLw145nCsGDMoFenV6ajNi2PR5WCwpAxW6Q==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.59.7" - } - }, - "node_modules/@microsoft/api-documenter/node_modules/@rushstack/node-core-library": { - "version": "3.59.7", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz", - "integrity": "sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw==", - "dev": true, - "dependencies": { - "colors": "~1.2.1", - "fs-extra": "~7.0.1", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.22.1", - "semver": "~7.5.4", - "z-schema": "~5.0.2" - }, - "peerDependencies": { - "@types/node": "*" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.15.2.tgz", - "integrity": "sha512-5+C2uoJY8b+odcZD6coEe2XNC4ZjGB4vCMESbqW/8DHRWC/qIHfANdmN9F1wz/lAgxz72i7xRoVtPY2j7e4gpQ==", - "dev": true, - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, "node_modules/@microsoft/api-documenter/node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", From ea253a0542460ee1f4f5f7478889bbfe19e06ee6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:17:36 -0700 Subject: [PATCH 18/86] chore(deps): Bump eslint from 8.48.0 to 8.51.0 (#7579) Bumps [eslint](https://github.com/eslint/eslint) from 8.48.0 to 8.51.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.48.0...v8.51.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5d9c8ed49..31d6ab3aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -411,9 +411,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", - "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -517,9 +517,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3907,16 +3907,16 @@ } }, "node_modules/eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", - "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.48.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/js": "8.51.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", From 8d7fc1365a37101e7581038b59f3ce55bd0a7c12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:17:49 -0700 Subject: [PATCH 19/86] chore(deps): Bump @blockly/dev-tools from 7.0.3 to 7.1.0 (#7580) Bumps [@blockly/dev-tools](https://github.com/google/blockly-samples/tree/HEAD/plugins/dev-tools) from 7.0.3 to 7.1.0. - [Release notes](https://github.com/google/blockly-samples/releases) - [Changelog](https://github.com/google/blockly-samples/blob/master/plugins/dev-tools/CHANGELOG.md) - [Commits](https://github.com/google/blockly-samples/commits/@blockly/dev-tools@7.1.0/plugins/dev-tools) --- updated-dependencies: - dependency-name: "@blockly/dev-tools" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31d6ab3aa..796e3b014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -265,9 +265,9 @@ } }, "node_modules/@blockly/dev-tools": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-7.0.3.tgz", - "integrity": "sha512-IyupTGAx0yMQImOKyS0xnqe6WKYwwh9B+4EHT5VlNORrku4TxfJfM0rsVyeacOvAG6hBHAE9J9VqYih79WNFfA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-7.1.0.tgz", + "integrity": "sha512-6Z3RfYcFRWhVhSjOwnE3vFr5xPW7WPQb2POjOCzvaPoevHZf7mSkCAOcyuNck5gLCms9TK96B1ezzimMAuo8Sg==", "dev": true, "dependencies": { "@blockly/block-test": "^5.0.0", From 2747ded23383bfc1b71899254961d90de6c28fd5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:18:06 -0700 Subject: [PATCH 20/86] chore(deps): Bump webdriverio from 8.16.7 to 8.16.22 (#7581) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.16.7 to 8.16.22. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.22/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 152 ++++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 71 deletions(-) diff --git a/package-lock.json b/package-lock.json index 796e3b014..6419fc9b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -147,21 +147,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -1092,9 +1092,9 @@ "dev": true }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", "dev": true }, "node_modules/@types/json-schema": { @@ -1110,9 +1110,9 @@ "dev": true }, "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", + "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", "dev": true }, "node_modules/@types/semver": { @@ -1138,9 +1138,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", + "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", "dev": true, "dependencies": { "@types/node": "*" @@ -1529,14 +1529,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.16.7", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.7.tgz", - "integrity": "sha512-cdUQ7Hy3608b9w2pbrm6Qagv7r8JpxSLzg7X7LEXQTAD0bS8w6VuA9DzI2GVcUXLijLUlAfHwpJUlcL5Yt3R/w==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.22.tgz", + "integrity": "sha512-sxqiVUEq++GFDKeR+HfzlgNhEbYuJZlrkU09p2rZzCRpPM3ty4azzdHB+XEdHHJJlV4UguvqUkp7n2126d9SAQ==", "dev": true, "dependencies": { - "@wdio/logger": "8.11.0", - "@wdio/types": "8.16.7", - "@wdio/utils": "8.16.7", + "@wdio/logger": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1560,9 +1560,9 @@ } }, "node_modules/@wdio/logger": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.11.0.tgz", - "integrity": "sha512-IsuKSaYi7NKEdgA57h8muzlN/MVp1dQG+V4C//7g4m03YJUnNQLvDhJzLjdeNTfvZy61U7foQSyt+3ktNzZkXA==", + "version": "8.16.17", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.16.17.tgz", + "integrity": "sha512-zeQ41z3T+b4IsrriZZipayXxLNDuGsm7TdExaviNGojPVrIsQUCSd/FvlLHM32b7ZrMyInHenu/zx1cjAZO71g==", "dev": true, "dependencies": { "chalk": "^5.1.2", @@ -1632,9 +1632,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.16.7", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.7.tgz", - "integrity": "sha512-s7fSO5CbrFdM5gsLgXzdCbZykJzZ7bpfxdW3v7NT0IQMABlv4cYpesK66DHQGjSG8Rr3LEqsMmpkt2TlMiwWVQ==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.22.tgz", + "integrity": "sha512-bg30seCgYu5JXukJ7M0qWKZLNATpKROvnl5/lRSOu4oopjm28UUan/+gHfHfyJ3MJ2uFNhaIVotPAvUziVJAdg==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1644,14 +1644,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.16.7", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.7.tgz", - "integrity": "sha512-uId5CapZSGCIqXjdOB8nuzd9WgHNkay2Imw3u0faOn0iyPVw3pF4r41xEBqtDkAnrOcaxmLvvyjuhEl6PvTm+w==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.22.tgz", + "integrity": "sha512-1hQjm7Jweiz+ABakS33TyWXYoxEg7LxL12RqbEYqtGB6ZTJhik+Cwyj/jcJbETSjiYJflmHxDvhFwuOkLR8ljg==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", - "@wdio/logger": "8.11.0", - "@wdio/types": "8.16.7", + "@wdio/logger": "8.16.17", + "@wdio/types": "8.16.22", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -1661,6 +1661,7 @@ "import-meta-resolve": "^3.0.0", "locate-app": "^2.1.0", "safaridriver": "^0.1.0", + "split2": "^4.2.0", "wait-port": "^1.0.4" }, "engines": { @@ -2640,12 +2641,12 @@ } }, "node_modules/cacheable-request": { - "version": "10.2.13", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.13.tgz", - "integrity": "sha512-3SD4rrMu1msNGEtNSt8Od6enwdo//U9s4ykmXfA2TD58kcLkCobtCDiby7kNyj7a/Q7lz/mAesAFI54rTdnvBA==", + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "dependencies": { - "@types/http-cache-semantics": "^4.0.1", + "@types/http-cache-semantics": "^4.0.2", "get-stream": "^6.0.1", "http-cache-semantics": "^4.1.1", "keyv": "^4.5.3", @@ -3550,9 +3551,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1188743", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1188743.tgz", - "integrity": "sha512-FZDQC58vLiGR2mjSgsMzU8aEJieovMonIyxf38b775eYdIfAYgSzyAWnDf0Eq6ouF/L9qcbqR8jcQeIC34jp/w==", + "version": "0.0.1203626", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz", + "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==", "dev": true }, "node_modules/dir-glob": { @@ -3695,9 +3696,9 @@ } }, "node_modules/edgedriver": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-5.3.6.tgz", - "integrity": "sha512-AvrkKsaMx8X5M64NVgPTfA+XTnOv6bvxH1Cp1m8cBQQVD0HEaC9OJMwPV9Kmqnxh0fCL7VJiBKZH5YOfikbB0g==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-5.3.7.tgz", + "integrity": "sha512-E1qNFEA9NbaCPSvGaeZhyd7mEZLar+oFS0NRAe5TehJcQ3cayoUdJE5uOFrbxdv/rM4NEPH7aK9a9kgG09rszA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -7288,9 +7289,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -9575,9 +9576,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.3.1.tgz", - "integrity": "sha512-pphNW/msgOUSkJbH58x8sqpq8uQj6b0ZKGxEsLKMUnGorRcDjrUaLS+39+/ub41JNTwrrMyJcUB8+YZs3mbwqw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.4.0.tgz", + "integrity": "sha512-HT3RRs7sTfY22KuPQJkD/XjbTbxgP2Je5HPt6H6JEGvcjHd5Lqru75EbrP3tb4FYjNJ+DjLp+MNQTFQU0mhXNw==", "dev": true, "engines": { "node": ">=16" @@ -9599,9 +9600,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.3.1.tgz", - "integrity": "sha512-pphNW/msgOUSkJbH58x8sqpq8uQj6b0ZKGxEsLKMUnGorRcDjrUaLS+39+/ub41JNTwrrMyJcUB8+YZs3mbwqw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.4.0.tgz", + "integrity": "sha512-HT3RRs7sTfY22KuPQJkD/XjbTbxgP2Je5HPt6H6JEGvcjHd5Lqru75EbrP3tb4FYjNJ+DjLp+MNQTFQU0mhXNw==", "dev": true, "engines": { "node": ">=16" @@ -10595,6 +10596,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -11726,9 +11736,9 @@ } }, "node_modules/wait-port": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.0.4.tgz", - "integrity": "sha512-w8Ftna3h6XSFWWc2JC5gZEgp64nz8bnaTp5cvzbJSZ53j+omktWTDdwXxEF0jM8YveviLgFWvNGrSvRHnkyHyw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz", + "integrity": "sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==", "dev": true, "dependencies": { "chalk": "^4.1.2", @@ -11752,18 +11762,18 @@ } }, "node_modules/webdriver": { - "version": "8.16.7", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.7.tgz", - "integrity": "sha512-YQDYLIfx5zppkKSDHtcBNwQ0VccThGdrIHKVF1m4mOOsw422MYeoUzoKCRWrzH2Osh25zB34DrDhHVKq4q5APg==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.22.tgz", + "integrity": "sha512-7W3LwQ5Np/qQG/EHD02aujv4QBuiE3/PbDd576s4QRDVa5RHLTvuAg3sZpj5kJ4wZEK2MbPsj1Nb8xqSyCUUqw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.16.7", - "@wdio/logger": "8.11.0", + "@wdio/config": "8.16.22", + "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", - "@wdio/types": "8.16.7", - "@wdio/utils": "8.16.7", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11811,23 +11821,23 @@ } }, "node_modules/webdriverio": { - "version": "8.16.7", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.7.tgz", - "integrity": "sha512-Idom8HYyDoZ02kcc53/XnY/3yZnpub8fxRAwNZDshTvdji7C7fiS/nEYuqxYIVG7bkACrGGkyzHshXhsMriybQ==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.22.tgz", + "integrity": "sha512-fzZtONvimqYc+C7DnnntkOz883+VP50uIvofLkDdH5yXU6duyclclChwWNZWllEHZvkLfpmLgrpgbS7R1wNGQg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.7", - "@wdio/logger": "8.11.0", + "@wdio/config": "8.16.22", + "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", "@wdio/repl": "8.10.1", - "@wdio/types": "8.16.7", - "@wdio/utils": "8.16.7", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools-protocol": "^0.0.1188743", + "devtools-protocol": "^0.0.1203626", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^3.0.0", "is-plain-obj": "^4.1.0", @@ -11839,7 +11849,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.16.7" + "webdriver": "8.16.22" }, "engines": { "node": "^16.13 || >=18" From ed3decbb37510ff4cd64e77720a571b5e12afa32 Mon Sep 17 00:00:00 2001 From: Minh Seikel <99860964+goldenkairos@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:29:40 -0700 Subject: [PATCH 21/86] fix: Corrected typo from 'codefor' to 'code for' (#7549) --- core/generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/generator.ts b/core/generator.ts index c50a24853..e4518681d 100644 --- a/core/generator.ts +++ b/core/generator.ts @@ -248,7 +248,7 @@ export class CodeGenerator { } if (typeof func !== 'function') { throw Error( - `${this.name_} generator does not know how to generate code` + + `${this.name_} generator does not know how to generate code ` + `for block type "${block.type}".`, ); } From ab3bc6c3d89107b217149ef9df41a40768517848 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 9 Oct 2023 10:34:06 -0700 Subject: [PATCH 22/86] fix: colour from colour picker not being updated (#7584) * fix: colour from colour picker not being updated * chore: clarify what code is doing --- core/field_colour.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/core/field_colour.ts b/core/field_colour.ts index de771c9af..6b78a2e50 100644 --- a/core/field_colour.ts +++ b/core/field_colour.ts @@ -246,12 +246,9 @@ export class FieldColour extends Field { const block = this.getSourceBlock() as BlockSvg | null; if (!block) throw new UnattachedFieldError(); - // In general, do *not* let fields control the color of blocks. Having the - // field control the color is unexpected, and could have performance - // impacts. - // Whenever we render, the field may no longer be a full-block-field so - // we need to update the colour. - if (this.getConstants()!.FIELD_COLOUR_FULL_BLOCK) block.applyColour(); + // Calling applyColour updates the UI (full-block vs non-full-block) for the + // colour field, and the colour of the field/block. + block.applyColour(); } /** From 1e3b5b4c76f24d2274ef4947c1fcf657f0058f11 Mon Sep 17 00:00:00 2001 From: potaracom <54124561+potaracom@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:19:44 +0900 Subject: [PATCH 23/86] fix: recreate dropdown div (#7572) * fix: recreate dropdown div * fix: recreate tooltip div * fix: recreate widget div * fix: Stop using global variables and use getDiv() * Revert "fix: Stop using global variables and use getDiv()" This reverts commit 322c4d884bff86e41d8280d81ce9752a50339e54. * fix: reset widget div --- core/dropdowndiv.ts | 2 +- core/tooltip.ts | 2 +- core/widgetdiv.ts | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/dropdowndiv.ts b/core/dropdowndiv.ts index f5d8076fa..c90661c4e 100644 --- a/core/dropdowndiv.ts +++ b/core/dropdowndiv.ts @@ -113,7 +113,7 @@ export interface PositionMetrics { * @internal */ export function createDom() { - if (div) { + if (document.querySelector('.blocklyDropDownDiv')) { return; // Already created. } div = document.createElement('div'); diff --git a/core/tooltip.ts b/core/tooltip.ts index 51c38e653..0478b91fd 100644 --- a/core/tooltip.ts +++ b/core/tooltip.ts @@ -184,7 +184,7 @@ function getTargetObject( * Create the tooltip div and inject it onto the page. */ export function createDom() { - if (containerDiv) { + if (document.querySelector('.blocklyTooltipDiv')) { return; // Already created. } // Create an HTML container for popup overlays (e.g. editor widgets). diff --git a/core/widgetdiv.ts b/core/widgetdiv.ts index b53f7cd28..52816f363 100644 --- a/core/widgetdiv.ts +++ b/core/widgetdiv.ts @@ -19,6 +19,9 @@ let owner: unknown = null; /** Optional cleanup function set by whichever object uses the widget. */ let dispose: (() => void) | null = null; +/** A class name representing the current owner's workspace container. */ +const containerClassName = 'blocklyWidgetDiv'; + /** A class name representing the current owner's workspace renderer. */ let rendererClassName = ''; @@ -45,18 +48,21 @@ export function getDiv(): HTMLDivElement | null { */ export function testOnly_setDiv(newDiv: HTMLDivElement | null) { containerDiv = newDiv; + if (newDiv === null) { + document.querySelector('.' + containerClassName)?.remove(); + } } /** * Create the widget div and inject it onto the page. */ export function createDom() { - if (containerDiv) { + if (document.querySelector('.' + containerClassName)) { return; // Already created. } containerDiv = document.createElement('div') as HTMLDivElement; - containerDiv.className = 'blocklyWidgetDiv'; + containerDiv.className = containerClassName; const container = common.getParentContainer() || document.body; container.appendChild(containerDiv); } From 072c5f768f583a5a4d692f9d5755e551a7e9a08c Mon Sep 17 00:00:00 2001 From: Oscar <71343264+0scvr@users.noreply.github.com> Date: Sat, 14 Oct 2023 02:22:34 +0200 Subject: [PATCH 24/86] fix: bring block to front when icon clicked (#7590) Closes #7588 Signed-off-by: Oscar <71343264+0scvr@users.noreply.github.com> --- core/gesture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/gesture.ts b/core/gesture.ts index 03c81c3cc..4549efcba 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -945,7 +945,7 @@ export class Gesture { 'Cannot do an icon click because the start icon is undefined', ); } - + this.bringBlockToFront(); this.startIcon.onClick(); } From f3ce2f9e0be65a308b471d29485a9ff63149f5a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 08:45:52 -0700 Subject: [PATCH 25/86] chore(deps): Bump chai from 4.3.8 to 4.3.10 (#7594) Bumps [chai](https://github.com/chaijs/chai) from 4.3.8 to 4.3.10. - [Release notes](https://github.com/chaijs/chai/releases) - [Changelog](https://github.com/chaijs/chai/blob/4.x.x/History.md) - [Commits](https://github.com/chaijs/chai/compare/v4.3.8...v4.3.10) --- updated-dependencies: - dependency-name: chai dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54ae901d6..91b153f1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2693,18 +2693,18 @@ } }, "node_modules/chai": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz", - "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -2739,10 +2739,13 @@ } }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } @@ -3429,9 +3432,9 @@ } }, "node_modules/deep-eql": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", - "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "dependencies": { "type-detect": "^4.0.0" @@ -5065,9 +5068,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -7607,12 +7610,12 @@ "dev": true }, "node_modules/loupe": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.3.tgz", - "integrity": "sha512-krIV4Cf1BIGIx2t1e6tucThhrBemUnIUjMtD2vN4mrMxnxpBvrcosBSpooqunBqP/hOEEV1w/Cr1YskGtqw5Jg==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "node_modules/lowercase-keys": { From 85037b810c51accdabac4e7315cc112bb436fdfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 08:47:09 -0700 Subject: [PATCH 26/86] chore(deps): Bump @typescript-eslint/eslint-plugin from 6.7.3 to 6.7.5 (#7595) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.7.3 to 6.7.5. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.5/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 118 +++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91b153f1c..1309be70a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1157,16 +1157,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz", - "integrity": "sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.3", - "@typescript-eslint/type-utils": "6.7.3", - "@typescript-eslint/utils": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1192,13 +1192,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", - "integrity": "sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1209,9 +1209,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", - "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1222,12 +1222,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", - "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1286,13 +1286,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz", - "integrity": "sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.3", - "@typescript-eslint/utils": "6.7.3", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1313,9 +1313,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", - "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1326,13 +1326,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz", - "integrity": "sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1353,12 +1353,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", - "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1412,17 +1412,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.3.tgz", - "integrity": "sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.3", - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/typescript-estree": "6.7.3", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" }, "engines": { @@ -1437,13 +1437,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", - "integrity": "sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1454,9 +1454,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", - "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1467,13 +1467,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz", - "integrity": "sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1494,12 +1494,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", - "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { From ec4e6a2d304c719c438cd420be7ae94bbdbd419e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 09:35:01 -0700 Subject: [PATCH 27/86] chore(deps-dev): Bump undici from 5.22.1 to 5.26.3 (#7597) Bumps [undici](https://github.com/nodejs/undici) from 5.22.1 to 5.26.3. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v5.22.1...v5.26.3) --- updated-dependencies: - dependency-name: undici dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1309be70a..1f2c5ffd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -419,6 +419,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@gulp-sourcemaps/identity-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", @@ -2590,18 +2599,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dev": true, - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -10767,15 +10764,6 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/streamx": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", @@ -11348,12 +11336,12 @@ "dev": true }, "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.26.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.3.tgz", + "integrity": "sha512-H7n2zmKEWgOllKkIUkLvFmsJQj062lSm3uA4EYApG8gLuiOM0/go9bIoC3HVaSnfg4xunowDE2i9p8drkXuvDw==", "dev": true, "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { "node": ">=14.0" From 3a03f4d11b864e0f67e95b135326adba5800f21f Mon Sep 17 00:00:00 2001 From: Oscar <71343264+0scvr@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:19:17 +0200 Subject: [PATCH 28/86] fix: block creation successful with undefined messages (#7591) closes #7589 Signed-off-by: Oscar <71343264+0scvr@users.noreply.github.com> --- core/block.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/block.ts b/core/block.ts index 578015d3a..d57043e55 100644 --- a/core/block.ts +++ b/core/block.ts @@ -1641,6 +1641,18 @@ export class Block implements IASTNodeLocation, IDeletable { ); } + // Validate that each arg has a corresponding message + let n = 0; + while (json['args' + n]) { + if (json['message' + n] === undefined) { + throw Error( + warningPrefix + + `args${n} must have a corresponding message (message${n}).`, + ); + } + n++; + } + // Set basic properties of block. // Makes styles backward compatible with old way of defining hat style. if (json['style'] && json['style'].hat) { From 0e95e45fee87b72a30078735752e95d78db9fdaa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:57:58 -0700 Subject: [PATCH 29/86] chore(deps): Bump webdriverio from 8.16.22 to 8.18.2 (#7596) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.16.22 to 8.18.2. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.18.2/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 82 +++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1f2c5ffd4..cf08a6429 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1147,9 +1147,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", - "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", + "version": "8.5.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz", + "integrity": "sha512-6UrLjiDUvn40CMrAubXuIVtj2PEfKDffJS7ychvnPU44j+KVeXmdHHTgqcM/dxLUTHxlXHiFM8Skmb8ozGdTnQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -1538,14 +1538,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.16.22", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.22.tgz", - "integrity": "sha512-sxqiVUEq++GFDKeR+HfzlgNhEbYuJZlrkU09p2rZzCRpPM3ty4azzdHB+XEdHHJJlV4UguvqUkp7n2126d9SAQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.18.2.tgz", + "integrity": "sha512-O3K36Wk/G/P5t9NfI/jBjLMdJq1KEDQTmbLvrbRckqzX5SQmPFg2pg18gE9N3JQE4A7qR+imxVo45HmhFDyn4w==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.22", - "@wdio/utils": "8.16.22", + "@wdio/types": "8.17.0", + "@wdio/utils": "8.18.2", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1623,9 +1623,9 @@ } }, "node_modules/@wdio/protocols": { - "version": "8.16.5", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.16.5.tgz", - "integrity": "sha512-u9I57hIqmcOgrDH327ZCc2GTXv2YFN5bg6UaA3OUoJU7eJgGYHFB6RrjiNjLXer68iIx07wwVM70V/1xzijd3Q==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.18.0.tgz", + "integrity": "sha512-TABA0mksHvu5tE8qNYYDR0fDyo90NCANeghbGAtsI8TUsJzgH0dwpos3WSSiB97J9HRSZuWIMa7YuABEkBIjWQ==", "dev": true }, "node_modules/@wdio/repl": { @@ -1641,9 +1641,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.16.22", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.22.tgz", - "integrity": "sha512-bg30seCgYu5JXukJ7M0qWKZLNATpKROvnl5/lRSOu4oopjm28UUan/+gHfHfyJ3MJ2uFNhaIVotPAvUziVJAdg==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.17.0.tgz", + "integrity": "sha512-OkIpr5iHcwFXQpr4csXsiQ/WelX+Dhz/A8STFzoDQFYxMlR3nzm/S+Q1P4UoJfyhrNWlsFpLhShGK1cn+XUE5Q==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1653,14 +1653,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.16.22", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.22.tgz", - "integrity": "sha512-1hQjm7Jweiz+ABakS33TyWXYoxEg7LxL12RqbEYqtGB6ZTJhik+Cwyj/jcJbETSjiYJflmHxDvhFwuOkLR8ljg==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.18.2.tgz", + "integrity": "sha512-TQrrKv+knFn4Z/T/e/+wdnBoykNBg6rfo0NsAwaWh4PbJ1tf+Dc9GjzWhvJTgHwZf4v78K8Z+77qkqoLCF1wSg==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.22", + "@wdio/types": "8.17.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -3551,9 +3551,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1203626", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz", - "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==", + "version": "0.0.1206220", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1206220.tgz", + "integrity": "sha512-zTcXveZkrQdpBwZzAd6spwu+WZet0hU+m/hAm7j61PDUQgG42YkMMdbFYqbDrxIiMTEgJInn70ck1Jl10RQ1aQ==", "dev": true }, "node_modules/dir-glob": { @@ -3696,13 +3696,13 @@ } }, "node_modules/edgedriver": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-5.3.7.tgz", - "integrity": "sha512-E1qNFEA9NbaCPSvGaeZhyd7mEZLar+oFS0NRAe5TehJcQ3cayoUdJE5uOFrbxdv/rM4NEPH7aK9a9kgG09rszA==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-5.3.8.tgz", + "integrity": "sha512-FWLPDuwJDeGGgtmlqTXb4lQi/HV9yylLo1F9O1g9TLqSemA5T6xH28seUIfyleVirLFtDQyKNUxKsMhMT4IfnA==", "dev": true, "hasInstallScript": true, "dependencies": { - "@wdio/logger": "^8.11.0", + "@wdio/logger": "^8.16.17", "decamelize": "^6.0.0", "edge-paths": "^3.0.5", "node-fetch": "^3.3.2", @@ -11753,18 +11753,18 @@ } }, "node_modules/webdriver": { - "version": "8.16.22", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.22.tgz", - "integrity": "sha512-7W3LwQ5Np/qQG/EHD02aujv4QBuiE3/PbDd576s4QRDVa5RHLTvuAg3sZpj5kJ4wZEK2MbPsj1Nb8xqSyCUUqw==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.18.2.tgz", + "integrity": "sha512-7xr8K2jlrRdhqK6LLHrg96OiccWT5EeBIQXk9xAifgIbs6l/JfzCjC9WqC0AmX9plXjR8wf2LS+Ob9Ajhx6v+A==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.16.22", + "@wdio/config": "8.18.2", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.16.5", - "@wdio/types": "8.16.22", - "@wdio/utils": "8.16.22", + "@wdio/protocols": "8.18.0", + "@wdio/types": "8.17.0", + "@wdio/utils": "8.18.2", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11812,23 +11812,23 @@ } }, "node_modules/webdriverio": { - "version": "8.16.22", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.22.tgz", - "integrity": "sha512-fzZtONvimqYc+C7DnnntkOz883+VP50uIvofLkDdH5yXU6duyclclChwWNZWllEHZvkLfpmLgrpgbS7R1wNGQg==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.18.2.tgz", + "integrity": "sha512-vX+U4QH9HdyT3upcOzP6YMpnAA1oZJJAZetvf9aWZ9KnBzgkL60LiZ/q9xCX+VWYKEIvNZ66ekppbuZ8FpobIQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.22", + "@wdio/config": "8.18.2", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.16.5", + "@wdio/protocols": "8.18.0", "@wdio/repl": "8.10.1", - "@wdio/types": "8.16.22", - "@wdio/utils": "8.16.22", + "@wdio/types": "8.17.0", + "@wdio/utils": "8.18.2", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools-protocol": "^0.0.1203626", + "devtools-protocol": "^0.0.1206220", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^3.0.0", "is-plain-obj": "^4.1.0", @@ -11840,7 +11840,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.16.22" + "webdriver": "8.18.2" }, "engines": { "node": "^16.13 || >=18" From b2688441fae57a8cd474d3b34d0852acd32e9849 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 18 Oct 2023 09:29:08 -0700 Subject: [PATCH 30/86] chore: fix shouldStartNewRow docs and param names (#7558) --- core/renderers/common/info.ts | 22 +++++++++++----------- core/renderers/zelos/info.ts | 16 ++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core/renderers/common/info.ts b/core/renderers/common/info.ts index 9830e890a..fa44b7743 100644 --- a/core/renderers/common/info.ts +++ b/core/renderers/common/info.ts @@ -345,34 +345,34 @@ export class RenderInfo { /** * Decide whether to start a new row between the two Blockly.Inputs. * - * @param input The first input to consider - * @param lastInput The input that follows. - * @returns True if the next input should be rendered on a new row. + * @param currInput The current input. + * @param prevInput The previous input. + * @returns True if the current input should be rendered on a new row. */ - protected shouldStartNewRow_(input: Input, lastInput?: Input): boolean { + protected shouldStartNewRow_(currInput: Input, prevInput?: Input): boolean { // If this is the first input, just add to the existing row. // That row is either empty or has some icons in it. - if (!lastInput) { + if (!prevInput) { return false; } // If the previous input was an end-row input, then any following input // should always be rendered on the next row. - if (lastInput instanceof EndRowInput) { + if (prevInput instanceof EndRowInput) { return true; } // A statement input or an input following one always gets a new row. if ( - input instanceof StatementInput || - lastInput instanceof StatementInput + currInput instanceof StatementInput || + prevInput instanceof StatementInput ) { return true; } // Value inputs, dummy inputs, and any input following an external value // input get a new row if inputs are not inlined. if ( - input instanceof ValueInput || - input instanceof DummyInput || - lastInput instanceof ValueInput + currInput instanceof ValueInput || + currInput instanceof DummyInput || + prevInput instanceof ValueInput ) { return !this.isInline; } diff --git a/core/renderers/zelos/info.ts b/core/renderers/zelos/info.ts index 8748bcf5f..623f0a3b0 100644 --- a/core/renderers/zelos/info.ts +++ b/core/renderers/zelos/info.ts @@ -118,29 +118,29 @@ export class RenderInfo extends BaseRenderInfo { this.finalize_(); } - override shouldStartNewRow_(input: Input, lastInput: Input): boolean { + override shouldStartNewRow_(currInput: Input, prevInput: Input): boolean { // If this is the first input, just add to the existing row. // That row is either empty or has some icons in it. - if (!lastInput) { + if (!prevInput) { return false; } // If the previous input was an end-row input, then any following input // should always be rendered on the next row. - if (lastInput instanceof EndRowInput) { + if (prevInput instanceof EndRowInput) { return true; } // A statement input or an input following one always gets a new row. if ( - input instanceof StatementInput || - lastInput instanceof StatementInput + currInput instanceof StatementInput || + prevInput instanceof StatementInput ) { return true; } // Value, dummy, and end-row inputs get new row if inputs are not inlined. if ( - input instanceof ValueInput || - input instanceof DummyInput || - input instanceof EndRowInput + currInput instanceof ValueInput || + currInput instanceof DummyInput || + currInput instanceof EndRowInput ) { return !this.isInline || this.isMultiRow; } From 582e19a0f1603b88535023113e64700b53b1651d Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Fri, 20 Oct 2023 16:59:30 +0200 Subject: [PATCH 31/86] fix(generators): Modify type signature of forBlock (#7555) Make two changes to the forBlock dictionary on CodeGenerator objects: - Change the type of the second argument to the special 'this' type (was CodeGenerator), so that e.g. JS block generator functions can call JavascriptGenerator.prototype.getAdjusted (not defined on CodeGenerator). - Change the way forBlock is declared from using an index signature to using the Record<> template type. The two should be equivalent but for some reason the former provokes type errors when used with the 'this' type. Additionally, deprecate the now-unused (but exported) BlockGenerator type alias. Technically the change of signaure is a breaking chnage, but it is unlikely to affect any developers in practice, since any block generator function (Block, CodeGenerator) => ... can be substituted in for (Block, C extends CodeGenerator) => ..., so any existing generator functions can still be added to any CodeGenerator or subclass instance's .forBlock. The only situation in which this would be breaking is if a developer was obtaining block generator functions FROM a subclass instance's .forBlock dictionary and assuming they were (Block CodeGenerator) => ... --- core/generator.ts | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/core/generator.ts b/core/generator.ts index e4518681d..d94597fc1 100644 --- a/core/generator.ts +++ b/core/generator.ts @@ -19,8 +19,10 @@ import type {Workspace} from './workspace.js'; import {warn} from './utils/deprecation.js'; /** - * Type declaration for per-block-type generator functions. + * Deprecated, no-longer used type declaration for per-block-type generator + * functions. * + * @deprecated * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/generating-code} * @param block The Block instance to generate code for. * @param genearator The CodeGenerator calling the function. @@ -39,8 +41,25 @@ export type BlockGenerator = ( export class CodeGenerator { name_: string; - /** A dictionary of block generator functions keyed by block type. */ - forBlock: {[type: string]: BlockGenerator} = Object.create(null); + /** + * A dictionary of block generator functions, keyed by block type. + * Each block generator function takes two parameters: + * + * - the Block to generate code for, and + * - the calling CodeGenerator (or subclass) instance, so the + * function can call methods defined below (e.g. blockToCode) or + * on the relevant subclass (e.g. JavascripGenerator), + * + * and returns: + * + * - a [code, precedence] tuple (for value/expression blocks), or + * - a string containing the generated code (for statement blocks), or + * - null if no code should be emitted for block. + */ + forBlock: Record< + string, + (block: Block, generator: this) => [string, number] | string | null + > = Object.create(null); /** * This is used as a placeholder in functions defined using From c8cc33a01a27f2f4ded74cf8069c230968d879c3 Mon Sep 17 00:00:00 2001 From: Hady Bazzi <122710550+HadyBazzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:18:33 -0400 Subject: [PATCH 32/86] fix: text join block warning when using block-plus-minus plugin (#7598) --- blocks/text.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blocks/text.ts b/blocks/text.ts index eba64d9ab..10a757d21 100644 --- a/blocks/text.ts +++ b/blocks/text.ts @@ -1018,6 +1018,8 @@ Extensions.register('text_indexOf_tooltip', INDEXOF_TOOLTIP_EXTENSION); Extensions.register('text_quotes', QUOTES_EXTENSION); +Extensions.registerMixin('quote_image_mixin', QUOTE_IMAGE_MIXIN); + Extensions.registerMutator( 'text_join_mutator', JOIN_MUTATOR_MIXIN, From e7dec4ae1b71edd6a2688ba904b11bd38fd6fb91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 08:59:20 -0700 Subject: [PATCH 33/86] chore(deps): Bump webdriverio from 8.18.2 to 8.20.0 (#7604) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.18.2 to 8.20.0. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.20.0/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 128 +++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf08a6429..b40e3d93c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1101,9 +1101,9 @@ "dev": true }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", - "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==", "dev": true }, "node_modules/@types/json-schema": { @@ -1119,9 +1119,9 @@ "dev": true }, "node_modules/@types/normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", "dev": true }, "node_modules/@types/semver": { @@ -1147,9 +1147,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz", - "integrity": "sha512-6UrLjiDUvn40CMrAubXuIVtj2PEfKDffJS7ychvnPU44j+KVeXmdHHTgqcM/dxLUTHxlXHiFM8Skmb8ozGdTnQ==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", + "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", "dev": true, "dependencies": { "@types/node": "*" @@ -1538,14 +1538,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.18.2.tgz", - "integrity": "sha512-O3K36Wk/G/P5t9NfI/jBjLMdJq1KEDQTmbLvrbRckqzX5SQmPFg2pg18gE9N3JQE4A7qR+imxVo45HmhFDyn4w==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.20.0.tgz", + "integrity": "sha512-ODsafHlxEawyYa6IyIdXJMV2plPFyrDbGrXLNKNFBQVfB/FmoHUiiOTh+4Gu+sUXzpn2YNH5O199qHxHw61uUw==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", - "@wdio/types": "8.17.0", - "@wdio/utils": "8.18.2", + "@wdio/types": "8.20.0", + "@wdio/utils": "8.20.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1641,9 +1641,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.17.0.tgz", - "integrity": "sha512-OkIpr5iHcwFXQpr4csXsiQ/WelX+Dhz/A8STFzoDQFYxMlR3nzm/S+Q1P4UoJfyhrNWlsFpLhShGK1cn+XUE5Q==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.20.0.tgz", + "integrity": "sha512-y0En5V5PPF48IHJMetaNYQobhCr3ddsgp2aX/crLL51UccWqnFpCL8pCh6cP01gRgCchCasa2JCBMB+PucbYmA==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1653,14 +1653,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.18.2.tgz", - "integrity": "sha512-TQrrKv+knFn4Z/T/e/+wdnBoykNBg6rfo0NsAwaWh4PbJ1tf+Dc9GjzWhvJTgHwZf4v78K8Z+77qkqoLCF1wSg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.20.0.tgz", + "integrity": "sha512-nZ5QF5lPyZNJG9YaSrRuVfkVeg80yRrUQT42D0mUDDjmUIh2pAXDMu4HxgxocuQSOyLacg4Vpg3Sju9NFipxIA==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.17.0", + "@wdio/types": "8.20.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -1678,9 +1678,9 @@ } }, "node_modules/@wdio/utils/node_modules/@puppeteer/browsers": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.7.1.tgz", - "integrity": "sha512-nIb8SOBgDEMFY2iS2MdnUZOg2ikcYchRrBoF+wtdjieRFKR2uGRipHY/oFLo+2N6anDualyClPzGywTHRGrLfw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.8.0.tgz", + "integrity": "sha512-TkRHIV6k2D8OlUe8RtG+5jgOF/H98Myx0M6AOafC8DdNVOFiBSFa5cpRDtpm8LXOa9sVwe0+e6Q3FC56X/DZfg==", "dev": true, "dependencies": { "debug": "4.3.4", @@ -1689,7 +1689,7 @@ "proxy-agent": "6.3.1", "tar-fs": "3.0.4", "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" + "yargs": "17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" @@ -1710,20 +1710,6 @@ "node": ">= 14" } }, - "node_modules/@wdio/utils/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wdio/utils/node_modules/decamelize": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", @@ -1790,24 +1776,6 @@ "node": ">= 14" } }, - "node_modules/@wdio/utils/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -3551,9 +3519,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1206220", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1206220.tgz", - "integrity": "sha512-zTcXveZkrQdpBwZzAd6spwu+WZet0hU+m/hAm7j61PDUQgG42YkMMdbFYqbDrxIiMTEgJInn70ck1Jl10RQ1aQ==", + "version": "0.0.1209236", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1209236.tgz", + "integrity": "sha512-z4eehc+fhmptqhxwreLcg9iydszZGU4Q5FzaaElXVGp3KyfXbjtXeUCmo4l8FxBJbyXtCz4VRIJsGW2ekApyUQ==", "dev": true }, "node_modules/dir-glob": { @@ -9576,9 +9544,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.4.0.tgz", - "integrity": "sha512-HT3RRs7sTfY22KuPQJkD/XjbTbxgP2Je5HPt6H6JEGvcjHd5Lqru75EbrP3tb4FYjNJ+DjLp+MNQTFQU0mhXNw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", + "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", "dev": true, "engines": { "node": ">=16" @@ -9600,9 +9568,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.4.0.tgz", - "integrity": "sha512-HT3RRs7sTfY22KuPQJkD/XjbTbxgP2Je5HPt6H6JEGvcjHd5Lqru75EbrP3tb4FYjNJ+DjLp+MNQTFQU0mhXNw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", + "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", "dev": true, "engines": { "node": ">=16" @@ -11753,18 +11721,18 @@ } }, "node_modules/webdriver": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.18.2.tgz", - "integrity": "sha512-7xr8K2jlrRdhqK6LLHrg96OiccWT5EeBIQXk9xAifgIbs6l/JfzCjC9WqC0AmX9plXjR8wf2LS+Ob9Ajhx6v+A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.20.0.tgz", + "integrity": "sha512-U/sej7yljVf/enEWR9L2AtOntrd3lqtkEtHeuSWU2FPp5cWvoMEe7vQiG0WJA74VE2e7uwd8S1LfCgQD1wY3Bg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.18.2", + "@wdio/config": "8.20.0", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.18.0", - "@wdio/types": "8.17.0", - "@wdio/utils": "8.18.2", + "@wdio/types": "8.20.0", + "@wdio/utils": "8.20.0", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11812,23 +11780,23 @@ } }, "node_modules/webdriverio": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.18.2.tgz", - "integrity": "sha512-vX+U4QH9HdyT3upcOzP6YMpnAA1oZJJAZetvf9aWZ9KnBzgkL60LiZ/q9xCX+VWYKEIvNZ66ekppbuZ8FpobIQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.20.0.tgz", + "integrity": "sha512-nVd3n4v1CYzjEezK6OgmGIcVx+T/7PNYwLK3fTNH2hGRNX05TyGGcR9HAcVZCbIu8WWFKRE0SrLvCjEutPO8gg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.18.2", + "@wdio/config": "8.20.0", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.18.0", "@wdio/repl": "8.10.1", - "@wdio/types": "8.17.0", - "@wdio/utils": "8.18.2", + "@wdio/types": "8.20.0", + "@wdio/utils": "8.20.0", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools-protocol": "^0.0.1206220", + "devtools-protocol": "^0.0.1209236", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^3.0.0", "is-plain-obj": "^4.1.0", @@ -11840,7 +11808,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.18.2" + "webdriver": "8.20.0" }, "engines": { "node": "^16.13 || >=18" From 7d2c307fedbcb2cbb5f40382e69b912109c86666 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 26 Oct 2023 09:47:39 -0700 Subject: [PATCH 34/86] fix: widget positioning (#7507) * chore: delete dead code * chore: moves location updating into the block * chore: change dragging to use update component locations * fix: field widgets not being moved when blocks are editted * chore: remove unnecessary resizeEditor_ calls * chore: format * chore: fix build * fix: tests * chore: PR comments * chore: format --- core/block_dragger.ts | 27 +++---- core/block_svg.ts | 104 +++++++++++--------------- core/field.ts | 8 ++ core/field_input.ts | 21 +++--- core/render_management.ts | 72 +++++------------- core/rendered_connection.ts | 22 ------ tests/mocha/render_management_test.js | 2 +- 7 files changed, 94 insertions(+), 162 deletions(-) diff --git a/core/block_dragger.ts b/core/block_dragger.ts index 2d72d55de..cd9a1e48d 100644 --- a/core/block_dragger.ts +++ b/core/block_dragger.ts @@ -29,6 +29,7 @@ import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import type {WorkspaceSvg} from './workspace_svg.js'; import {hasBubble} from './interfaces/i_has_bubble.js'; +import * as deprecation from './utils/deprecation.js'; /** * Class for a block dragger. It moves blocks around the workspace when they @@ -48,7 +49,12 @@ export class BlockDragger implements IBlockDragger { /** Whether the block would be deleted if dropped immediately. */ protected wouldDeleteBlock_ = false; protected startXY_: Coordinate; - protected dragIconData_: IconPositionData[]; + + /** + * @deprecated To be removed in v11. Updating icons is now handled by the + * block's `moveDuringDrag` method. + */ + protected dragIconData_: IconPositionData[] = []; /** * @param block The block to drag. @@ -70,11 +76,6 @@ export class BlockDragger implements IBlockDragger { */ this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY(); - /** - * A list of all of the icons (comment, warning, and mutator) that are - * on this block and its descendants. Moving an icon moves the bubble that - * extends from it if that bubble is open. - */ this.dragIconData_ = initIconData(block, this.startXY_); } @@ -85,7 +86,6 @@ export class BlockDragger implements IBlockDragger { */ dispose() { this.dragIconData_.length = 0; - if (this.draggedConnectionManager_) { this.draggedConnectionManager_.dispose(); } @@ -178,7 +178,6 @@ export class BlockDragger implements IBlockDragger { const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); const newLoc = Coordinate.sum(this.startXY_, delta); this.draggingBlock_.moveDuringDrag(newLoc); - this.dragIcons_(delta); const oldDragTarget = this.dragTarget_; this.dragTarget_ = this.workspace_.getDragTarget(e); @@ -210,7 +209,6 @@ export class BlockDragger implements IBlockDragger { endDrag(e: PointerEvent, currentDragDeltaXY: Coordinate) { // Make sure internal state is fresh. this.drag(e, currentDragDeltaXY); - this.dragIconData_ = []; this.fireDragEndEvent_(); dom.stopTextWidthCache(); @@ -398,14 +396,11 @@ export class BlockDragger implements IBlockDragger { /** * Move all of the icons connected to this drag. * - * @param dxy How far to move the icons from their original positions, in - * workspace units. + * @deprecated To be removed in v11. This is now handled by the block's + * `moveDuringDrag` method. */ - protected dragIcons_(dxy: Coordinate) { - // Moving icons moves their associated bubbles. - for (const data of this.dragIconData_) { - data.icon.onLocationChange(Coordinate.sum(data.location, dxy)); - } + protected dragIcons_() { + deprecation.warn('Blockly.BlockDragger.prototype.dragIcons_', 'v10', 'v11'); } /** diff --git a/core/block_svg.ts b/core/block_svg.ts index b419122ba..e175db567 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -154,6 +154,9 @@ export class BlockSvg */ private bumpNeighboursPid = 0; + /** Whether this block is currently being dragged. */ + private dragging = false; + /** * The location of the top left of this block (in workspace coordinates) * relative to either its parent block, or the workspace origin if it has no @@ -384,9 +387,13 @@ export class BlockSvg event = new (eventUtils.get(eventUtils.BLOCK_MOVE)!)(this) as BlockMove; reason && event.setReason(reason); } - const xy = this.getRelativeToSurfaceXY(); - this.translate(xy.x + dx, xy.y + dy); - this.moveConnections(dx, dy); + + const delta = new Coordinate(dx, dy); + const currLoc = this.getRelativeToSurfaceXY(); + const newLoc = Coordinate.sum(currLoc, delta); + this.translate(newLoc.x, newLoc.y); + this.updateComponentLocations(newLoc); + if (eventsEnabled && event) { event!.recordNew(); eventUtils.fire(event); @@ -437,6 +444,7 @@ export class BlockSvg moveDuringDrag(newLoc: Coordinate) { this.translate(newLoc.x, newLoc.y); this.getSvgRoot().setAttribute('transform', this.getTranslation()); + this.updateComponentLocations(newLoc); } /** Snap this block to the nearest grid point. */ @@ -649,32 +657,47 @@ export class BlockSvg } /** - * Move the connections for this block and all blocks attached under it. - * Also update any attached bubbles. + * Updates the locations of any parts of the block that need to know where + * they are (e.g. connections, icons). * - * @param dx Horizontal offset from current location, in workspace units. - * @param dy Vertical offset from current location, in workspace units. + * @param blockOrigin The top-left of this block in workspace coordinates. * @internal */ - moveConnections(dx: number, dy: number) { + updateComponentLocations(blockOrigin: Coordinate) { if (!this.rendered) { // Rendering is required to lay out the blocks. // This is probably an invisible block attached to a collapsed block. return; } - const myConnections = this.getConnections_(false); - for (let i = 0; i < myConnections.length; i++) { - myConnections[i].moveBy(dx, dy); - } - const icons = this.getIcons(); - const pos = this.getRelativeToSurfaceXY(); - for (const icon of icons) { - icon.onLocationChange(pos); - } - // Recurse through all blocks attached under this one. - for (let i = 0; i < this.childBlocks_.length; i++) { - (this.childBlocks_[i] as BlockSvg).moveConnections(dx, dy); + if (!this.dragging) this.updateConnectionLocations(blockOrigin); + this.updateIconLocations(blockOrigin); + this.updateFieldLocations(blockOrigin); + + for (const child of this.getChildren(false)) { + child.updateComponentLocations( + Coordinate.sum(blockOrigin, child.relativeCoords), + ); + } + } + + private updateConnectionLocations(blockOrigin: Coordinate) { + for (const conn of this.getConnections_(false)) { + conn.moveToOffset(blockOrigin); + } + } + + private updateIconLocations(blockOrigin: Coordinate) { + for (const icon of this.getIcons()) { + icon.onLocationChange(blockOrigin); + } + } + + private updateFieldLocations(blockOrigin: Coordinate) { + for (const input of this.inputList) { + for (const field of input.fieldRow) { + field.onLocationChange(blockOrigin); + } } } @@ -686,6 +709,7 @@ export class BlockSvg * @internal */ setDragging(adding: boolean) { + this.dragging = adding; if (adding) { this.translation = ''; common.draggingConnections.push(...this.getConnections_(true)); @@ -1628,46 +1652,6 @@ export class BlockSvg } } - /** - * Update all of the connections on this block with the new locations - * calculated during rendering. Also move all of the connected blocks based - * on the new connection locations. - * - * @internal - */ - private updateConnectionAndIconLocations() { - const blockTL = this.getRelativeToSurfaceXY(); - // Don't tighten previous or output connections because they are inferior - // connections. - if (this.previousConnection) { - this.previousConnection.moveToOffset(blockTL); - } - if (this.outputConnection) { - this.outputConnection.moveToOffset(blockTL); - } - - for (let i = 0; i < this.inputList.length; i++) { - const conn = this.inputList[i].connection as RenderedConnection; - if (conn) { - conn.moveToOffset(blockTL); - if (conn.isConnected()) { - conn.tighten(); - } - } - } - - if (this.nextConnection) { - this.nextConnection.moveToOffset(blockTL); - if (this.nextConnection.isConnected()) { - this.nextConnection.tighten(); - } - } - - for (const icon of this.getIcons()) { - icon.onLocationChange(blockTL); - } - } - /** * Add the cursor SVG to this block's SVG group. * diff --git a/core/field.ts b/core/field.ts index 529c5aaef..cfae1429b 100644 --- a/core/field.ts +++ b/core/field.ts @@ -960,6 +960,14 @@ export abstract class Field return new Rect(xy.y, xy.y + scaledHeight, xy.x, xy.x + scaledWidth); } + /** + * Notifies the field that it has changed locations. + * + * @param _ The location of this field's block's top-start corner + * in workspace coordinates. + */ + onLocationChange(_: Coordinate) {} + /** * Get the text from this field to display on the block. May differ from * `getText` due to ellipsis, and other formatting. diff --git a/core/field_input.ts b/core/field_input.ts index 22c6765b4..2cd4015b0 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -33,7 +33,6 @@ import {Coordinate} from './utils/coordinate.js'; import * as userAgent from './utils/useragent.js'; import * as WidgetDiv from './widgetdiv.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -import * as renderManagement from './render_management.js'; import {Size} from './utils/size.js'; /** @@ -251,6 +250,14 @@ export abstract class FieldInput extends Field< return super.getSize(); } + /** + * Notifies the field that it has changed locations. Moves the widget div to + * be in the correct place if it is open. + */ + onLocationChange(): void { + if (this.isBeingEdited_) this.resizeEditor_(); + } + /** * Updates the colour of the htmlInput given the current validity of the * field's value. @@ -263,7 +270,6 @@ export abstract class FieldInput extends Field< // This logic is done in render_ rather than doValueInvalid_ or // doValueUpdate_ so that the code is more centralized. if (this.isBeingEdited_) { - this.resizeEditor_(); const htmlInput = this.htmlInput_ as HTMLElement; if (!this.isTextValid_) { dom.addClass(htmlInput, 'blocklyInvalidInput'); @@ -576,11 +582,6 @@ export abstract class FieldInput extends Field< ), ); } - - // Resize the widget div after the block has finished rendering. - renderManagement.finishQueuedRenders().then(() => { - this.resizeEditor_(); - }); } /** @@ -631,7 +632,7 @@ export abstract class FieldInput extends Field< /** * Handles repositioning the WidgetDiv used for input fields when the * workspace is resized. Will bump the block into the viewport and update the - * position of the field if necessary. + * position of the text input if necessary. * * @returns True for rendered workspaces, as we never want to hide the widget * div. @@ -642,13 +643,13 @@ export abstract class FieldInput extends Field< // rendered blocks. if (!(block instanceof BlockSvg)) return false; - bumpObjects.bumpIntoBounds( + const bumped = bumpObjects.bumpIntoBounds( this.workspace_!, this.workspace_!.getMetricsManager().getViewMetrics(true), block, ); - this.resizeEditor_(); + if (!bumped) this.resizeEditor_(); return true; } diff --git a/core/render_management.ts b/core/render_management.ts index 8c088eacf..541459860 100644 --- a/core/render_management.ts +++ b/core/render_management.ts @@ -5,7 +5,6 @@ */ import {BlockSvg} from './block_svg.js'; -import {Coordinate} from './utils/coordinate.js'; import * as userAgent from './utils/useragent.js'; /** The set of all blocks in need of rendering which don't have parents. */ @@ -114,28 +113,36 @@ function queueBlock(block: BlockSvg) { */ function doRenders() { const workspaces = new Set([...rootBlocks].map((block) => block.workspace)); - for (const block of rootBlocks) { - // No need to render a dead block. - if (block.isDisposed()) continue; - // A render for this block may have been queued, and then the block was - // connected to a parent, so it is no longer a root block. - // Rendering will be triggered through the real root block. - if (block.getParent()) continue; - + const blocks = [...rootBlocks].filter(shouldRenderRootBlock); + for (const block of blocks) { renderBlock(block); - const blockOrigin = block.getRelativeToSurfaceXY(); - updateConnectionLocations(block, blockOrigin); - updateIconLocations(block, blockOrigin); } for (const workspace of workspaces) { workspace.resizeContents(); } + for (const block of blocks) { + const blockOrigin = block.getRelativeToSurfaceXY(); + block.updateComponentLocations(blockOrigin); + } rootBlocks.clear(); dirtyBlocks = new Set(); afterRendersPromise = null; } +/** + * Returns true if the block should be rendered. + * + * No need to render dead blocks. + * + * No need to render blocks with parents. A render for the block may have been + * queued, and the the block was connected to a parent, so it is no longer a + * root block. Rendering will be triggered through the real root block. + */ +function shouldRenderRootBlock(block: BlockSvg): boolean { + return !block.isDisposed() && !block.getParent(); +} + /** * Recursively renders all of the dirty children of the given block, and * then renders the block. @@ -149,44 +156,3 @@ function renderBlock(block: BlockSvg) { } block.renderEfficiently(); } - -/** - * Updates the connection database with the new locations of all of the - * connections that are children of the given block. - * - * @param block The block to update the connection locations of. - * @param blockOrigin The top left of the given block in workspace coordinates. - */ -function updateConnectionLocations(block: BlockSvg, blockOrigin: Coordinate) { - for (const conn of block.getConnections_(false)) { - const moved = conn.moveToOffset(blockOrigin); - const target = conn.targetBlock(); - if (!conn.isSuperior()) continue; - if (!target) continue; - if (moved || dirtyBlocks.has(target)) { - updateConnectionLocations( - target, - Coordinate.sum(blockOrigin, target.relativeCoords), - ); - } - } -} - -/** - * Updates all icons that are children of the given block with their new - * locations. - * - * @param block The block to update the icon locations of. - */ -function updateIconLocations(block: BlockSvg, blockOrigin: Coordinate) { - if (!block.getIcons) return; - for (const icon of block.getIcons()) { - icon.onLocationChange(blockOrigin); - } - for (const child of block.getChildren(false)) { - updateIconLocations( - child, - Coordinate.sum(blockOrigin, child.relativeCoords), - ); - } -} diff --git a/core/rendered_connection.ts b/core/rendered_connection.ts index 3a1c32385..08c0471a2 100644 --- a/core/rendered_connection.ts +++ b/core/rendered_connection.ts @@ -24,7 +24,6 @@ import * as internalConstants from './internal_constants.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import {Svg} from './utils/svg.js'; -import * as svgMath from './utils/svg_math.js'; import * as svgPaths from './utils/svg_paths.js'; /** A shape that has a pathDown property. */ @@ -270,27 +269,6 @@ export class RenderedConnection extends Connection { return this.offsetInBlock; } - /** - * Move the blocks on either side of this connection right next to each other. - * - * @internal - */ - tighten() { - const dx = this.targetConnection!.x - this.x; - const dy = this.targetConnection!.y - this.y; - if (dx !== 0 || dy !== 0) { - const block = this.targetBlock(); - const svgRoot = block!.getSvgRoot(); - if (!svgRoot) { - throw Error('block is not rendered.'); - } - // Workspace coordinates. - const xy = svgMath.getRelativeXY(svgRoot); - block!.translate(xy.x - dx, xy.y - dy); - block!.moveConnections(-dx, -dy); - } - } - /** * Moves the blocks on either side of this connection right next to * each other, based on their local offsets, not global positions. diff --git a/tests/mocha/render_management_test.js b/tests/mocha/render_management_test.js index 240a9dd15..d5d957df4 100644 --- a/tests/mocha/render_management_test.js +++ b/tests/mocha/render_management_test.js @@ -30,8 +30,8 @@ suite('Render Management', function () { getParent: () => null, getChildren: () => [], isDisposed: () => false, - getConnections_: () => [], getRelativeToSurfaceXY: () => ({x: 0, y: 0}), + updateComponentLocations: () => {}, workspace: { resizeContents: () => {}, }, From 4ab8d000995a93eafbc29444abb76e535aedf134 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Mon, 30 Oct 2023 09:16:13 +0100 Subject: [PATCH 35/86] refactor(generators): Migrate JavaScript generators to TypeScript (#7602) * refactor(generators): Migrate javascript_generator.js to TypeScript * refactor(generators): Simplify getAdjusted Slightly simplify the implementation of getAdjusted, in part to make it more readable. Also improve its JSDoc comment. * refactor(generators): Migrate generators/javascript/* to TypeScript First pass doing very mechanistic migration, not attempting to fix all the resulting type errors. * fix(generators): Fix type errors in generator functions This consists almost entirely of adding casts, so the code output by tsc should be as similar as possible to the pre-migration .js source files. * refactor(generators): Migrate generators/javascript.js to TypeScript The way the generator functions are added to javascriptGenerator.forBlock has been modified so that incorrect generator function signatures will cause tsc to generate a type error. * chore(generator): Format One block protected with // prettier-ignore to preserve careful comment formatting. Where there are repeated concatenations prettier has made a pretty mess of things, but the correct fix is probably to use template literals instead (rather than just locally disabling prettier). This has been added to the to-do list in #7600. * fix(generators): Fixes for PR #7602 * fix(generators): Fix syntax error --- .prettierignore | 5 +- blocks/lists.ts | 8 +- blocks/loops.ts | 8 +- blocks/procedures.ts | 8 +- blocks/text.ts | 8 +- generators/{javascript.js => javascript.ts} | 19 +- .../javascript/{colour.js => colour.ts} | 67 ++-- ...t_generator.js => javascript_generator.ts} | 269 ++++++++------- generators/javascript/{lists.js => lists.ts} | 302 ++++++++++------- generators/javascript/logic.js | 130 -------- generators/javascript/logic.ts | 153 +++++++++ generators/javascript/{loops.js => loops.ts} | 191 +++++++---- generators/javascript/{math.js => math.ts} | 270 +++++++++------ .../{procedures.js => procedures.ts} | 90 +++-- generators/javascript/{text.js => text.ts} | 314 ++++++++++-------- .../javascript/{variables.js => variables.ts} | 18 +- ...iables_dynamic.js => variables_dynamic.ts} | 1 - 17 files changed, 1095 insertions(+), 766 deletions(-) rename generators/{javascript.js => javascript.ts} (79%) rename generators/javascript/{colour.js => colour.ts} (69%) rename generators/javascript/{javascript_generator.js => javascript_generator.ts} (54%) rename generators/javascript/{lists.js => lists.ts} (60%) delete mode 100644 generators/javascript/logic.js create mode 100644 generators/javascript/logic.ts rename generators/javascript/{loops.js => loops.ts} (53%) rename generators/javascript/{math.js => math.ts} (62%) rename generators/javascript/{procedures.js => procedures.ts} (58%) rename generators/javascript/{text.js => text.ts} (52%) rename generators/javascript/{variables.js => variables.ts} (57%) rename generators/javascript/{variables_dynamic.js => variables_dynamic.ts} (99%) diff --git a/.prettierignore b/.prettierignore index 64dd749f1..9d52f19fe 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,7 +18,6 @@ # Demos, scripts, misc /node_modules/* -/generators/* /demos/* /appengine/* /externs/* @@ -27,5 +26,5 @@ CHANGELOG.md PULL_REQUEST_TEMPLATE.md -# Don't bother formatting js blocks since we're getting rid of them -/blocks/*.js +# Don't bother formatting JavaScript files we're about to migrate: +/generators/**/*.js diff --git a/blocks/lists.ts b/blocks/lists.ts index a85e39352..d115a321c 100644 --- a/blocks/lists.ts +++ b/blocks/lists.ts @@ -111,8 +111,12 @@ export const blocks = createBlockDefinitionsFromJsonArray([ }, ]); -/** Type of a 'lists_create_with' block. */ -type CreateWithBlock = Block & ListCreateWithMixin; +/** + * Type of a 'lists_create_with' block. + * + * @internal + */ +export type CreateWithBlock = Block & ListCreateWithMixin; interface ListCreateWithMixin extends ListCreateWithMixinType { itemCount_: number; } diff --git a/blocks/loops.ts b/blocks/loops.ts index e70fdae31..02d9d34be 100644 --- a/blocks/loops.ts +++ b/blocks/loops.ts @@ -325,8 +325,12 @@ export const loopTypes: Set = new Set([ 'controls_whileUntil', ]); -/** Type of a block that has CONTROL_FLOW_IN_LOOP_CHECK_MIXIN */ -type ControlFlowInLoopBlock = Block & ControlFlowInLoopMixin; +/** + * Type of a block that has CONTROL_FLOW_IN_LOOP_CHECK_MIXIN + * + * @internal + */ +export type ControlFlowInLoopBlock = Block & ControlFlowInLoopMixin; interface ControlFlowInLoopMixin extends ControlFlowInLoopMixinType {} type ControlFlowInLoopMixinType = typeof CONTROL_FLOW_IN_LOOP_CHECK_MIXIN; diff --git a/blocks/procedures.ts b/blocks/procedures.ts index 46109fa27..7150bda8a 100644 --- a/blocks/procedures.ts +++ b/blocks/procedures.ts @@ -1209,8 +1209,12 @@ blocks['procedures_callreturn'] = { defType_: 'procedures_defreturn', }; -/** Type of a procedures_ifreturn block. */ -type IfReturnBlock = Block & IfReturnMixin; +/** + * Type of a procedures_ifreturn block. + * + * @internal + */ +export type IfReturnBlock = Block & IfReturnMixin; interface IfReturnMixin extends IfReturnMixinType { hasReturnValue_: boolean; } diff --git a/blocks/text.ts b/blocks/text.ts index 10a757d21..824da782b 100644 --- a/blocks/text.ts +++ b/blocks/text.ts @@ -725,8 +725,12 @@ const QUOTES_EXTENSION = function (this: QuoteImageBlock) { this.quoteField_('TEXT'); }; -/** Type of a block that has TEXT_JOIN_MUTATOR_MIXIN */ -type JoinMutatorBlock = BlockSvg & JoinMutatorMixin & QuoteImageMixin; +/** + * Type of a block that has TEXT_JOIN_MUTATOR_MIXIN + * + * @internal + */ +export type JoinMutatorBlock = BlockSvg & JoinMutatorMixin & QuoteImageMixin; interface JoinMutatorMixin extends JoinMutatorMixinType {} type JoinMutatorMixinType = typeof JOIN_MUTATOR_MIXIN; diff --git a/generators/javascript.js b/generators/javascript.ts similarity index 79% rename from generators/javascript.js rename to generators/javascript.ts index 7ff772c5b..079c2f793 100644 --- a/generators/javascript.js +++ b/generators/javascript.ts @@ -32,8 +32,17 @@ export * from './javascript/javascript_generator.js'; export const javascriptGenerator = new JavascriptGenerator(); // Install per-block-type generator functions: -Object.assign( - javascriptGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +const generators: typeof javascriptGenerator.forBlock = { + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, +}; +for (const name in generators) { + javascriptGenerator.forBlock[name] = generators[name]; +} diff --git a/generators/javascript/colour.js b/generators/javascript/colour.ts similarity index 69% rename from generators/javascript/colour.js rename to generators/javascript/colour.ts index 41d588c75..3e7089cd7 100644 --- a/generators/javascript/colour.js +++ b/generators/javascript/colour.ts @@ -10,35 +10,48 @@ // Former goog.module ID: Blockly.JavaScript.colour +import type {Block} from '../../core/block.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {Order} from './javascript_generator.js'; - -export function colour_picker(block, generator) { +export function colour_picker( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block, generator) { +export function colour_random( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Generate a random colour. - const functionName = generator.provideFunction_('colourRandom', ` + const functionName = generator.provideFunction_( + 'colourRandom', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { var num = Math.floor(Math.random() * Math.pow(2, 24)); return '#' + ('00000' + num.toString(16)).substr(-6); } -`); +`, + ); const code = functionName + '()'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_rgb(block, generator) { +export function colour_rgb( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; - const green = - generator.valueToCode(block, 'GREEN', Order.NONE) || 0; - const blue = - generator.valueToCode(block, 'BLUE', Order.NONE) || 0; - const functionName = generator.provideFunction_('colourRgb', ` + const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; + const blue = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; + const functionName = generator.provideFunction_( + 'colourRgb', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { r = Math.max(Math.min(Number(r), 100), 0) * 2.55; g = Math.max(Math.min(Number(g), 100), 0) * 2.55; @@ -48,20 +61,23 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { b = ('0' + (Math.round(b) || 0).toString(16)).slice(-2); return '#' + r + g + b; } -`); +`, + ); const code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_blend(block, generator) { +export function colour_blend( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Blend two colours together. - const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || - "'#000000'"; - const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || - "'#000000'"; - const ratio = - generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - const functionName = generator.provideFunction_('colourBlend', ` + const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; + const functionName = generator.provideFunction_( + 'colourBlend', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(c1, c2, ratio) { ratio = Math.max(Math.min(Number(ratio), 1), 0); var r1 = parseInt(c1.substring(1, 3), 16); @@ -78,7 +94,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(c1, c2, ratio) { b = ('0' + (b || 0).toString(16)).slice(-2); return '#' + r + g + b; } -`); +`, + ); const code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/javascript/javascript_generator.js b/generators/javascript/javascript_generator.ts similarity index 54% rename from generators/javascript/javascript_generator.js rename to generators/javascript/javascript_generator.ts index f85fce18f..547b7daf7 100644 --- a/generators/javascript/javascript_generator.js +++ b/generators/javascript/javascript_generator.ts @@ -5,63 +5,62 @@ */ /** - * @fileoverview Helper functions for generating JavaScript for blocks. - * @suppress {checkTypes|globalThis} + * @file JavaScript code generator class, including helper methods for + * generating JavaScript for blocks. */ // Former goog.module ID: Blockly.JavaScript import * as Variables from '../../core/variables.js'; import * as stringUtils from '../../core/utils/string.js'; -// import type {Block} from '../../core/block.js'; +import type {Block} from '../../core/block.js'; import {CodeGenerator} from '../../core/generator.js'; import {Names, NameType} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; +import type {Workspace} from '../../core/workspace.js'; import {inputTypes} from '../../core/inputs/input_types.js'; - /** * Order of operation ENUMs. * https://developer.mozilla.org/en/JavaScript/Reference/Operators/Operator_Precedence - * @enum {number} */ -export const Order = { - ATOMIC: 0, // 0 "" ... - NEW: 1.1, // new - MEMBER: 1.2, // . [] - FUNCTION_CALL: 2, // () - INCREMENT: 3, // ++ - DECREMENT: 3, // -- - BITWISE_NOT: 4.1, // ~ - UNARY_PLUS: 4.2, // + - UNARY_NEGATION: 4.3, // - - LOGICAL_NOT: 4.4, // ! - TYPEOF: 4.5, // typeof - VOID: 4.6, // void - DELETE: 4.7, // delete - AWAIT: 4.8, // await - EXPONENTIATION: 5.0, // ** - MULTIPLICATION: 5.1, // * - DIVISION: 5.2, // / - MODULUS: 5.3, // % - SUBTRACTION: 6.1, // - - ADDITION: 6.2, // + - BITWISE_SHIFT: 7, // << >> >>> - RELATIONAL: 8, // < <= > >= - IN: 8, // in - INSTANCEOF: 8, // instanceof - EQUALITY: 9, // == != === !== - BITWISE_AND: 10, // & - BITWISE_XOR: 11, // ^ - BITWISE_OR: 12, // | - LOGICAL_AND: 13, // && - LOGICAL_OR: 14, // || - CONDITIONAL: 15, // ?: - ASSIGNMENT: 16, //: += -= **= *= /= %= <<= >>= ... - YIELD: 17, // yield - COMMA: 18, // , - NONE: 99, // (...) -}; +// prettier-ignore +export enum Order { + ATOMIC = 0, // 0 "" ... + NEW = 1.1, // new + MEMBER = 1.2, // . [] + FUNCTION_CALL = 2, // () + INCREMENT = 3, // ++ + DECREMENT = 3, // -- + BITWISE_NOT = 4.1, // ~ + UNARY_PLUS = 4.2, // + + UNARY_NEGATION = 4.3, // - + LOGICAL_NOT = 4.4, // ! + TYPEOF = 4.5, // typeof + VOID = 4.6, // void + DELETE = 4.7, // delete + AWAIT = 4.8, // await + EXPONENTIATION = 5.0, // ** + MULTIPLICATION = 5.1, // * + DIVISION = 5.2, // / + MODULUS = 5.3, // % + SUBTRACTION = 6.1, // - + ADDITION = 6.2, // + + BITWISE_SHIFT = 7, // << >> >>> + RELATIONAL = 8, // < <= > >= + IN = 8, // in + INSTANCEOF = 8, // instanceof + EQUALITY = 9, // == != === !== + BITWISE_AND = 10, // & + BITWISE_XOR = 11, // ^ + BITWISE_OR = 12, // | + LOGICAL_AND = 13, // && + LOGICAL_OR = 14, // || + CONDITIONAL = 15, // ?: + ASSIGNMENT = 16, // = += -= **= *= /= %= <<= >>= ... + YIELD = 17, // yield + COMMA = 18, // , + NONE = 99, // (...) +} /** * JavaScript code generator class. @@ -69,9 +68,8 @@ export const Order = { export class JavascriptGenerator extends CodeGenerator { /** * List of outer-inner pairings that do NOT require parentheses. - * @type {!Array>} */ - ORDER_OVERRIDES = [ + ORDER_OVERRIDES: number[][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], @@ -95,11 +93,12 @@ export class JavascriptGenerator extends CodeGenerator { // a && (b && c) -> a && b && c [Order.LOGICAL_AND, Order.LOGICAL_AND], // a || (b || c) -> a || b || c - [Order.LOGICAL_OR, Order.LOGICAL_OR] + [Order.LOGICAL_OR, Order.LOGICAL_OR], ]; - constructor(name) { - super(name ?? 'JavaScript'); + /** @param name Name of the language the generator is for. */ + constructor(name = 'JavaScript') { + super(name); this.isInitialized = false; // Copy Order values onto instance for backwards compatibility @@ -110,16 +109,26 @@ export class JavascriptGenerator extends CodeGenerator { // replace data properties with get accessors that call // deprecate.warn().) for (const key in Order) { - this['ORDER_' + key] = Order[key]; + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; } // List of illegal variable names. This is not intended to be a // security feature. Blockly is 100% client-side, so bypassing // this list is trivial. This is intended to prevent users from // accidentally clobbering a built-in object or function. + // + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords this.addReservedWords( - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords - 'break,case,catch,class,const,continue,debugger,default,delete,do,' + + 'break,case,catch,class,const,continue,debugger,default,delete,do,' + 'else,export,extends,finally,for,function,if,import,in,instanceof,' + 'new,return,super,switch,this,throw,try,typeof,var,void,' + 'while,with,yield,' + @@ -131,15 +140,16 @@ export class JavascriptGenerator extends CodeGenerator { 'arguments,' + // Everything in the current environment (835 items in Chrome, // 104 in Node). - Object.getOwnPropertyNames(globalThis).join(',') + Object.getOwnPropertyNames(globalThis).join(','), ); } /** * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. + * + * @param workspace Workspace to generate code from. */ - init(workspace) { + init(workspace: Workspace) { super.init(workspace); if (!this.nameDB_) { @@ -157,14 +167,16 @@ export class JavascriptGenerator extends CodeGenerator { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { defvars.push( - this.nameDB_.getName(devVarList[i], NameType.DEVELOPER_VARIABLE)); + this.nameDB_.getName(devVarList[i], NameType.DEVELOPER_VARIABLE), + ); } // Add user variables, but only ones that are being used. const variables = Variables.allUsedVarModels(workspace); for (let i = 0; i < variables.length; i++) { defvars.push( - this.nameDB_.getName(variables[i].getId(), NameType.VARIABLE)); + this.nameDB_.getName(variables[i].getId(), NameType.VARIABLE), + ); } // Declare all of the variables. @@ -176,70 +188,74 @@ export class JavascriptGenerator extends CodeGenerator { /** * Prepend the generated code with the variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. + * + * @param code Generated code. + * @returns Completed code. */ - finish(code) { + finish(code: string): string { // Convert the definitions dictionary into a list. const definitions = Object.values(this.definitions_); // Call Blockly.CodeGenerator's finish. super.finish(code); this.isInitialized = false; - this.nameDB_.reset(); + this.nameDB_!.reset(); return definitions.join('\n\n') + '\n\n\n' + code; } /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. A trailing semicolon is needed to make this legal. - * @param {string} line Line of generated code. - * @return {string} Legal line of code. + * + * @param line Line of generated code. + * @returns Legal line of code. */ - scrubNakedValue(line) { + scrubNakedValue(line: string): string { return line + ';\n'; } /** * Encode a string as a properly escaped JavaScript string, complete with * quotes. - * @param {string} string Text to encode. - * @return {string} JavaScript string. + * + * @param string Text to encode. + * @returns JavaScript string. */ - quote_(string) { + quote_(string: string): string { // Can't use goog.string.quote since Google's style guide recommends // JS string literals use single quotes. - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n') - .replace(/'/g, '\\\''); - return '\'' + string + '\''; + string = string + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\\n') + .replace(/'/g, "\\'"); + return "'" + string + "'"; } /** * Encode a string as a properly escaped multiline JavaScript string, complete * with quotes. - * @param {string} string Text to encode. - * @return {string} JavaScript string. + * @param string Text to encode. + * @returns JavaScript string. */ - multiline_quote_(string) { + multiline_quote_(string: string): string { // Can't use goog.string.quote since Google's style guide recommends // JS string literals use single quotes. const lines = string.split(/\n/g).map(this.quote_); - return lines.join(' + \'\\n\' +\n'); + return lines.join(" + '\\n' +\n"); } /** * Common tasks for generating JavaScript from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The JavaScript code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this - * statement. - * @return {string} JavaScript code with comments and subsequent blocks added. + * + * @param block The current block. + * @param code The JavaScript code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns JavaScript code with comments and subsequent blocks added. * @protected */ - scrub_(block, code, opt_thisOnly) { + scrub_(block: Block, code: string, thisOnly = false): string { let commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { @@ -253,7 +269,7 @@ export class JavascriptGenerator extends CodeGenerator { // Don't collect comments for nested statements. for (let i = 0; i < block.inputList.length; i++) { if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); + const childBlock = block.inputList[i].connection!.targetBlock(); if (childBlock) { comment = this.allNestedComments(childBlock); if (comment) { @@ -264,68 +280,69 @@ export class JavascriptGenerator extends CodeGenerator { } } const nextBlock = - block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); + block.nextConnection && block.nextConnection.targetBlock(); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); return commentCode + code + nextCode; } /** - * Gets a property and adjusts the value while taking into account indexing. - * @param {!Block} block The block. - * @param {string} atId The property ID of the element to get. - * @param {number=} opt_delta Value to add. - * @param {boolean=} opt_negate Whether to negate the value. - * @param {number=} opt_order The highest order acting on this value. - * @return {string|number} + * Generate code representing the specified value input, adjusted to take into + * account indexing (zero- or one-based) and optionally by a specified delta + * and/or by negation. + * + * @param block The block. + * @param atId The ID of the input block to get (and adjust) the value of. + * @param delta Value to add. + * @param negate Whether to negate the value. + * @param order The highest order acting on this value. + * @returns The adjusted value. */ - getAdjusted(block, atId, opt_delta, opt_negate, opt_order) { - let delta = opt_delta || 0; - let order = opt_order || this.ORDER_NONE; + getAdjusted( + block: Block, + atId: string, + delta = 0, + negate = false, + order = Order.NONE, + ): string | number { if (block.workspace.options.oneBasedIndex) { delta--; } const defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - let innerOrder; - let outerOrder = order; + let orderForInput = order; if (delta > 0) { - outerOrder = this.ORDER_ADDITION; - innerOrder = this.ORDER_ADDITION; + orderForInput = Order.ADDITION; } else if (delta < 0) { - outerOrder = this.ORDER_SUBTRACTION; - innerOrder = this.ORDER_SUBTRACTION; - } else if (opt_negate) { - outerOrder = this.ORDER_UNARY_NEGATION; - innerOrder = this.ORDER_UNARY_NEGATION; + orderForInput = Order.SUBTRACTION; + } else if (negate) { + orderForInput = Order.UNARY_NEGATION; } - let at = this.valueToCode(block, atId, outerOrder) || defaultAtIndex; + let at = this.valueToCode(block, atId, orderForInput) || defaultAtIndex; + // Easy case: no adjustments. + if (delta === 0 && !negate) { + return at; + } + // If the index is a naked number, adjust it right now. if (stringUtils.isNumber(at)) { - // If the index is a naked number, adjust it right now. - at = Number(at) + delta; - if (opt_negate) { - at = -at; - } - } else { - // If the index is dynamic, adjust it in code. - if (delta > 0) { - at = at + ' + ' + delta; - } else if (delta < 0) { - at = at + ' - ' + -delta; - } - if (opt_negate) { - if (delta) { - at = '-(' + at + ')'; - } else { - at = '-' + at; - } - } - innerOrder = Math.floor(innerOrder); - order = Math.floor(order); - if (innerOrder && order >= innerOrder) { - at = '(' + at + ')'; + at = String(Number(at) + delta); + if (negate) { + at = String(-Number(at)); } + return at; + } + // If the index is dynamic, adjust it in code. + if (delta > 0) { + at = `${at} + ${delta}`; + } else if (delta < 0) { + at = `${at} - ${-delta}`; + } + if (negate) { + at = delta ? `-(${at})` : `-${at}`; + } + if (Math.floor(order) >= Math.floor(orderForInput)) { + at = `(${at})`; } return at; } diff --git a/generators/javascript/lists.js b/generators/javascript/lists.ts similarity index 60% rename from generators/javascript/lists.js rename to generators/javascript/lists.ts index 9e4265716..6283f1d27 100644 --- a/generators/javascript/lists.js +++ b/generators/javascript/lists.ts @@ -11,30 +11,42 @@ // Former goog.module ID: Blockly.JavaScript.lists +import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './javascript_generator.js'; - -export function lists_create_empty(block, generator) { +export function lists_create_empty( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Create an empty list. return ['[]', Order.ATOMIC]; -}; +} -export function lists_create_with(block, generator) { +export function lists_create_with( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + const createWithBlock = block as CreateWithBlock; // Create a list with any number of elements of any type. - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || - 'null'; + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; -}; +} -export function lists_repeat(block, generator) { +export function lists_repeat( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Create a list with one element repeated. - const functionName = generator.provideFunction_('listsRepeat', ` + const functionName = generator.provideFunction_( + 'listsRepeat', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(value, n) { var array = []; for (var i = 0; i < n; i++) { @@ -42,56 +54,61 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(value, n) { } return array; } -`); - const element = - generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; - const repeatCount = - generator.valueToCode(block, 'NUM', Order.NONE) || '0'; +`, + ); + const element = generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; + const repeatCount = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = functionName + '(' + element + ', ' + repeatCount + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_length(block, generator) { +export function lists_length( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // String or array length. - const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + const list = generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; return [list + '.length', Order.MEMBER]; -}; +} -export function lists_isEmpty(block, generator) { +export function lists_isEmpty( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Is the string null or array empty? - const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + const list = generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; return ['!' + list + '.length', Order.LOGICAL_NOT]; -}; +} -export function lists_indexOf(block, generator) { +export function lists_indexOf( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Find an item in the list. const operator = - block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; - const item = - generator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; + const item = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const list = generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; const code = list + '.' + operator + '(' + item + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITION]; } return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_getIndex(block, generator) { +export function lists_getIndex( + block: Block, + generator: JavascriptGenerator, +): [string, Order] | string { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const listOrder = - (where === 'RANDOM') ? Order.NONE : Order.MEMBER; - const list = - generator.valueToCode(block, 'VALUE', listOrder) || '[]'; + const listOrder = where === 'RANDOM' ? Order.NONE : Order.MEMBER; + const list = generator.valueToCode(block, 'VALUE', listOrder) || '[]'; switch (where) { - case ('FIRST'): + case 'FIRST': if (mode === 'GET') { const code = list + '[0]'; return [code, Order.MEMBER]; @@ -102,7 +119,7 @@ export function lists_getIndex(block, generator) { return list + '.shift();\n'; } break; - case ('LAST'): + case 'LAST': if (mode === 'GET') { const code = list + '.slice(-1)[0]'; return [code, Order.MEMBER]; @@ -113,7 +130,7 @@ export function lists_getIndex(block, generator) { return list + '.pop();\n'; } break; - case ('FROM_START'): { + case 'FROM_START': { const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const code = list + '[' + at + ']'; @@ -126,7 +143,7 @@ export function lists_getIndex(block, generator) { } break; } - case ('FROM_END'): { + case 'FROM_END': { const at = generator.getAdjusted(block, 'AT', 1, true); if (mode === 'GET') { const code = list + '.slice(' + at + ')[0]'; @@ -139,9 +156,10 @@ export function lists_getIndex(block, generator) { } break; } - case ('RANDOM'): { - const functionName = - generator.provideFunction_('listsGetRandomItem', ` + case 'RANDOM': { + const functionName = generator.provideFunction_( + 'listsGetRandomItem', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { var x = Math.floor(Math.random() * list.length); if (remove) { @@ -150,7 +168,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { return list[x]; } } -`); +`, + ); const code = functionName + '(' + list + ', ' + (mode !== 'GET') + ')'; if (mode === 'GET' || mode === 'GET_REMOVE') { return [code, Order.FUNCTION_CALL]; @@ -161,40 +180,38 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, remove) { } } throw Error('Unhandled combination (lists_getIndex).'); -}; +} -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: JavascriptGenerator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. - let list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + let list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const value = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || - 'null'; + const value = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } - const listVar = - generator.nameDB_.getDistinctName( - 'tmpList', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmpList', + NameType.VARIABLE, + )!; const code = 'var ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; } switch (where) { - case ('FIRST'): + case 'FIRST': if (mode === 'SET') { return list + '[0] = ' + value + ';\n'; } else if (mode === 'INSERT') { return list + '.unshift(' + value + ');\n'; } break; - case ('LAST'): + case 'LAST': if (mode === 'SET') { let code = cacheList(); code += list + '[' + list + '.length - 1] = ' + value + ';\n'; @@ -203,7 +220,7 @@ export function lists_setIndex(block, generator) { return list + '.push(' + value + ');\n'; } break; - case ('FROM_START'): { + case 'FROM_START': { const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { return list + '[' + at + '] = ' + value + ';\n'; @@ -212,27 +229,40 @@ export function lists_setIndex(block, generator) { } break; } - case ('FROM_END'): { + case 'FROM_END': { const at = generator.getAdjusted( - block, 'AT', 1, false, Order.SUBTRACTION); + block, + 'AT', + 1, + false, + Order.SUBTRACTION, + ); let code = cacheList(); if (mode === 'SET') { code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n'; return code; } else if (mode === 'INSERT') { - code += list + '.splice(' + list + '.length - ' + at + ', 0, ' + value + - ');\n'; + code += + list + + '.splice(' + + list + + '.length - ' + + at + + ', 0, ' + + value + + ');\n'; return code; } break; } - case ('RANDOM'): { + case 'RANDOM': { let code = cacheList(); - const xVar = - generator.nameDB_.getDistinctName( - 'tmpX', NameType.VARIABLE); - code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list + - '.length);\n'; + const xVar = generator.nameDB_!.getDistinctName( + 'tmpX', + NameType.VARIABLE, + ); + code += + 'var ' + xVar + ' = Math.floor(Math.random() * ' + list + '.length);\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; return code; @@ -244,16 +274,20 @@ export function lists_setIndex(block, generator) { } } throw Error('Unhandled combination (lists_setIndex).'); -}; +} /** * Returns an expression calculating the index into a list. - * @param {string} listName Name of the list, used to calculate length. - * @param {string} where The method of indexing, selected by dropdown in Blockly - * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string|undefined} Index expression. + * @param listName Name of the list, used to calculate length. + * @param where The method of indexing, selected by dropdown in Blockly + * @param opt_at The optional offset when indexing from start/end. + * @returns Index expression. */ -const getSubstringIndex = function(listName, where, opt_at) { +const getSubstringIndex = function ( + listName: string, + where: string, + opt_at?: string, +): string | undefined { if (where === 'FIRST') { return '0'; } else if (where === 'FROM_END') { @@ -265,18 +299,29 @@ const getSubstringIndex = function(listName, where, opt_at) { } }; -export function lists_getSublist(block, generator) { +export function lists_getSublist( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Dictionary of WHEREn field choices and their CamelCase equivalents. + const wherePascalCase = { + 'FIRST': 'First', + 'LAST': 'Last', + 'FROM_START': 'FromStart', + 'FROM_END': 'FromEnd', + }; + type WhereOption = keyof typeof wherePascalCase; // Get sublist. - const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; - const where1 = block.getFieldValue('WHERE1'); - const where2 = block.getFieldValue('WHERE2'); + const list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; + const where1 = block.getFieldValue('WHERE1') as WhereOption; + const where2 = block.getFieldValue('WHERE2') as WhereOption; let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = list + '.slice(0)'; } else if ( - list.match(/^\w+$/) || - (where1 !== 'FROM_END' && where2 === 'FROM_START')) { + list.match(/^\w+$/) || + (where1 !== 'FROM_END' && where2 === 'FROM_START') + ) { // If the list is a variable or doesn't require a call for length, don't // generate a helper function. let at1; @@ -285,8 +330,7 @@ export function lists_getSublist(block, generator) { at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = generator.getAdjusted( - block, 'AT1', 1, false, Order.SUBTRACTION); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = list + '.length - ' + at1; break; case 'FIRST': @@ -301,8 +345,7 @@ export function lists_getSublist(block, generator) { at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = generator.getAdjusted( - block, 'AT2', 0, false, Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); at2 = list + '.length - ' + at2; break; case 'LAST': @@ -315,45 +358,49 @@ export function lists_getSublist(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const wherePascalCase = { - 'FIRST': 'First', - 'LAST': 'Last', - 'FROM_START': 'FromStart', - 'FROM_END': 'FromEnd', - }; // The value for 'FROM_END' and'FROM_START' depends on `at` so // we add it as a parameter. const at1Param = - (where1 === 'FROM_END' || where1 === 'FROM_START') ? ', at1' : ''; + where1 === 'FROM_END' || where1 === 'FROM_START' ? ', at1' : ''; const at2Param = - (where2 === 'FROM_END' || where2 === 'FROM_START') ? ', at2' : ''; + where2 === 'FROM_END' || where2 === 'FROM_START' ? ', at2' : ''; const functionName = generator.provideFunction_( - 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { + 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], + ` +function ${ + generator.FUNCTION_NAME_PLACEHOLDER_ + }(sequence${at1Param}${at2Param}) { var start = ${getSubstringIndex('sequence', where1, 'at1')}; var end = ${getSubstringIndex('sequence', where2, 'at2')} + 1; return sequence.slice(start, end); } -`); - code = functionName + '(' + list + - // The value for 'FROM_END' and 'FROM_START' depends on `at` so we - // pass it. - ((where1 === 'FROM_END' || where1 === 'FROM_START') ? ', ' + at1 : '') + - ((where2 === 'FROM_END' || where2 === 'FROM_START') ? ', ' + at2 : '') + - ')'; +`, + ); + code = + functionName + + '(' + + list + + // The value for 'FROM_END' and 'FROM_START' depends on `at` so we + // pass it. + (where1 === 'FROM_END' || where1 === 'FROM_START' ? ', ' + at1 : '') + + (where2 === 'FROM_END' || where2 === 'FROM_START' ? ', ' + at2 : '') + + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_sort(block, generator) { +export function lists_sort( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Block for sorting a list. const list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || - '[]'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || '[]'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const getCompareFunctionName = - generator.provideFunction_('listsGetSortCompare', ` + const getCompareFunctionName = generator.provideFunction_( + 'listsGetSortCompare', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { var compareFuncs = { 'NUMERIC': function(a, b) { @@ -366,19 +413,28 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { var compare = compareFuncs[type]; return function(a, b) { return compare(a, b) * direction; }; } - `); + `, + ); return [ - list + '.slice().sort(' + getCompareFunctionName + '("' + type + '", ' + - direction + '))', - Order.FUNCTION_CALL + list + + '.slice().sort(' + + getCompareFunctionName + + '("' + + type + + '", ' + + direction + + '))', + Order.FUNCTION_CALL, ]; -}; +} -export function lists_split(block, generator) { +export function lists_split( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. let input = generator.valueToCode(block, 'INPUT', Order.MEMBER); - const delimiter = - generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + const delimiter = generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -396,13 +452,15 @@ export function lists_split(block, generator) { } const code = input + '.' + functionName + '(' + delimiter + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_reverse(block, generator) { +export function lists_reverse( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Block for reversing a list. const list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || - '[]'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || '[]'; const code = list + '.slice().reverse()'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/javascript/logic.js b/generators/javascript/logic.js deleted file mode 100644 index 896c8954b..000000000 --- a/generators/javascript/logic.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @license - * Copyright 2012 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Generating JavaScript for logic blocks. - */ - -// Former goog.module ID: Blockly.JavaScript.logic - -import {Order} from './javascript_generator.js'; - - -export function controls_if(block, generator) { - // If/elseif/else condition. - let n = 0; - let code = ''; - if (generator.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += generator.injectId( - generator.STATEMENT_PREFIX, block); - } - do { - const conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || - 'false'; - let branchCode = generator.statementToCode(block, 'DO' + n); - if (generator.STATEMENT_SUFFIX) { - branchCode = generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; - } - code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + - branchCode + '}'; - n++; - } while (block.getInput('IF' + n)); - - if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { - let branchCode = generator.statementToCode(block, 'ELSE'); - if (generator.STATEMENT_SUFFIX) { - branchCode = generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; - } - code += ' else {\n' + branchCode + '}'; - } - return code + '\n'; -}; - -export const controls_ifelse = controls_if; - -export function logic_compare(block, generator) { - // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; - const order = (operator === '==' || operator === '!=') ? - Order.EQUALITY : - Order.RELATIONAL; - const argument0 = generator.valueToCode(block, 'A', order) || '0'; - const argument1 = generator.valueToCode(block, 'B', order) || '0'; - const code = argument0 + ' ' + operator + ' ' + argument1; - return [code, order]; -}; - -export function logic_operation(block, generator) { - // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; - const order = (operator === '&&') ? Order.LOGICAL_AND : - Order.LOGICAL_OR; - let argument0 = generator.valueToCode(block, 'A', order); - let argument1 = generator.valueToCode(block, 'B', order); - if (!argument0 && !argument1) { - // If there are no arguments, then the return value is false. - argument0 = 'false'; - argument1 = 'false'; - } else { - // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === '&&') ? 'true' : 'false'; - if (!argument0) { - argument0 = defaultArgument; - } - if (!argument1) { - argument1 = defaultArgument; - } - } - const code = argument0 + ' ' + operator + ' ' + argument1; - return [code, order]; -}; - -export function logic_negate(block, generator) { - // Negation. - const order = Order.LOGICAL_NOT; - const argument0 = - generator.valueToCode(block, 'BOOL', order) || 'true'; - const code = '!' + argument0; - return [code, order]; -}; - -export function logic_boolean(block, generator) { - // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; - return [code, Order.ATOMIC]; -}; - -export function logic_null(block, generator) { - // Null data type. - return ['null', Order.ATOMIC]; -}; - -export function logic_ternary(block, generator) { - // Ternary operator. - const value_if = - generator.valueToCode(block, 'IF', Order.CONDITIONAL) || - 'false'; - const value_then = - generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || - 'null'; - const value_else = - generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || - 'null'; - const code = value_if + ' ? ' + value_then + ' : ' + value_else; - return [code, Order.CONDITIONAL]; -}; diff --git a/generators/javascript/logic.ts b/generators/javascript/logic.ts new file mode 100644 index 000000000..36604ea7d --- /dev/null +++ b/generators/javascript/logic.ts @@ -0,0 +1,153 @@ +/** + * @license + * Copyright 2012 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Generating JavaScript for logic blocks. + */ + +// Former goog.module ID: Blockly.JavaScript.logic + +import type {Block} from '../../core/block.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; +import {Order} from './javascript_generator.js'; + +export function controls_if(block: Block, generator: JavascriptGenerator) { + // If/elseif/else condition. + let n = 0; + let code = ''; + if (generator.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += generator.injectId(generator.STATEMENT_PREFIX, block); + } + do { + const conditionCode = + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + let branchCode = generator.statementToCode(block, 'DO' + n); + if (generator.STATEMENT_SUFFIX) { + branchCode = + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; + } + code += + (n > 0 ? ' else ' : '') + + 'if (' + + conditionCode + + ') {\n' + + branchCode + + '}'; + n++; + } while (block.getInput('IF' + n)); + + if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { + let branchCode = generator.statementToCode(block, 'ELSE'); + if (generator.STATEMENT_SUFFIX) { + branchCode = + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; + } + code += ' else {\n' + branchCode + '}'; + } + return code + '\n'; +} + +export const controls_ifelse = controls_if; + +export function logic_compare( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Dictionary of OP comparison operators and their implementations. + const OPERATORS = { + 'EQ': '==', + 'NEQ': '!=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; + const order = + operator === '==' || operator === '!=' ? Order.EQUALITY : Order.RELATIONAL; + const argument0 = generator.valueToCode(block, 'A', order) || '0'; + const argument1 = generator.valueToCode(block, 'B', order) || '0'; + const code = argument0 + ' ' + operator + ' ' + argument1; + return [code, order]; +} + +export function logic_operation( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Operations 'and', 'or'. + const operator = block.getFieldValue('OP') === 'AND' ? '&&' : '||'; + const order = operator === '&&' ? Order.LOGICAL_AND : Order.LOGICAL_OR; + let argument0 = generator.valueToCode(block, 'A', order); + let argument1 = generator.valueToCode(block, 'B', order); + if (!argument0 && !argument1) { + // If there are no arguments, then the return value is false. + argument0 = 'false'; + argument1 = 'false'; + } else { + // Single missing arguments have no effect on the return value. + const defaultArgument = operator === '&&' ? 'true' : 'false'; + if (!argument0) { + argument0 = defaultArgument; + } + if (!argument1) { + argument1 = defaultArgument; + } + } + const code = argument0 + ' ' + operator + ' ' + argument1; + return [code, order]; +} + +export function logic_negate( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Negation. + const order = Order.LOGICAL_NOT; + const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; + const code = '!' + argument0; + return [code, order]; +} + +export function logic_boolean( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Boolean values true and false. + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false'; + return [code, Order.ATOMIC]; +} + +export function logic_null( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Null data type. + return ['null', Order.ATOMIC]; +} + +export function logic_ternary( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Ternary operator. + const value_if = + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + const value_then = + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + const value_else = + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; + const code = value_if + ' ? ' + value_then + ' : ' + value_else; + return [code, Order.CONDITIONAL]; +} diff --git a/generators/javascript/loops.js b/generators/javascript/loops.ts similarity index 53% rename from generators/javascript/loops.js rename to generators/javascript/loops.ts index fbe532ce7..a5dd86357 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.ts @@ -11,11 +11,16 @@ // Former goog.module ID: Blockly.JavaScript.loops import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './javascript_generator.js'; - -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext( + block: Block, + generator: JavascriptGenerator, +) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -23,65 +28,88 @@ export function controls_repeat_ext(block, generator) { repeats = String(Number(block.getFieldValue('TIMES'))); } else { // External number. - repeats = - generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || - '0'; + repeats = generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; } let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; - const loopVar = - generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { - endVar = - generator.nameDB_.getDistinctName( - 'repeat_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + 'repeat_end', + NameType.VARIABLE, + ); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } - code += 'for (var ' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + - loopVar + '++) {\n' + branch + '}\n'; + code += + 'for (var ' + + loopVar + + ' = 0; ' + + loopVar + + ' < ' + + endVar + + '; ' + + loopVar + + '++) {\n' + + branch + + '}\n'; return code; -}; +} export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil( + block: Block, + generator: JavascriptGenerator, +) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - generator.valueToCode( - block, 'BOOL', - until ? Order.LOGICAL_NOT : Order.NONE) || - 'false'; + generator.valueToCode( + block, + 'BOOL', + until ? Order.LOGICAL_NOT : Order.NONE, + ) || 'false'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; -}; +} -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: JavascriptGenerator) { // For loop. - const variable0 = - generator.getVariableName( - block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; - const argument1 = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; - const increment = - generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + const increment = generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code; - if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && - stringUtils.isNumber(increment)) { + if ( + stringUtils.isNumber(argument0) && + stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment) + ) { // All arguments are simple numbers. const up = Number(argument0) <= Number(argument1); - code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + - (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; + code = + 'for (' + + variable0 + + ' = ' + + argument0 + + '; ' + + variable0 + + (up ? ' <= ' : ' >= ') + + argument1 + + '; ' + + variable0; const step = Math.abs(Number(increment)); if (step === 1) { code += up ? '++' : '--'; @@ -94,84 +122,117 @@ export function controls_for(block, generator) { // Cache non-trivial values to variables to prevent repeated look-ups. let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { - startVar = generator.nameDB_.getDistinctName( - variable0 + '_start', NameType.VARIABLE); + startVar = generator.nameDB_!.getDistinctName( + variable0 + '_start', + NameType.VARIABLE, + ); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { - endVar = generator.nameDB_.getDistinctName( - variable0 + '_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + variable0 + '_end', + NameType.VARIABLE, + ); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. - const incVar = generator.nameDB_.getDistinctName( - variable0 + '_inc', NameType.VARIABLE); + const incVar = generator.nameDB_!.getDistinctName( + variable0 + '_inc', + NameType.VARIABLE, + ); code += 'var ' + incVar + ' = '; if (stringUtils.isNumber(increment)) { - code += Math.abs(increment) + ';\n'; + code += Math.abs(Number(increment)) + ';\n'; } else { code += 'Math.abs(' + increment + ');\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; - code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + - ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + - ' >= ' + endVar + '; ' + variable0 + ' += ' + incVar + ') {\n' + - branch + '}\n'; + code += + 'for (' + + variable0 + + ' = ' + + startVar + + '; ' + + incVar + + ' >= 0 ? ' + + variable0 + + ' <= ' + + endVar + + ' : ' + + variable0 + + ' >= ' + + endVar + + '; ' + + variable0 + + ' += ' + + incVar + + ') {\n' + + branch + + '}\n'; } return code; -}; +} -export function controls_forEach(block, generator) { +export function controls_forEach(block: Block, generator: JavascriptGenerator) { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || - '[]'; + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; // Cache non-trivial values to variables to prevent repeated look-ups. let listVar = argument0; if (!argument0.match(/^\w+$/)) { - listVar = generator.nameDB_.getDistinctName( - variable0 + '_list', NameType.VARIABLE); + listVar = generator.nameDB_!.getDistinctName( + variable0 + '_list', + NameType.VARIABLE, + ); code += 'var ' + listVar + ' = ' + argument0 + ';\n'; } - const indexVar = generator.nameDB_.getDistinctName( - variable0 + '_index', NameType.VARIABLE); - branch = generator.INDENT + variable0 + ' = ' + listVar + - '[' + indexVar + '];\n' + branch; + const indexVar = generator.nameDB_!.getDistinctName( + variable0 + '_index', + NameType.VARIABLE, + ); + branch = + generator.INDENT + + variable0 + + ' = ' + + listVar + + '[' + + indexVar + + '];\n' + + branch; code += 'for (var ' + indexVar + ' in ' + listVar + ') {\n' + branch + '}\n'; return code; -}; +} -export function controls_flow_statements(block, generator) { +export function controls_flow_statements( + block: Block, + generator: JavascriptGenerator, +) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += generator.injectId( - generator.STATEMENT_PREFIX, block); + xfix += generator.injectId(generator.STATEMENT_PREFIX, block); } if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += generator.injectId( - generator.STATEMENT_SUFFIX, block); + xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += generator.injectId( - generator.STATEMENT_PREFIX, loop); + xfix += generator.injectId(generator.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { @@ -181,4 +242,4 @@ export function controls_flow_statements(block, generator) { return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/javascript/math.js b/generators/javascript/math.ts similarity index 62% rename from generators/javascript/math.js rename to generators/javascript/math.ts index 95fa32f5a..c05e817cf 100644 --- a/generators/javascript/math.js +++ b/generators/javascript/math.ts @@ -11,27 +11,34 @@ // Former goog.module ID: Blockly.JavaScript.math +import type {Block} from '../../core/block.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {Order} from './javascript_generator.js'; - -export function math_number(block, generator) { +export function math_number( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Numeric value. - const code = Number(block.getFieldValue('NUM')); - const order = code >= 0 ? Order.ATOMIC : - Order.UNARY_NEGATION; - return [code, order]; -}; + const number = Number(block.getFieldValue('NUM')); + const order = number >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION; + return [String(number), order]; +} -export function math_arithmetic(block, generator) { +export function math_arithmetic( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITION], 'MINUS': [' - ', Order.SUBTRACTION], 'MULTIPLY': [' * ', Order.MULTIPLICATION], 'DIVIDE': [' / ', Order.DIVISION], - 'POWER': [null, Order.NONE], // Handle power separately. + 'POWER': [null, Order.NONE], // Handle power separately. }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; @@ -44,17 +51,19 @@ export function math_arithmetic(block, generator) { } code = argument0 + operator + argument1; return [code, order]; -}; +} -export function math_single(block, generator) { +export function math_single( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - arg = generator.valueToCode(block, 'NUM', - Order.UNARY_NEGATION) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.UNARY_NEGATION) || '0'; if (arg[0] === '-') { // --3 is not legal in JS. arg = ' ' + arg; @@ -63,11 +72,9 @@ export function math_single(block, generator) { return [code, Order.UNARY_NEGATION]; } if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = generator.valueToCode(block, 'NUM', - Order.DIVISION) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.DIVISION) || '0'; } else { - arg = generator.valueToCode(block, 'NUM', - Order.NONE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. @@ -128,11 +135,14 @@ export function math_single(block, generator) { throw Error('Unknown math operator: ' + operator); } return [code, Order.DIVISION]; -}; +} -export function math_constant(block, generator) { +export function math_constant( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['Math.PI', Order.MEMBER], 'E': ['Math.E', Order.MEMBER], 'GOLDEN_RATIO': ['(1 + Math.sqrt(5)) / 2', Order.DIVISION], @@ -140,33 +150,36 @@ export function math_constant(block, generator) { 'SQRT1_2': ['Math.SQRT1_2', Order.MEMBER], 'INFINITY': ['Infinity', Order.ATOMIC], }; - return CONSTANTS[block.getFieldValue('CONSTANT')]; -}; + type ConstantOption = keyof typeof CONSTANTS; + return CONSTANTS[block.getFieldValue('CONSTANT') as ConstantOption]; +} -export function math_number_property(block, generator) { +export function math_number_property( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. - const PROPERTIES = { + const PROPERTIES: Record = { 'EVEN': [' % 2 === 0', Order.MODULUS, Order.EQUALITY], 'ODD': [' % 2 === 1', Order.MODULUS, Order.EQUALITY], - 'WHOLE': [' % 1 === 0', Order.MODULUS, - Order.EQUALITY], - 'POSITIVE': [' > 0', Order.RELATIONAL, - Order.RELATIONAL], - 'NEGATIVE': [' < 0', Order.RELATIONAL, - Order.RELATIONAL], + 'WHOLE': [' % 1 === 0', Order.MODULUS, Order.EQUALITY], + 'POSITIVE': [' > 0', Order.RELATIONAL, Order.RELATIONAL], + 'NEGATIVE': [' < 0', Order.RELATIONAL, Order.RELATIONAL], 'DIVISIBLE_BY': [null, Order.MODULUS, Order.EQUALITY], 'PRIME': [null, Order.NONE, Order.FUNCTION_CALL], }; - const dropdownProperty = block.getFieldValue('PROPERTY'); + type PropertyOption = keyof typeof PROPERTIES; + const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; const numberToCheck = - generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || - '0'; + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = generator.provideFunction_('mathIsPrime', ` + const functionName = generator.provideFunction_( + 'mathIsPrime', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if (n == 2 || n == 3) { @@ -185,68 +198,81 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { } return true; } -`); +`, + ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MODULUS) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; code = numberToCheck + ' % ' + divisor + ' === 0'; } else { code = numberToCheck + suffix; } return [code, outputOrder]; -}; +} -export function math_change(block, generator) { +export function math_change(block: Block, generator: JavascriptGenerator) { // Add to a variable in place. - const argument0 = generator.valueToCode(block, 'DELTA', - Order.ADDITION) || '0'; + const argument0 = + generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; const varName = generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = (typeof ' + varName + ' === \'number\' ? ' + varName + - ' : 0) + ' + argument0 + ';\n'; -}; + return ( + varName + + ' = (typeof ' + + varName + + " === 'number' ? " + + varName + + ' : 0) + ' + + argument0 + + ';\n' + ); +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); let list; let code; switch (func) { case 'SUM': - list = generator.valueToCode(block, 'LIST', - Order.MEMBER) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; code = list + '.reduce(function(x, y) {return x + y;}, 0)'; break; case 'MIN': - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = 'Math.min.apply(null, ' + list + ')'; break; case 'MAX': - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = 'Math.max.apply(null, ' + list + ')'; break; case 'AVERAGE': { // mathMean([null,null,1,3]) === 2.0. - const functionName = generator.provideFunction_('mathMean', ` + const functionName = generator.provideFunction_( + 'mathMean', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { return myList.reduce(function(x, y) {return x + y;}, 0) / myList.length; } -`); - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; +`, + ); + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { // mathMedian([null,null,1,3]) === 2.0. - const functionName = generator.provideFunction_('mathMedian', ` + const functionName = generator.provideFunction_( + 'mathMedian', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { var localList = myList.filter(function (x) {return typeof x === 'number';}); if (!localList.length) return null; @@ -257,9 +283,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { return localList[(localList.length - 1) / 2]; } } -`); - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; +`, + ); + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } @@ -267,7 +293,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList) { // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. - const functionName = generator.provideFunction_('mathModes', ` + const functionName = generator.provideFunction_( + 'mathModes', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(values) { var modes = []; var counts = []; @@ -296,15 +324,16 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(values) { } return modes; } -`); - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; +`, + ); + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - const functionName = - generator.provideFunction_('mathStandardDeviation', ` + const functionName = generator.provideFunction_( + 'mathStandardDeviation', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(numbers) { var n = numbers.length; if (!n) return null; @@ -316,22 +345,23 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(numbers) { variance = variance / n; return Math.sqrt(variance); } -`); - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; +`, + ); + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'RANDOM': { - const functionName = - generator.provideFunction_('mathRandomList', ` + const functionName = generator.provideFunction_( + 'mathRandomList', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) { var x = Math.floor(Math.random() * list.length); return list[x]; } -`); - list = generator.valueToCode(block, 'LIST', - Order.NONE) || '[]'; +`, + ); + list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } @@ -339,38 +369,51 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) { throw Error('Unknown operator: ' + func); } return [code, Order.FUNCTION_CALL]; -}; +} -export function math_modulo(block, generator) { +export function math_modulo( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Remainder computation. - const argument0 = generator.valueToCode(block, 'DIVIDEND', - Order.MODULUS) || '0'; - const argument1 = generator.valueToCode(block, 'DIVISOR', - Order.MODULUS) || '0'; + const argument0 = + generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; + const argument1 = + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MODULUS]; -}; +} -export function math_constrain(block, generator) { +export function math_constrain( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Constrain a number between two limits. - const argument0 = generator.valueToCode(block, 'VALUE', - Order.NONE) || '0'; - const argument1 = generator.valueToCode(block, 'LOW', - Order.NONE) || '0'; - const argument2 = generator.valueToCode(block, 'HIGH', - Order.NONE) || 'Infinity'; - const code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + - argument2 + ')'; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; + const argument2 = + generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; + const code = + 'Math.min(Math.max(' + + argument0 + + ', ' + + argument1 + + '), ' + + argument2 + + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_int(block, generator) { +export function math_random_int( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Random integer between [X] and [Y]. - const argument0 = generator.valueToCode(block, 'FROM', - Order.NONE) || '0'; - const argument1 = generator.valueToCode(block, 'TO', - Order.NONE) || '0'; - const functionName = generator.provideFunction_('mathRandomInt', ` + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; + const functionName = generator.provideFunction_( + 'mathRandomInt', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(a, b) { if (a > b) { // Swap a and b to ensure a is smaller. @@ -380,22 +423,29 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(a, b) { } return Math.floor(Math.random() * (b - a + 1) + a); } -`); +`, + ); const code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_float(block, generator) { +export function math_random_float( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Random fraction between 0 and 1. return ['Math.random()', Order.FUNCTION_CALL]; -}; +} -export function math_atan2(block, generator) { +export function math_atan2( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. - const argument0 = generator.valueToCode(block, 'X', - Order.NONE) || '0'; - const argument1 = generator.valueToCode(block, 'Y', - Order.NONE) || '0'; - return ['Math.atan2(' + argument1 + ', ' + argument0 + ') / Math.PI * 180', - Order.DIVISION]; -}; + const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; + return [ + 'Math.atan2(' + argument1 + ', ' + argument0 + ') / Math.PI * 180', + Order.DIVISION, + ]; +} diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.ts similarity index 58% rename from generators/javascript/procedures.js rename to generators/javascript/procedures.ts index 7f975289c..f0b5c94f0 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.ts @@ -10,20 +10,23 @@ // Former goog.module ID: Blockly.JavaScript.procedures +import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {Order} from './javascript_generator.js'; - -export function procedures_defreturn(block, generator) { +export function procedures_defreturn( + block: Block, + generator: JavascriptGenerator, +) { // Define a procedure with a return value. const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { - xfix1 += generator.injectId( - generator.STATEMENT_PREFIX, block); + xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); } if (generator.STATEMENT_SUFFIX) { - xfix1 += generator.injectId( - generator.STATEMENT_SUFFIX, block); + xfix1 += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (xfix1) { xfix1 = generator.prefixLines(xfix1, generator.INDENT); @@ -31,13 +34,12 @@ export function procedures_defreturn(block, generator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId( - generator.INFINITE_LOOP_TRAP, block), - generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } const branch = generator.statementToCode(block, 'STACK'); - let returnValue = - generator.valueToCode(block, 'RETURN', Order.NONE) || ''; + let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. @@ -49,63 +51,83 @@ export function procedures_defreturn(block, generator) { const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = - generator.getVariableName(variables[i]); + args[i] = generator.getVariableName(variables[i]); } - let code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + xfix1 + - loopTrap + branch + xfix2 + returnValue + '}'; + let code = + 'function ' + + funcName + + '(' + + args.join(', ') + + ') {\n' + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue + + '}'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Call a procedure with a return value. const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || - 'null'; + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'null'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn( + block: Block, + generator: JavascriptGenerator, +) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn']( + block, + generator, + ) as [string, Order]; return tuple[0] + ';\n'; -}; +} -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn( + block: Block, + generator: JavascriptGenerator, +) { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || - 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. code += generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), - generator.INDENT); + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } - if (block.hasReturnValue_) { - const value = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; + if ((block as IfReturnBlock).hasReturnValue_) { + const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; code += generator.INDENT + 'return ' + value + ';\n'; } else { code += generator.INDENT + 'return;\n'; } code += '}\n'; return code; -}; +} diff --git a/generators/javascript/text.js b/generators/javascript/text.ts similarity index 52% rename from generators/javascript/text.js rename to generators/javascript/text.ts index 32125051f..79008cba9 100644 --- a/generators/javascript/text.js +++ b/generators/javascript/text.ts @@ -10,9 +10,11 @@ // Former goog.module ID: Blockly.JavaScript.texts +import type {Block} from '../../core/block.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; +import type {JavascriptGenerator} from './javascript_generator.js'; import {Order} from './javascript_generator.js'; - /** * Regular expression to detect a single-quoted string literal. */ @@ -21,11 +23,11 @@ const strRegExp = /^\s*'([^']|\\')*'\s*$/; /** * Enclose the provided value in 'String(...)' function. * Leave string literals alone. - * @param {string} value Code evaluating to a value. - * @return {Array} Array containing code evaluating to a string + * @param value Code evaluating to a value. + * @returns Array containing code evaluating to a string * and the order of the returned code.[string, number] */ -const forceString = function(value) { +const forceString = function (value: string): [string, Order] { if (strRegExp.test(value)) { return [value, Order.ATOMIC]; } @@ -34,12 +36,16 @@ const forceString = function(value) { /** * Returns an expression calculating the index into a string. - * @param {string} stringName Name of the string, used to calculate length. - * @param {string} where The method of indexing, selected by dropdown in Blockly - * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string|undefined} Index expression. + * @param stringName Name of the string, used to calculate length. + * @param where The method of indexing, selected by dropdown in Blockly + * @param opt_at The optional offset when indexing from start/end. + * @returns Index expression. */ -const getSubstringIndex = function(stringName, where, opt_at) { +const getSubstringIndex = function ( + stringName: string, + where: string, + opt_at?: string, +): string | undefined { if (where === 'FIRST') { return '0'; } else if (where === 'FROM_END') { @@ -51,101 +57,112 @@ const getSubstringIndex = function(stringName, where, opt_at) { } }; -export function text(block, generator) { +export function text( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block, generator) { +export function text_multiline( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Text value. - const code = - generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = code.indexOf('+') !== -1 ? Order.ADDITION : - Order.ATOMIC; + const code = generator.multiline_quote_(block.getFieldValue('TEXT')); + const order = code.indexOf('+') !== -1 ? Order.ADDITION : Order.ATOMIC; return [code, order]; -}; +} -export function text_join(block, generator) { +export function text_join( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + const joinBlock = block as JoinMutatorBlock; // Create a string made up of any number of elements of any type. - switch (block.itemCount_) { + switch (joinBlock.itemCount_) { case 0: return ["''", Order.ATOMIC]; case 1: { - const element = generator.valueToCode(block, 'ADD0', - Order.NONE) || "''"; + const element = + generator.valueToCode(joinBlock, 'ADD0', Order.NONE) || "''"; const codeAndOrder = forceString(element); return codeAndOrder; } case 2: { - const element0 = generator.valueToCode(block, 'ADD0', - Order.NONE) || "''"; - const element1 = generator.valueToCode(block, 'ADD1', - Order.NONE) || "''"; - const code = forceString(element0)[0] + - ' + ' + forceString(element1)[0]; + const element0 = + generator.valueToCode(joinBlock, 'ADD0', Order.NONE) || "''"; + const element1 = + generator.valueToCode(joinBlock, 'ADD1', Order.NONE) || "''"; + const code = forceString(element0)[0] + ' + ' + forceString(element1)[0]; return [code, Order.ADDITION]; } default: { - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = generator.valueToCode(block, 'ADD' + i, - Order.NONE) || "''"; + const elements = new Array(joinBlock.itemCount_); + for (let i = 0; i < joinBlock.itemCount_; i++) { + elements[i] = + generator.valueToCode(joinBlock, 'ADD' + i, Order.NONE) || "''"; } - const code = '[' + elements.join(',') + '].join(\'\')'; + const code = '[' + elements.join(',') + "].join('')"; return [code, Order.FUNCTION_CALL]; } } -}; +} -export function text_append(block, generator) { +export function text_append(block: Block, generator: JavascriptGenerator) { // Append to a variable in place. const varName = generator.getVariableName(block.getFieldValue('VAR')); - const value = generator.valueToCode(block, 'TEXT', - Order.NONE) || "''"; - const code = varName + ' += ' + - forceString(value)[0] + ';\n'; + const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const code = varName + ' += ' + forceString(value)[0] + ';\n'; return code; -}; +} -export function text_length(block, generator) { +export function text_length( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // String or array length. - const text = generator.valueToCode(block, 'VALUE', - Order.MEMBER) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; return [text + '.length', Order.MEMBER]; -}; +} -export function text_isEmpty(block, generator) { +export function text_isEmpty( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Is the string null or array empty? - const text = generator.valueToCode(block, 'VALUE', - Order.MEMBER) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; return ['!' + text + '.length', Order.LOGICAL_NOT]; -}; +} -export function text_indexOf(block, generator) { +export function text_indexOf( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Search the text for a substring. - const operator = block.getFieldValue('END') === 'FIRST' ? - 'indexOf' : 'lastIndexOf'; - const substring = generator.valueToCode(block, 'FIND', - Order.NONE) || "''"; - const text = generator.valueToCode(block, 'VALUE', - Order.MEMBER) || "''"; + const operator = + block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; const code = text + '.' + operator + '(' + substring + ')'; // Adjust index if using one-based indices. if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITION]; } return [code, Order.FUNCTION_CALL]; -}; +} -export function text_charAt(block, generator) { +export function text_charAt( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = (where === 'RANDOM') ? Order.NONE : - Order.MEMBER; - const text = - generator.valueToCode(block, 'VALUE', textOrder) || "''"; + const textOrder = where === 'RANDOM' ? Order.NONE : Order.MEMBER; + const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { const code = text + '.charAt(0)'; @@ -167,30 +184,44 @@ export function text_charAt(block, generator) { return [code, Order.FUNCTION_CALL]; } case 'RANDOM': { - const functionName = - generator.provideFunction_('textRandomLetter', ` + const functionName = generator.provideFunction_( + 'textRandomLetter', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(text) { var x = Math.floor(Math.random() * text.length); return text[x]; } -`); +`, + ); const code = functionName + '(' + text + ')'; return [code, Order.FUNCTION_CALL]; } } throw Error('Unhandled option (text_charAt).'); -}; +} -export function text_getSubstring(block, generator) { +export function text_getSubstring( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + // Dictionary of WHEREn field choices and their CamelCase equivalents. */ + const wherePascalCase = { + 'FIRST': 'First', + 'LAST': 'Last', + 'FROM_START': 'FromStart', + 'FROM_END': 'FromEnd', + }; + type WhereOption = keyof typeof wherePascalCase; // Get substring. - const where1 = block.getFieldValue('WHERE1'); - const where2 = block.getFieldValue('WHERE2'); - const requiresLengthCall = (where1 !== 'FROM_END' && where1 !== 'LAST' && - where2 !== 'FROM_END' && where2 !== 'LAST'); - const textOrder = requiresLengthCall ? Order.MEMBER : - Order.NONE; - const text = - generator.valueToCode(block, 'STRING', textOrder) || "''"; + const where1 = block.getFieldValue('WHERE1') as WhereOption; + const where2 = block.getFieldValue('WHERE2') as WhereOption; + const requiresLengthCall = + where1 !== 'FROM_END' && + where1 !== 'LAST' && + where2 !== 'FROM_END' && + where2 !== 'LAST'; + const textOrder = requiresLengthCall ? Order.MEMBER : Order.NONE; + const text = generator.valueToCode(block, 'STRING', textOrder) || "''"; let code; if (where1 === 'FIRST' && where2 === 'LAST') { code = text; @@ -204,8 +235,7 @@ export function text_getSubstring(block, generator) { at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = generator.getAdjusted(block, 'AT1', 1, false, - Order.SUBTRACTION); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = text + '.length - ' + at1; break; case 'FIRST': @@ -220,8 +250,7 @@ export function text_getSubstring(block, generator) { at2 = generator.getAdjusted(block, 'AT2', 1); break; case 'FROM_END': - at2 = generator.getAdjusted(block, 'AT2', 0, false, - Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); at2 = text + '.length - ' + at2; break; case 'LAST': @@ -234,82 +263,97 @@ export function text_getSubstring(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const wherePascalCase = {'FIRST': 'First', 'LAST': 'Last', - 'FROM_START': 'FromStart', 'FROM_END': 'FromEnd'}; // The value for 'FROM_END' and'FROM_START' depends on `at` so // we add it as a parameter. const at1Param = - (where1 === 'FROM_END' || where1 === 'FROM_START') ? ', at1' : ''; + where1 === 'FROM_END' || where1 === 'FROM_START' ? ', at1' : ''; const at2Param = - (where2 === 'FROM_END' || where2 === 'FROM_START') ? ', at2' : ''; + where2 === 'FROM_END' || where2 === 'FROM_START' ? ', at2' : ''; const functionName = generator.provideFunction_( - 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(sequence${at1Param}${at2Param}) { + 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2], + ` +function ${ + generator.FUNCTION_NAME_PLACEHOLDER_ + }(sequence${at1Param}${at2Param}) { var start = ${getSubstringIndex('sequence', where1, 'at1')}; var end = ${getSubstringIndex('sequence', where2, 'at2')} + 1; return sequence.slice(start, end); } -`); - code = functionName + '(' + text + - // The value for 'FROM_END' and 'FROM_START' depends on `at` so we - // pass it. - ((where1 === 'FROM_END' || where1 === 'FROM_START') ? ', ' + at1 : '') + - ((where2 === 'FROM_END' || where2 === 'FROM_START') ? ', ' + at2 : '') + - ')'; +`, + ); + code = + functionName + + '(' + + text + + // The value for 'FROM_END' and 'FROM_START' depends on `at` so we + // pass it. + (where1 === 'FROM_END' || where1 === 'FROM_START' ? ', ' + at1 : '') + + (where2 === 'FROM_END' || where2 === 'FROM_START' ? ', ' + at2 : '') + + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} -export function text_changeCase(block, generator) { +export function text_changeCase( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.toUpperCase()', 'LOWERCASE': '.toLowerCase()', 'TITLECASE': null, }; - const operator = OPERATORS[block.getFieldValue('CASE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('CASE') as OperatorOption]; const textOrder = operator ? Order.MEMBER : Order.NONE; - const text = - generator.valueToCode(block, 'TEXT', textOrder) || "''"; + const text = generator.valueToCode(block, 'TEXT', textOrder) || "''"; let code; if (operator) { // Upper and lower case are functions built into generator. code = text + operator; } else { // Title case is not a native JavaScript function. Define one. - const functionName = - generator.provideFunction_('textToTitleCase', ` + const functionName = generator.provideFunction_( + 'textToTitleCase', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) { return str.replace(/\\S+/g, function(txt) {return txt[0].toUpperCase() + txt.substring(1).toLowerCase();}); } -`); +`, + ); code = functionName + '(' + text + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} -export function text_trim(block, generator) { +export function text_trim( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = { 'LEFT': ".replace(/^[\\s\\xa0]+/, '')", 'RIGHT': ".replace(/[\\s\\xa0]+$/, '')", 'BOTH': '.trim()', }; - const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = generator.valueToCode(block, 'TEXT', - Order.MEMBER) || "''"; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; + const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; return [text + operator, Order.FUNCTION_CALL]; -}; +} -export function text_print(block, generator) { +export function text_print(block: Block, generator: JavascriptGenerator) { // Print statement. - const msg = generator.valueToCode(block, 'TEXT', - Order.NONE) || "''"; + const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'window.alert(' + msg + ');\n'; -}; +} -export function text_prompt_ext(block, generator) { +export function text_prompt_ext( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { // Prompt function. let msg; if (block.getField('TEXT')) { @@ -325,16 +369,19 @@ export function text_prompt_ext(block, generator) { code = 'Number(' + code + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { - const text = generator.valueToCode(block, 'TEXT', - Order.NONE) || "''"; - const sub = generator.valueToCode(block, 'SUB', - Order.NONE) || "''"; - const functionName = generator.provideFunction_('textCount', ` +export function text_count( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; + const functionName = generator.provideFunction_( + 'textCount', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) { if (needle.length === 0) { return haystack.length + 1; @@ -342,33 +389,40 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) { return haystack.split(needle).length - 1; } } -`); +`, + ); const code = functionName + '(' + text + ', ' + sub + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_replace(block, generator) { - const text = generator.valueToCode(block, 'TEXT', - Order.NONE) || "''"; - const from = generator.valueToCode(block, 'FROM', - Order.NONE) || "''"; +export function text_replace( + block: Block, + generator: JavascriptGenerator, +): [string, Order] { + const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; + const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; // The regex escaping code below is taken from the implementation of // goog.string.regExpEscape. - const functionName = generator.provideFunction_('textReplace', ` + const functionName = generator.provideFunction_( + 'textReplace', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) { needle = needle.replace(/([-()\\[\\]{}+?*.$\\^|,:# Date: Mon, 30 Oct 2023 15:07:46 -0700 Subject: [PATCH 36/86] chore(deps): Bump concurrently from 8.2.1 to 8.2.2 (#7603) Bumps [concurrently](https://github.com/open-cli-tools/concurrently) from 8.2.1 to 8.2.2. - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](https://github.com/open-cli-tools/concurrently/compare/v8.2.1...v8.2.2) --- updated-dependencies: - dependency-name: concurrently dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b40e3d93c..fb16b4352 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3096,9 +3096,9 @@ } }, "node_modules/concurrently": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.1.tgz", - "integrity": "sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", "dev": true, "dependencies": { "chalk": "^4.1.2", From 32fe20dee0b7a3ab2c288a7b66095c51b159cf17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:08:11 -0700 Subject: [PATCH 37/86] chore(deps): Bump eslint from 8.51.0 to 8.52.0 (#7606) Bumps [eslint](https://github.com/eslint/eslint) from 8.51.0 to 8.52.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.51.0...v8.52.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb16b4352..a8ae7e86b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -411,9 +411,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -526,12 +526,12 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -553,9 +553,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@hyperjump/json-pointer": { @@ -1537,6 +1537,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@wdio/config": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.20.0.tgz", @@ -3876,18 +3882,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", From 30df65680c0c9893041b941897a0bf6d908525c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:09:19 -0700 Subject: [PATCH 38/86] chore(deps): Bump @typescript-eslint/eslint-plugin from 6.7.5 to 6.9.0 (#7614) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.7.5 to 6.9.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 130 +++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8ae7e86b..7ded5023b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1107,9 +1107,9 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", "dev": true }, "node_modules/@types/node": { @@ -1125,9 +1125,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, "node_modules/@types/vinyl": { @@ -1166,16 +1166,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", - "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", + "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.5", - "@typescript-eslint/type-utils": "6.7.5", - "@typescript-eslint/utils": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1201,13 +1201,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", - "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5" + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1218,9 +1218,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", - "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1231,12 +1231,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", - "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1295,13 +1295,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", - "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", + "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.5", - "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1322,9 +1322,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", - "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1335,13 +1335,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", - "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1362,12 +1362,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", - "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1421,17 +1421,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", - "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", + "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.5", - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", "semver": "^7.5.4" }, "engines": { @@ -1446,13 +1446,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", - "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5" + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1463,9 +1463,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", - "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1476,13 +1476,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", - "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1503,12 +1503,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", - "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { From 4003093404785825d6dd009190cf312ce5f44654 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:09:57 -0700 Subject: [PATCH 39/86] chore(deps): Bump webdriverio from 8.20.0 to 8.20.4 (#7616) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.20.0 to 8.20.4. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.20.4/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 64 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ded5023b..23d26a6ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1544,14 +1544,14 @@ "dev": true }, "node_modules/@wdio/config": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.20.0.tgz", - "integrity": "sha512-ODsafHlxEawyYa6IyIdXJMV2plPFyrDbGrXLNKNFBQVfB/FmoHUiiOTh+4Gu+sUXzpn2YNH5O199qHxHw61uUw==", + "version": "8.20.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.20.3.tgz", + "integrity": "sha512-UaPjDjdXztrWgpoodSjZc1/9oXX1WpjhZSW55ZA2PKzCO7QuS/Fory5lMMpJD4v6/9fNUiRp7A4/rd+w7am1vA==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.0", + "@wdio/utils": "8.20.3", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1629,9 +1629,9 @@ } }, "node_modules/@wdio/protocols": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.18.0.tgz", - "integrity": "sha512-TABA0mksHvu5tE8qNYYDR0fDyo90NCANeghbGAtsI8TUsJzgH0dwpos3WSSiB97J9HRSZuWIMa7YuABEkBIjWQ==", + "version": "8.20.4", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.20.4.tgz", + "integrity": "sha512-9PwA2xgjsoB/9Fm8UWRhJlw61O69ckRICuBn0bzoHmMF7uMzYgDvDTekzYKn8JfjzvLm/MnWXL8raCZfQQ0P5g==", "dev": true }, "node_modules/@wdio/repl": { @@ -1659,9 +1659,9 @@ } }, "node_modules/@wdio/utils": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.20.0.tgz", - "integrity": "sha512-nZ5QF5lPyZNJG9YaSrRuVfkVeg80yRrUQT42D0mUDDjmUIh2pAXDMu4HxgxocuQSOyLacg4Vpg3Sju9NFipxIA==", + "version": "8.20.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.20.3.tgz", + "integrity": "sha512-McGS9TFNfjS3cGJkF8hXyajGE5LKFJnPg/fbdXTIBzYohiAzQ1rUMyllPdxxHslnpQPkflBHI6XSYBxU7yB9Lw==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", @@ -8758,9 +8758,9 @@ } }, "node_modules/parse-json": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.0.tgz", - "integrity": "sha512-ihtdrgbqdONYD156Ap6qTcaGcGdkdAxodO1wLqQ/j7HP1u2sFYppINiq4jyC8F+Nm+4fVufylCV00QmkTHkSUg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.21.4", @@ -9551,9 +9551,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", - "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.6.0.tgz", + "integrity": "sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==", "dev": true, "engines": { "node": ">=16" @@ -9575,9 +9575,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", - "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.6.0.tgz", + "integrity": "sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==", "dev": true, "engines": { "node": ">=16" @@ -11728,18 +11728,18 @@ } }, "node_modules/webdriver": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.20.0.tgz", - "integrity": "sha512-U/sej7yljVf/enEWR9L2AtOntrd3lqtkEtHeuSWU2FPp5cWvoMEe7vQiG0WJA74VE2e7uwd8S1LfCgQD1wY3Bg==", + "version": "8.20.4", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.20.4.tgz", + "integrity": "sha512-X/6l+zGXn1trqA1LRwYETIJgkJQTVZ/xE1SrTlSxk2BE7Tq40voxfbDKUyauaCyRyABhA0ZgK5/1UOqeCKW15w==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.20.0", + "@wdio/config": "8.20.3", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.18.0", + "@wdio/protocols": "8.20.4", "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.0", + "@wdio/utils": "8.20.3", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11787,18 +11787,18 @@ } }, "node_modules/webdriverio": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.20.0.tgz", - "integrity": "sha512-nVd3n4v1CYzjEezK6OgmGIcVx+T/7PNYwLK3fTNH2hGRNX05TyGGcR9HAcVZCbIu8WWFKRE0SrLvCjEutPO8gg==", + "version": "8.20.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.20.4.tgz", + "integrity": "sha512-+iyYK0NTviXv3Lyws07CaX9pLET9l0bh8aPICfCyf7f0NZLUDvUoEKvjviMCfLq4lbDu7CFIEyDZUJeuqlRwlw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.20.0", + "@wdio/config": "8.20.3", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.18.0", + "@wdio/protocols": "8.20.4", "@wdio/repl": "8.10.1", "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.0", + "@wdio/utils": "8.20.3", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -11815,7 +11815,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.20.0" + "webdriver": "8.20.4" }, "engines": { "node": "^16.13 || >=18" From 910abf1bb84b5d9da06cc7e4ff4b022b0a2218a8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 31 Oct 2023 10:44:49 -0700 Subject: [PATCH 40/86] feat: add tooltip support for icons (#7608) --- core/icons/icon.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/core/icons/icon.ts b/core/icons/icon.ts index 095f52509..c5979445c 100644 --- a/core/icons/icon.ts +++ b/core/icons/icon.ts @@ -15,6 +15,7 @@ import {Size} from '../utils/size.js'; import {Svg} from '../utils/svg.js'; import type {IconType} from './icon_types.js'; import * as deprecation from '../utils/deprecation.js'; +import * as tooltip from '../tooltip.js'; /** * The abstract icon class. Icons are visual elements that live in the top-start @@ -35,7 +36,12 @@ export abstract class Icon implements IIcon { /** The root svg element visually representing this icon. */ protected svgRoot: SVGGElement | null = null; - constructor(protected sourceBlock: Block) {} + /** The tooltip for this icon. */ + protected tooltip: tooltip.TipInfo; + + constructor(protected sourceBlock: Block) { + this.tooltip = sourceBlock; + } getType(): IconType { throw new Error('Icons must implement getType'); @@ -54,9 +60,12 @@ export abstract class Icon implements IIcon { this, pointerdownListener, ); + (this.svgRoot as any).tooltip = this; + tooltip.bindMouseEvents(this.svgRoot); } dispose(): void { + tooltip.unbindMouseEvents(this.svgRoot); dom.removeNode(this.svgRoot); } @@ -68,6 +77,19 @@ export abstract class Icon implements IIcon { return new Size(0, 0); } + /** + * Sets the tooltip for this icon to the given value. Null to show the + * tooltip of the block. + */ + setTooltip(tip: tooltip.TipInfo | null) { + this.tooltip = tip ?? this.sourceBlock; + } + + /** Returns the tooltip for this icon. */ + getTooltip(): tooltip.TipInfo { + return this.tooltip; + } + applyColour(): void {} updateEditable(): void {} From 37bfcbc31e5e024d45e37cc3d01a57e52e809ddb Mon Sep 17 00:00:00 2001 From: Apoorv Garg <57873504+Apoorvgarg-creator@users.noreply.github.com> Date: Wed, 1 Nov 2023 00:10:15 +0530 Subject: [PATCH 41/86] Fix: #7557 (#7622) --- core/icons/mutator_icon.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/icons/mutator_icon.ts b/core/icons/mutator_icon.ts index a2987bff2..b86ef19c2 100644 --- a/core/icons/mutator_icon.ts +++ b/core/icons/mutator_icon.ts @@ -151,7 +151,9 @@ export class MutatorIcon extends Icon implements IHasBubble { override onClick(): void { super.onClick(); - this.setBubbleVisible(!this.bubbleIsVisible()); + if (this.sourceBlock.isEditable()) { + this.setBubbleVisible(!this.bubbleIsVisible()); + } } bubbleIsVisible(): boolean { From 666a393ac5c99b193225efdd413414d0405f469e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 1 Nov 2023 15:48:34 +0000 Subject: [PATCH 42/86] chore: drop node16 (#7620) --- .github/workflows/browser_test.yml | 2 +- .github/workflows/build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/browser_test.yml b/.github/workflows/browser_test.yml index 9b832e246..5fccc9c11 100644 --- a/.github/workflows/browser_test.yml +++ b/.github/workflows/browser_test.yml @@ -19,7 +19,7 @@ jobs: # TODO (#2114): re-enable osx build. # os: [ubuntu-latest, macos-latest] os: [macos-latest] - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85866cb2e..04eba7308 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: # TODO (#2114): re-enable osx build. # os: [ubuntu-latest, macos-latest] os: [ubuntu-latest] - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ From 73841995ec5ad6be9a40160f0d408fd8dcac34d3 Mon Sep 17 00:00:00 2001 From: Trey Pisano <126501514+treypisano@users.noreply.github.com> Date: Wed, 1 Nov 2023 11:52:27 -0400 Subject: [PATCH 43/86] fix: flyout id is different than first placed block (#7618) * add saveIds param and logic to save correctly * remove whitespace * add saveIds to recursive calls * run format * change name from addIds to saveIds * add saveIds test * change blockId on false saveIds to undefined --- core/flyout_base.ts | 2 +- core/serialization/blocks.ts | 26 +++++++++++++++++++++----- tests/mocha/jso_serialization_test.js | 6 ++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index bb30a45cb..49341d37c 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -1213,7 +1213,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { // Clone the block. // TODO(#7432): Add a saveIds parameter to `save`. - const json = blocks.save(oldBlock) as blocks.State; + const json = blocks.save(oldBlock, {saveIds: false}) as blocks.State; // Normallly this resizes leading to weird jumps. Save it for terminateDrag. targetWorkspace.setResizesEnabled(false); const block = blocks.append(json, targetWorkspace) as BlockSvg; diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index e53f30944..498f6000c 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -86,20 +86,21 @@ export function save( addInputBlocks = true, addNextBlocks = true, doFullSerialization = true, + saveIds = true, }: { addCoordinates?: boolean; addInputBlocks?: boolean; addNextBlocks?: boolean; doFullSerialization?: boolean; + saveIds?: boolean; } = {}, ): State | null { if (block.isInsertionMarker()) { return null; } - const state = { 'type': block.type, - 'id': block.id, + 'id': saveIds ? block.id : undefined, }; if (addCoordinates) { @@ -122,12 +123,22 @@ export function save( if (addInputBlocks) { // AnyDuringMigration because: Argument of type '{ type: string; id: // string; }' is not assignable to parameter of type 'State'. - saveInputBlocks(block, state as AnyDuringMigration, doFullSerialization); + saveInputBlocks( + block, + state as AnyDuringMigration, + doFullSerialization, + saveIds, + ); } if (addNextBlocks) { // AnyDuringMigration because: Argument of type '{ type: string; id: // string; }' is not assignable to parameter of type 'State'. - saveNextBlocks(block, state as AnyDuringMigration, doFullSerialization); + saveNextBlocks( + block, + state as AnyDuringMigration, + doFullSerialization, + saveIds, + ); } // AnyDuringMigration because: Type '{ type: string; id: string; }' is not @@ -270,6 +281,7 @@ function saveInputBlocks( block: Block, state: State, doFullSerialization: boolean, + saveIds: boolean, ) { const inputs = Object.create(null); for (let i = 0; i < block.inputList.length; i++) { @@ -278,6 +290,7 @@ function saveInputBlocks( const connectionState = saveConnection( input.connection as Connection, doFullSerialization, + saveIds, ); if (connectionState) { inputs[input.name] = connectionState; @@ -301,6 +314,7 @@ function saveNextBlocks( block: Block, state: State, doFullSerialization: boolean, + saveIds: boolean, ) { if (!block.nextConnection) { return; @@ -308,6 +322,7 @@ function saveNextBlocks( const connectionState = saveConnection( block.nextConnection, doFullSerialization, + saveIds, ); if (connectionState) { state['next'] = connectionState; @@ -326,6 +341,7 @@ function saveNextBlocks( function saveConnection( connection: Connection, doFullSerialization: boolean, + saveIds: boolean, ): ConnectionState | null { const shadow = connection.getShadowState(true); const child = connection.targetBlock(); @@ -337,7 +353,7 @@ function saveConnection( state['shadow'] = shadow; } if (child && !child.isShadow()) { - state['block'] = save(child, {doFullSerialization}); + state['block'] = save(child, {doFullSerialization, saveIds}); } return state; } diff --git a/tests/mocha/jso_serialization_test.js b/tests/mocha/jso_serialization_test.js index 500bb2011..895ff0be2 100644 --- a/tests/mocha/jso_serialization_test.js +++ b/tests/mocha/jso_serialization_test.js @@ -61,6 +61,12 @@ suite('JSO Serialization', function () { assertProperty(jso, 'id', 'id0'); }); + test('saveId false', function () { + const block = this.workspace.newBlock('row_block'); + const jso = Blockly.serialization.blocks.save(block, {saveIds: false}); + assertProperty(jso, 'id', undefined); + }); + suite('Attributes', function () { suite('Collapsed', function () { test('True', function () { From 5322078056e44b6853247c062654a81d7c574860 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:47:24 -0700 Subject: [PATCH 44/86] chore(deps): Bump @hyperjump/json-schema from 1.5.2 to 1.6.4 (#7615) Bumps [@hyperjump/json-schema](https://github.com/hyperjump-io/json-schema) from 1.5.2 to 1.6.4. - [Commits](https://github.com/hyperjump-io/json-schema/compare/v1.5.2...v1.6.4) --- updated-dependencies: - dependency-name: "@hyperjump/json-schema" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 23d26a6ec..87dc47b60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -572,9 +572,9 @@ } }, "node_modules/@hyperjump/json-schema": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.5.2.tgz", - "integrity": "sha512-sjYufclp9Qa3o7MbDSbBoxi7TzWy0N11sRj1HyF/oU1G/TvPqrxd7mIvqUiaN3yLXd4EeparDSs3SGLZSrBVKQ==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.6.4.tgz", + "integrity": "sha512-GaROZHhIBvOcigBZkQVMcuBJFe0RKhOxydLoTWkqtyhAoX17RqK1kKgfs7oTll8jO42ITnC6Ehj7CjjMDMBBLQ==", "dev": true, "dependencies": { "@hyperjump/json-pointer": "^1.0.0", From 10024bd54e5092a33b466aba7e420af7c81fa736 Mon Sep 17 00:00:00 2001 From: Apoorv Garg <57873504+Apoorvgarg-creator@users.noreply.github.com> Date: Wed, 1 Nov 2023 22:29:21 +0530 Subject: [PATCH 45/86] fix: prevent crash when clicking on a field to delete a block (#7621) * Fix: #7587 * Fix: Lint error * Fix: Move expression out of loop * Fix: No need to use temp variable --- core/block_svg.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index e175db567..caaf89db1 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -1183,6 +1183,9 @@ export class BlockSvg bringToFront(blockOnly = false) { /* eslint-disable-next-line @typescript-eslint/no-this-alias */ let block: this | null = this; + if (block.isDeadOrDying()) { + return; + } do { const root = block.getSvgRoot(); const parent = root.parentNode; From 1b498681dd87bf8af28b0692bf9ce2249bef3d5f Mon Sep 17 00:00:00 2001 From: Siddheya Kulkarni <115717746+Asymtode712@users.noreply.github.com> Date: Thu, 2 Nov 2023 20:55:24 +0530 Subject: [PATCH 46/86] feat: add css classes to icons (#7626) * Update comment_icon.ts * Update mutator_icon.ts * Update warning_icon.ts * Update comment_icon.ts * Update mutator_icon.ts * Update warning_icon.ts * Update core/icons/comment_icon.ts Co-authored-by: Beka Westberg * Update mutator_icon.ts * Update warning_icon.ts --------- Co-authored-by: Beka Westberg --- core/icons/comment_icon.ts | 1 + core/icons/mutator_icon.ts | 1 + core/icons/warning_icon.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index d99588fe6..364ef67d1 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -110,6 +110,7 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { }, this.svgRoot, ); + dom.addClass(this.svgRoot!, 'blockly-icon-comment'); } override dispose() { diff --git a/core/icons/mutator_icon.ts b/core/icons/mutator_icon.ts index b86ef19c2..c53d58f8a 100644 --- a/core/icons/mutator_icon.ts +++ b/core/icons/mutator_icon.ts @@ -118,6 +118,7 @@ export class MutatorIcon extends Icon implements IHasBubble { {'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, this.svgRoot, ); + dom.addClass(this.svgRoot!, 'blockly-icon-mutator'); } override dispose(): void { diff --git a/core/icons/warning_icon.ts b/core/icons/warning_icon.ts index edb763f82..7c44d0d34 100644 --- a/core/icons/warning_icon.ts +++ b/core/icons/warning_icon.ts @@ -88,6 +88,7 @@ export class WarningIcon extends Icon implements IHasBubble { }, this.svgRoot, ); + dom.addClass(this.svgRoot!, 'blockly-icon-warning'); } override dispose() { From 9d117674ce64e88db35edd4426334fa4ae23d832 Mon Sep 17 00:00:00 2001 From: Apoorv Garg <57873504+Apoorvgarg-creator@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:01:17 +0530 Subject: [PATCH 47/86] Fix: #7416 (#7628) --- core/field_dropdown.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index 4aaed32b8..ad728f226 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -278,12 +278,8 @@ export class FieldDropdown extends Field { dom.addClass(menuElement, 'blocklyDropdownMenu'); if (this.getConstants()!.FIELD_DROPDOWN_COLOURED_DIV) { - const primaryColour = block.isShadow() - ? block.getParent()!.getColour() - : block.getColour(); - const borderColour = block.isShadow() - ? (block.getParent() as BlockSvg).style.colourTertiary - : (this.sourceBlock_ as BlockSvg).style.colourTertiary; + const primaryColour = block.getColour(); + const borderColour = (this.sourceBlock_ as BlockSvg).style.colourTertiary; dropDownDiv.setColour(primaryColour, borderColour); } From 0ad57f4fd37baf7e476d9fecc9cc34af11ef09e8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 3 Nov 2023 18:19:30 +0000 Subject: [PATCH 48/86] fix: shadows in insertion markers being displayed as shadows (#7609) * fix: shadows in insertion markers being displayed as shadows * chore: add unit tests * chore: remove only --- core/insertion_marker_manager.ts | 4 ++ tests/mocha/insertion_marker_manager_test.js | 73 ++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/core/insertion_marker_manager.ts b/core/insertion_marker_manager.ts index e9d04f728..69d3d2cb9 100644 --- a/core/insertion_marker_manager.ts +++ b/core/insertion_marker_manager.ts @@ -271,6 +271,10 @@ export class InsertionMarkerManager { } } + for (const block of result.getDescendants(false)) { + block.setInsertionMarker(true); + } + result.setCollapsed(sourceBlock.isCollapsed()); result.setInputsInline(sourceBlock.getInputsInline()); diff --git a/tests/mocha/insertion_marker_manager_test.js b/tests/mocha/insertion_marker_manager_test.js index 26996fa95..75cad8ebc 100644 --- a/tests/mocha/insertion_marker_manager_test.js +++ b/tests/mocha/insertion_marker_manager_test.js @@ -177,6 +177,79 @@ suite('Insertion marker manager', function () { const markers = manager.getInsertionMarkers(); chai.assert.equal(markers.length, 2); }); + + suite('children being set as insertion markers', function () { + setup(function () { + Blockly.Blocks['shadows_in_init'] = { + init: function () { + this.appendValueInput('test').connection.setShadowState({ + 'type': 'math_number', + }); + this.setPreviousStatement(true); + }, + }; + + Blockly.Blocks['shadows_in_load'] = { + init: function () { + this.appendValueInput('test'); + this.setPreviousStatement(true); + }, + + loadExtraState: function () { + this.getInput('test').connection.setShadowState({ + 'type': 'math_number', + }); + }, + + saveExtraState: function () { + return true; + }, + }; + }); + + teardown(function () { + delete Blockly.Blocks['shadows_in_init']; + delete Blockly.Blocks['shadows_in_load']; + }); + + test('Shadows added in init are set as insertion markers', function () { + const state = { + 'blocks': { + 'blocks': [ + { + 'id': 'first', + 'type': 'shadows_in_init', + }, + ], + }, + }; + const manager = createBlocksAndManager(this.workspace, state); + const markers = manager.getInsertionMarkers(); + chai.assert.isTrue( + markers[0].getChildren()[0].isInsertionMarker(), + 'Expected the shadow block to be an insertion maker', + ); + }); + + test('Shadows added in `loadExtraState` are set as insertion markers', function () { + const state = { + 'blocks': { + 'blocks': [ + { + 'id': 'first', + 'type': 'shadows_in_load', + }, + ], + }, + }; + const manager = createBlocksAndManager(this.workspace, state); + const markers = manager.getInsertionMarkers(); + chai.assert.isTrue( + markers[0].getChildren()[0].isInsertionMarker(), + 'Expected the shadow block to be an insertion maker', + ); + }); + }); }); suite('Would delete block', function () { From f82cbc3ef0f237129c0743978837cf8c421ab014 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:06:46 -0800 Subject: [PATCH 49/86] chore(deps): Bump @hyperjump/json-schema from 1.6.4 to 1.6.5 (#7633) Bumps [@hyperjump/json-schema](https://github.com/hyperjump-io/json-schema) from 1.6.4 to 1.6.5. - [Commits](https://github.com/hyperjump-io/json-schema/commits) --- updated-dependencies: - dependency-name: "@hyperjump/json-schema" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87dc47b60..36ba4d5ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -572,9 +572,9 @@ } }, "node_modules/@hyperjump/json-schema": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.6.4.tgz", - "integrity": "sha512-GaROZHhIBvOcigBZkQVMcuBJFe0RKhOxydLoTWkqtyhAoX17RqK1kKgfs7oTll8jO42ITnC6Ehj7CjjMDMBBLQ==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.6.5.tgz", + "integrity": "sha512-m9Ozq32JH9yy55JH4d/coXd2KGXKIWunzJZWr6J+rTRHvpchy7bZ7SBBLxLvslGJ5yoVSRQ4bEPh1mgJCzNhqg==", "dev": true, "dependencies": { "@hyperjump/json-pointer": "^1.0.0", From 4f73dc2440483f6f4b2a12cf8e7ed557feda8499 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:07:38 -0800 Subject: [PATCH 50/86] chore(deps): Bump @blockly/block-test from 5.0.0 to 5.0.2 (#7629) Bumps [@blockly/block-test](https://github.com/google/blockly-samples/tree/HEAD/plugins/block-test) from 5.0.0 to 5.0.2. - [Release notes](https://github.com/google/blockly-samples/releases) - [Changelog](https://github.com/google/blockly-samples/blob/master/plugins/block-test/CHANGELOG.md) - [Commits](https://github.com/google/blockly-samples/commits/@blockly/block-test@5.0.2/plugins/block-test) --- updated-dependencies: - dependency-name: "@blockly/block-test" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 36ba4d5ef..6fff44fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -253,9 +253,9 @@ } }, "node_modules/@blockly/block-test": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-5.0.0.tgz", - "integrity": "sha512-TASw4N3FQpJekOJTAm8ubGXOqf1pzVRBM64uqE6g+PtOgGGKw9G7F+Fs+OccS96mjwPEg1e+Eh6rsLRdV5kMqA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-5.0.2.tgz", + "integrity": "sha512-oZUc7DAdZZcYLUmx6Rqq9VkTyTj0vR9rrExmI6dqiOV0Jip12/244e05HrGQioz2MMN1xmsU8LmM89NnTj6uzw==", "dev": true, "engines": { "node": ">=8.17.0" From d8eb7b56bbf185521e1e85092da855b1addb61c4 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 7 Nov 2023 21:12:21 +0000 Subject: [PATCH 51/86] fix: make autoclose toggleable for flyouts (#7634) * fix: add basic autoclose toggling support * fix: drag areas being incorrect * fix: blocks getting bumped around when dragged into flyout area * fix: respect always-open flyouts attached to toolboxes * fix: flyout not hiding on ws click * fix: have all flyouts filter for capacity * chore: cleanup * fix: view metrics not respecting flyout * chore: fix change detectors * fix: trashcan not firing close event on click --- core/flyout_base.ts | 38 +++++-- core/flyout_horizontal.ts | 16 +-- core/flyout_vertical.ts | 16 +-- core/metrics_manager.ts | 69 ++++++------- tests/mocha/metrics_test.js | 185 +++++++++++++++++++++++++++-------- tests/mocha/trashcan_test.js | 10 +- 6 files changed, 212 insertions(+), 122 deletions(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 49341d37c..219d69e3e 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -36,6 +36,7 @@ import {WorkspaceSvg} from './workspace_svg.js'; import * as utilsXml from './utils/xml.js'; import * as Xml from './xml.js'; import * as renderManagement from './render_management.js'; +import {IAutoHideable} from './interfaces/i_autohideable.js'; enum FlyoutItemType { BLOCK = 'block', @@ -45,7 +46,10 @@ enum FlyoutItemType { /** * Class for a flyout. */ -export abstract class Flyout extends DeleteArea implements IFlyout { +export abstract class Flyout + extends DeleteArea + implements IAutoHideable, IFlyout +{ /** * Position the flyout. */ @@ -385,10 +389,8 @@ export abstract class Flyout extends DeleteArea implements IFlyout { this.wheel_, ), ); - if (!this.autoClose) { - this.filterWrapper = this.filterForCapacity.bind(this); - this.targetWorkspace.addChangeListener(this.filterWrapper); - } + this.filterWrapper = this.filterForCapacity.bind(this); + this.targetWorkspace.addChangeListener(this.filterWrapper); // Dragging the flyout up and down. this.boundEvents.push( @@ -414,6 +416,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { component: this, weight: 1, capabilities: [ + ComponentManager.Capability.AUTOHIDEABLE, ComponentManager.Capability.DELETE_AREA, ComponentManager.Capability.DRAG_TARGET, ], @@ -426,7 +429,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { */ dispose() { this.hide(); - this.workspace_.getComponentManager().removeComponent(this.id); + this.targetWorkspace.getComponentManager().removeComponent(this.id); for (const event of this.boundEvents) { browserEvents.unbind(event); } @@ -480,6 +483,26 @@ export abstract class Flyout extends DeleteArea implements IFlyout { return this.workspace_; } + /** + * Sets whether this flyout automatically closes when blocks are dragged out, + * the workspace is clicked, etc, or not. + */ + setAutoClose(autoClose: boolean) { + this.autoClose = autoClose; + this.targetWorkspace.recordDragTargets(); + this.targetWorkspace.resizeContents(); + } + + /** Automatically hides the flyout if it is an autoclosing flyout. */ + autoHide(onlyClosePopups: boolean): void { + if ( + !onlyClosePopups && + this.targetWorkspace.getFlyout(true) === this && + this.autoClose + ) + this.hide(); + } + /** * Is the flyout visible? * @@ -504,7 +527,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { if (!this.autoClose) { // Auto-close flyouts are ignored as drag targets, so only non // auto-close flyouts need to have their drag target updated. - this.workspace_.recordDragTargets(); + this.targetWorkspace.recordDragTargets(); } this.updateDisplay(); } @@ -624,6 +647,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { // Parse the Array, Node or NodeList into a a list of flyout items. const parsedContent = toolbox.convertFlyoutDefToJsonArray(flyoutDef); + if (!parsedContent.length) return; // No need to show an empty flyout. const flyoutInfo = this.createFlyoutInfo(parsedContent); renderManagement.triggerQueuedRenders(); diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index 9d827f4ea..02ac7377a 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -382,22 +382,10 @@ export class HorizontalFlyout extends Flyout { } } - if ( - this.targetWorkspace!.toolboxPosition === this.toolboxPosition_ && - this.toolboxPosition_ === toolbox.Position.TOP && - !this.targetWorkspace!.getToolbox() - ) { - // This flyout is a simple toolbox. Reposition the workspace so that - // (0,0) is in the correct position relative to the new absolute edge - // (ie toolbox edge). - this.targetWorkspace!.translate( - this.targetWorkspace!.scrollX, - this.targetWorkspace!.scrollY + flyoutHeight, - ); - } this.height_ = flyoutHeight; this.position(); - this.targetWorkspace!.recordDragTargets(); + this.targetWorkspace.resizeContents(); + this.targetWorkspace.recordDragTargets(); } } } diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index b3e656d0c..72c53efbf 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -375,22 +375,10 @@ export class VerticalFlyout extends Flyout { } } - if ( - this.targetWorkspace!.toolboxPosition === this.toolboxPosition_ && - this.toolboxPosition_ === toolbox.Position.LEFT && - !this.targetWorkspace!.getToolbox() - ) { - // This flyout is a simple toolbox. Reposition the workspace so that - // (0,0) is in the correct position relative to the new absolute edge - // (ie toolbox edge). - this.targetWorkspace!.translate( - this.targetWorkspace!.scrollX + flyoutWidth, - this.targetWorkspace!.scrollY, - ); - } this.width_ = flyoutWidth; this.position(); - this.targetWorkspace!.recordDragTargets(); + this.targetWorkspace.resizeContents(); + this.targetWorkspace.recordDragTargets(); } } } diff --git a/core/metrics_manager.ts b/core/metrics_manager.ts index cbadcefac..62a2614b6 100644 --- a/core/metrics_manager.ts +++ b/core/metrics_manager.ts @@ -111,26 +111,25 @@ export class MetricsManager implements IMetricsManager { */ getAbsoluteMetrics(): AbsoluteMetrics { let absoluteLeft = 0; + let absoluteTop = 0; + const toolboxMetrics = this.getToolboxMetrics(); - const flyoutMetrics = this.getFlyoutMetrics(true); - const doesToolboxExist = !!this.workspace_.getToolbox(); - const doesFlyoutExist = !!this.workspace_.getFlyout(true); - const toolboxPosition = doesToolboxExist + const flyoutMetrics = this.getFlyoutMetrics(); + const respectToolbox = !!this.workspace_.getToolbox(); + const respectFlyout = !this.workspace_.getFlyout()?.autoClose; + const toolboxPosition = respectToolbox ? toolboxMetrics.position : flyoutMetrics.position; const atLeft = toolboxPosition === toolboxUtils.Position.LEFT; const atTop = toolboxPosition === toolboxUtils.Position.TOP; - if (doesToolboxExist && atLeft) { - absoluteLeft = toolboxMetrics.width; - } else if (doesFlyoutExist && atLeft) { - absoluteLeft = flyoutMetrics.width; + if (atLeft) { + if (respectToolbox) absoluteLeft += toolboxMetrics.width; + if (respectFlyout) absoluteLeft += flyoutMetrics.width; } - let absoluteTop = 0; - if (doesToolboxExist && atTop) { - absoluteTop = toolboxMetrics.height; - } else if (doesFlyoutExist && atTop) { - absoluteTop = flyoutMetrics.height; + if (atTop) { + if (respectToolbox) absoluteTop += toolboxMetrics.height; + if (respectFlyout) absoluteTop += flyoutMetrics.height; } return { @@ -152,36 +151,26 @@ export class MetricsManager implements IMetricsManager { const scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1; const svgMetrics = this.getSvgMetrics(); const toolboxMetrics = this.getToolboxMetrics(); - const flyoutMetrics = this.getFlyoutMetrics(true); - const doesToolboxExist = !!this.workspace_.getToolbox(); - const toolboxPosition = doesToolboxExist + const flyoutMetrics = this.getFlyoutMetrics(); + const respectToolbox = !!this.workspace_.getToolbox(); + const respectFlyout = !this.workspace_.getFlyout()?.autoClose; + const toolboxPosition = respectToolbox ? toolboxMetrics.position : flyoutMetrics.position; - if (this.workspace_.getToolbox()) { - if ( - toolboxPosition === toolboxUtils.Position.TOP || - toolboxPosition === toolboxUtils.Position.BOTTOM - ) { - svgMetrics.height -= toolboxMetrics.height; - } else if ( - toolboxPosition === toolboxUtils.Position.LEFT || - toolboxPosition === toolboxUtils.Position.RIGHT - ) { - svgMetrics.width -= toolboxMetrics.width; - } - } else if (this.workspace_.getFlyout(true)) { - if ( - toolboxPosition === toolboxUtils.Position.TOP || - toolboxPosition === toolboxUtils.Position.BOTTOM - ) { - svgMetrics.height -= flyoutMetrics.height; - } else if ( - toolboxPosition === toolboxUtils.Position.LEFT || - toolboxPosition === toolboxUtils.Position.RIGHT - ) { - svgMetrics.width -= flyoutMetrics.width; - } + const horizToolbox = + toolboxPosition === toolboxUtils.Position.TOP || + toolboxPosition === toolboxUtils.Position.BOTTOM; + const vertToolbox = + toolboxPosition === toolboxUtils.Position.LEFT || + toolboxPosition === toolboxUtils.Position.RIGHT; + if (horizToolbox) { + if (respectToolbox) svgMetrics.height -= toolboxMetrics.height; + if (respectFlyout) svgMetrics.height -= flyoutMetrics.height; + } + if (vertToolbox) { + if (respectToolbox) svgMetrics.width -= toolboxMetrics.width; + if (respectFlyout) svgMetrics.width -= flyoutMetrics.width; } return { height: svgMetrics.height / scale, diff --git a/tests/mocha/metrics_test.js b/tests/mocha/metrics_test.js index 83fa605c6..ea2cba7ba 100644 --- a/tests/mocha/metrics_test.js +++ b/tests/mocha/metrics_test.js @@ -68,45 +68,93 @@ suite('Metrics', function () { 'getFlyout', ); }); - test('Toolbox at left', function () { - this.toolboxMetricsStub.returns({width: 107, height: 0, position: 2}); - this.flyoutMetricsStub.returns({}); + + test('left toolboxes with always open flyouts have both offsets', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); this.getToolboxStub.returns(true); - this.getFlyoutStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); - assertDimensionsMatch(absoluteMetrics, 107, 0); + assertDimensionsMatch(absoluteMetrics, 150, 0); }); - test('Toolbox at top', function () { - this.toolboxMetricsStub.returns({width: 0, height: 107, position: 0}); - this.flyoutMetricsStub.returns({}); + + test('top toolboxes with always open flyouts have both offsets', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); this.getToolboxStub.returns(true); - this.getFlyoutStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); - assertDimensionsMatch(absoluteMetrics, 0, 107); + assertDimensionsMatch(absoluteMetrics, 0, 150); }); - test('Flyout at left', function () { - this.toolboxMetricsStub.returns({}); - this.flyoutMetricsStub.returns({width: 107, height: 0, position: 2}); - this.getToolboxStub.returns(false); - this.getFlyoutStub.returns(true); + + test('left toolboxes with autoclosing flyouts only have a toolbox offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); + this.getToolboxStub.returns(true); + this.getFlyoutStub.returns({autoClose: true}); const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); - assertDimensionsMatch(absoluteMetrics, 107, 0); + assertDimensionsMatch(absoluteMetrics, 50, 0); }); - test('Flyout at top', function () { - this.toolboxMetricsStub.returns({}); - this.flyoutMetricsStub.returns({width: 0, height: 107, position: 0}); - this.getToolboxStub.returns(false); - this.getFlyoutStub.returns(true); + + test('top toolboxes with autoclosing flyouts only have a toolbox offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); + this.getToolboxStub.returns(true); + this.getFlyoutStub.returns({autoClose: true}); const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); - assertDimensionsMatch(absoluteMetrics, 0, 107); + assertDimensionsMatch(absoluteMetrics, 0, 50); + }); + + test('left always open flyouts have a flyout offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); + + const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); + + assertDimensionsMatch(absoluteMetrics, 100, 0); + }); + + test('top always open flyouts have a flyout offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); + + const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); + + assertDimensionsMatch(absoluteMetrics, 0, 100); + }); + + test('left autoclosing flyouts have no offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: true}); + + const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); + + assertDimensionsMatch(absoluteMetrics, 0, 0); + }); + + test('top autoclosing flyouts have no offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: true}); + + const absoluteMetrics = this.metricsManager.getAbsoluteMetrics(); + + assertDimensionsMatch(absoluteMetrics, 0, 0); }); }); @@ -132,50 +180,103 @@ suite('Metrics', function () { ); this.svgMetricsStub = sinon.stub(this.metricsManager, 'getSvgMetrics'); }); - test('Toolbox at left', function () { - this.toolboxMetricsStub.returns({width: 107, height: 0, position: 2}); - this.flyoutMetricsStub.returns({}); + + test('left toolboxes with always open flyouts have both offsets', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); this.svgMetricsStub.returns({width: 500, height: 500}); this.getToolboxStub.returns(true); - this.getFlyoutStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); const viewMetrics = this.metricsManager.getViewMetrics(); - assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 393, 500); + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 350, 500); }); - test('Toolbox at top', function () { - this.toolboxMetricsStub.returns({width: 0, height: 107, position: 0}); - this.flyoutMetricsStub.returns({}); + + test('top toolboxes with always open flyouts have both offsets', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); this.svgMetricsStub.returns({width: 500, height: 500}); this.getToolboxStub.returns(true); - this.getFlyoutStub.returns(false); + this.getFlyoutStub.returns({autoClose: false}); const viewMetrics = this.metricsManager.getViewMetrics(); - assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 393); + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 350); }); - test('Flyout at left', function () { - this.toolboxMetricsStub.returns({}); - this.flyoutMetricsStub.returns({width: 107, height: 0, position: 2}); + + test('left toolboxes with autoclosing flyouts only have a toolbox offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); + this.svgMetricsStub.returns({width: 500, height: 500}); + this.getToolboxStub.returns(true); + this.getFlyoutStub.returns({autoClose: true}); + + const viewMetrics = this.metricsManager.getViewMetrics(); + + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 450, 500); + }); + + test('top toolboxes with autoclosing flyouts only have a toolbox offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); + this.svgMetricsStub.returns({width: 500, height: 500}); + this.getToolboxStub.returns(true); + this.getFlyoutStub.returns({autoClose: true}); + + const viewMetrics = this.metricsManager.getViewMetrics(); + + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 450); + }); + + test('left always open flyouts have a flyout offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); this.svgMetricsStub.returns({width: 500, height: 500}); this.getToolboxStub.returns(false); - this.getFlyoutStub.returns(true); + this.getFlyoutStub.returns({autoClose: false}); const viewMetrics = this.metricsManager.getViewMetrics(); - assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 393, 500); + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 400, 500); }); - test('Flyout at top', function () { - this.toolboxMetricsStub.returns({}); - this.flyoutMetricsStub.returns({width: 0, height: 107, position: 0}); + + test('top always open flyouts have a flyout offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); this.svgMetricsStub.returns({width: 500, height: 500}); this.getToolboxStub.returns(false); - this.getFlyoutStub.returns(true); + this.getFlyoutStub.returns({autoClose: false}); const viewMetrics = this.metricsManager.getViewMetrics(); - assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 393); + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 400); }); + + test('left autoclosing flyouts have no offset', function () { + this.toolboxMetricsStub.returns({width: 50, height: 0, position: 2}); + this.flyoutMetricsStub.returns({width: 100, height: 0, position: 2}); + this.svgMetricsStub.returns({width: 500, height: 500}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: true}); + + const viewMetrics = this.metricsManager.getViewMetrics(); + + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 500); + }); + + test('top autoclosing flyouts have no offset', function () { + this.toolboxMetricsStub.returns({width: 0, height: 50, position: 0}); + this.flyoutMetricsStub.returns({width: 0, height: 100, position: 0}); + this.svgMetricsStub.returns({width: 500, height: 500}); + this.getToolboxStub.returns(false); + this.getFlyoutStub.returns({autoClose: true}); + + const viewMetrics = this.metricsManager.getViewMetrics(); + + assertDimensionsMatch(viewMetrics, -SCROLL_X, -SCROLL_Y, 500, 500); + }); + test('Get view metrics in workspace coordinates ', function () { const scale = 2; const getWorkspaceCoordinates = true; diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js index fd622c26e..14acd21b6 100644 --- a/tests/mocha/trashcan_test.js +++ b/tests/mocha/trashcan_test.js @@ -121,14 +121,14 @@ suite('Trashcan', function () { }); }); test('Click outside trashcan - fires trashcanClose', function () { - sinon.stub(this.trashcan.flyout, 'isVisible').returns(true); - // Stub flyout interaction. - const hideFlyoutStub = sinon.stub(this.trashcan.flyout, 'hide'); + this.trashcan.flyout.setVisible(true); simulateClick(this.workspace.svgGroup_); - sinon.assert.calledOnce(hideFlyoutStub); - + chai.assert.isFalse( + this.trashcan.flyout.isVisible(), + 'Expected flyout to be hidden', + ); assertEventFired( this.eventsFireStub, Blockly.Events.TrashcanOpen, From 02cd1c6a1be1e5040ec712c0418373405eadfa5a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 8 Nov 2023 23:25:45 +0000 Subject: [PATCH 52/86] fix: blocks being dragged behind toolbox (#7619) * fix: add layer manager to fix dragging * chore: fix block animations * chore: add tests * chore: format --- core/block_dragger.ts | 5 + core/block_svg.ts | 8 +- core/bubble_dragger.ts | 6 + core/css.ts | 11 ++ core/inject.ts | 13 ++- core/interfaces/i_rendered_element.ts | 22 ++++ core/layer_manager.ts | 154 ++++++++++++++++++++++++++ core/layers.ts | 19 ++++ core/workspace_comment_svg.ts | 19 ++-- core/workspace_svg.ts | 65 ++++++----- tests/mocha/index.html | 1 + tests/mocha/layering_test.js | 94 ++++++++++++++++ tests/mocha/theme_test.js | 2 +- tests/mocha/workspace_comment_test.js | 13 --- 14 files changed, 376 insertions(+), 56 deletions(-) create mode 100644 core/interfaces/i_rendered_element.ts create mode 100644 core/layer_manager.ts create mode 100644 core/layers.ts create mode 100644 tests/mocha/layering_test.js diff --git a/core/block_dragger.ts b/core/block_dragger.ts index cd9a1e48d..78c1381ae 100644 --- a/core/block_dragger.ts +++ b/core/block_dragger.ts @@ -30,6 +30,7 @@ import * as dom from './utils/dom.js'; import type {WorkspaceSvg} from './workspace_svg.js'; import {hasBubble} from './interfaces/i_has_bubble.js'; import * as deprecation from './utils/deprecation.js'; +import * as layers from './layers.js'; /** * Class for a block dragger. It moves blocks around the workspace when they @@ -119,6 +120,7 @@ export class BlockDragger implements IBlockDragger { this.disconnectBlock_(healStack, currentDragDeltaXY); } this.draggingBlock_.setDragging(true); + this.workspace_.getLayerManager()?.moveToDragLayer(this.draggingBlock_); } /** @@ -231,6 +233,9 @@ export class BlockDragger implements IBlockDragger { const deleted = this.maybeDeleteBlock_(); if (!deleted) { // These are expensive and don't need to be done if we're deleting. + this.workspace_ + .getLayerManager() + ?.moveOffDragLayer(this.draggingBlock_, layers.BLOCK); this.draggingBlock_.setDragging(false); if (delta) { // !preventMove diff --git a/core/block_svg.ts b/core/block_svg.ts index caaf89db1..5ead73340 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -354,6 +354,12 @@ export class BlockSvg * @returns Object with .x and .y properties in workspace coordinates. */ override getRelativeToSurfaceXY(): Coordinate { + const layerManger = this.workspace.getLayerManager(); + if (!layerManger) { + throw new Error( + 'Cannot calculate position because the workspace has not been appended', + ); + } let x = 0; let y = 0; @@ -365,7 +371,7 @@ export class BlockSvg x += xy.x; y += xy.y; element = element.parentNode as SVGElement; - } while (element && element !== this.workspace.getCanvas()); + } while (element && !layerManger.hasLayer(element)); } return new Coordinate(x, y); } diff --git a/core/bubble_dragger.ts b/core/bubble_dragger.ts index 47d03f6cc..e494c7ad2 100644 --- a/core/bubble_dragger.ts +++ b/core/bubble_dragger.ts @@ -20,6 +20,7 @@ import type {IDragTarget} from './interfaces/i_drag_target.js'; import {Coordinate} from './utils/coordinate.js'; import {WorkspaceCommentSvg} from './workspace_comment_svg.js'; import type {WorkspaceSvg} from './workspace_svg.js'; +import * as layers from './layers.js'; /** * Class for a bubble dragger. It moves things on the bubble canvas around the @@ -64,6 +65,8 @@ export class BubbleDragger { (this.bubble as AnyDuringMigration).setAutoLayout(false); } + this.workspace.getLayerManager()?.moveToDragLayer(this.bubble); + this.bubble.setDragging && this.bubble.setDragging(true); } @@ -163,6 +166,9 @@ export class BubbleDragger { // Put everything back onto the bubble canvas. if (this.bubble.setDragging) { this.bubble.setDragging(false); + this.workspace + .getLayerManager() + ?.moveOffDragLayer(this.bubble, layers.BUBBLE); } this.fireMoveEvent_(); } diff --git a/core/css.ts b/core/css.ts index 5d52ea1a5..07e9c98a4 100644 --- a/core/css.ts +++ b/core/css.ts @@ -496,4 +496,15 @@ input[type=number] { float: right; margin-right: -24px; } + +.blocklyBlockDragSurface { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: visible !important; + z-index: 80; + pointer-events: none; +} `; diff --git a/core/inject.ts b/core/inject.ts index 78c80e1a7..b938abaa4 100644 --- a/core/inject.ts +++ b/core/inject.ts @@ -60,7 +60,7 @@ export function inject( containerElement!.appendChild(subContainer); const svg = createDom(subContainer, options); - const workspace = createMainWorkspace(svg, options); + const workspace = createMainWorkspace(subContainer, svg, options); init(workspace); @@ -138,15 +138,20 @@ function createDom(container: Element, options: Options): SVGElement { * @param options Dictionary of options. * @returns Newly created main workspace. */ -function createMainWorkspace(svg: SVGElement, options: Options): WorkspaceSvg { +function createMainWorkspace( + injectionDiv: Element, + svg: SVGElement, + options: Options, +): WorkspaceSvg { options.parentWorkspace = null; const mainWorkspace = new WorkspaceSvg(options); const wsOptions = mainWorkspace.options; mainWorkspace.scale = wsOptions.zoomOptions.startScale; - svg.appendChild(mainWorkspace.createDom('blocklyMainBackground')); + svg.appendChild( + mainWorkspace.createDom('blocklyMainBackground', injectionDiv), + ); // Set the theme name and renderer name onto the injection div. - const injectionDiv = mainWorkspace.getInjectionDiv(); const rendererClassName = mainWorkspace.getRenderer().getClassName(); if (rendererClassName) { dom.addClass(injectionDiv, rendererClassName); diff --git a/core/interfaces/i_rendered_element.ts b/core/interfaces/i_rendered_element.ts new file mode 100644 index 000000000..7e6981ca6 --- /dev/null +++ b/core/interfaces/i_rendered_element.ts @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @internal */ +export interface IRenderedElement { + /** + * @returns The root SVG element of htis rendered element. + */ + getSvgRoot(): SVGElement; +} + +/** + * @returns True if the given object is an IRenderedElement. + * + * @internal + */ +export function isRenderedElement(obj: any): obj is IRenderedElement { + return obj['getSvgRoot'] !== undefined; +} diff --git a/core/layer_manager.ts b/core/layer_manager.ts new file mode 100644 index 000000000..c27339d9b --- /dev/null +++ b/core/layer_manager.ts @@ -0,0 +1,154 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {WorkspaceSvg} from './workspace_svg.js'; +import * as dom from './utils/dom.js'; +import {Svg} from './utils/svg.js'; +import {IRenderedElement} from './interfaces/i_rendered_element.js'; +import * as layerNums from './layers.js'; +import {Coordinate} from './utils/coordinate.js'; + +/** @internal */ +export class LayerManager { + /** The layer elements being dragged are appended to. */ + private dragLayer: SVGGElement | undefined; + /** The layers elements not being dragged are appended to. */ + private layers = new Map(); + + /** @internal */ + constructor(private workspace: WorkspaceSvg) { + const injectionDiv = workspace.getInjectionDiv(); + // `getInjectionDiv` is actually nullable. We hit this if the workspace + // is part of a flyout and the workspace the flyout is attached to hasn't + // been appended yet. + if (injectionDiv) { + this.dragLayer = this.createDragLayer(injectionDiv); + } + + // We construct these manually so we can add the css class for backwards + // compatibility. + const blockLayer = this.createLayer(layerNums.BLOCK); + dom.addClass(blockLayer, 'blocklyBlockCanvas'); + const bubbleLayer = this.createLayer(layerNums.BUBBLE); + dom.addClass(bubbleLayer, 'blocklyBubbleCanvas'); + } + + private createDragLayer(injectionDiv: Element) { + const svg = dom.createSvgElement(Svg.SVG, { + 'class': 'blocklyBlockDragSurface', + 'xmlns': dom.SVG_NS, + 'xmlns:html': dom.HTML_NS, + 'xmlns:xlink': dom.XLINK_NS, + 'version': '1.1', + }); + injectionDiv.append(svg); + return dom.createSvgElement(Svg.G, {}, svg); + } + + /** + * Translates layers when the workspace is dragged or zoomed. + * + * @internal + */ + translateLayers(newCoord: Coordinate, newScale: number) { + const translation = `translate(${newCoord.x}, ${newCoord.y}) scale(${newScale})`; + this.dragLayer?.setAttribute('transform', translation); + for (const [_, layer] of this.layers) { + layer.setAttribute('transform', translation); + } + } + + /** + * Moves the given element to the drag layer, which exists on top of all other + * layers, and the drag surface. + * + * @internal + */ + moveToDragLayer(elem: IRenderedElement) { + this.dragLayer?.appendChild(elem.getSvgRoot()); + } + + /** + * Moves the given element off of the drag layer. + * + * @internal + */ + moveOffDragLayer(elem: IRenderedElement, layerNum: number) { + this.append(elem, layerNum); + } + + /** + * Appends the given element to a layer. If the layer does not exist, it is + * created. + * + * @internal + */ + append(elem: IRenderedElement, layerNum: number) { + if (!this.layers.has(layerNum)) { + this.createLayer(layerNum); + } + this.layers.get(layerNum)?.appendChild(elem.getSvgRoot()); + } + + /** + * Creates a layer and inserts it at the proper place given the layer number. + * + * More positive layers exist later in the dom and are rendered ontop of + * less positive layers. Layers are added to the layer map as a side effect. + */ + private createLayer(layerNum: number): SVGGElement { + const parent = this.workspace.getSvgGroup(); + const layer = dom.createSvgElement(Svg.G, {}); + + let inserted = false; + const sortedLayers = [...this.layers].sort((a, b) => a[0] - b[0]); + for (const [num, sib] of sortedLayers) { + if (layerNum < num) { + parent.insertBefore(layer, sib); + inserted = true; + break; + } + } + if (!inserted) { + parent.appendChild(layer); + } + this.layers.set(layerNum, layer); + return layer; + } + + /** + * Returns true if the given element is a layer managed by the layer manager. + * False otherwise. + * + * @internal + */ + hasLayer(elem: SVGElement) { + return ( + elem === this.dragLayer || + new Set(this.layers.values()).has(elem as SVGGElement) + ); + } + + /** + * We need to be able to access this layer explicitly for backwards + * compatibility. + * + * @internal + */ + getBlockLayer(): SVGGElement { + return this.layers.get(layerNums.BLOCK)!; + } + + /** + * We need to be able to access this layer explicitly for backwards + * compatibility. + * + * @internal + */ + getBubbleLayer(): SVGGElement { + return this.layers.get(layerNums.BUBBLE)!; + } +} diff --git a/core/layers.ts b/core/layers.ts new file mode 100644 index 000000000..60a30c8f6 --- /dev/null +++ b/core/layers.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * The layer to place blocks on. + * + * @internal + */ +export const BLOCK = 50; + +/** + * The layer to place bubbles on. + * + * @internal + */ +export const BUBBLE = 100; diff --git a/core/workspace_comment_svg.ts b/core/workspace_comment_svg.ts index 7d8e18e68..0aa4292c6 100644 --- a/core/workspace_comment_svg.ts +++ b/core/workspace_comment_svg.ts @@ -315,22 +315,25 @@ export class WorkspaceCommentSvg * @internal */ override getRelativeToSurfaceXY(): Coordinate { + const layerManger = this.workspace.getLayerManager(); + if (!layerManger) { + throw new Error( + 'Cannot calculate position because the workspace has not been appended', + ); + } + let x = 0; let y = 0; - let element: Node | null = this.getSvgRoot(); + let element: SVGElement | null = this.getSvgRoot(); if (element) { do { // Loop through this comment and every parent. - const xy = svgMath.getRelativeXY(element as Element); + const xy = svgMath.getRelativeXY(element); x += xy.x; y += xy.y; - element = element.parentNode; - } while ( - element && - element !== this.workspace.getBubbleCanvas() && - element !== null - ); + element = element.parentNode as SVGElement; + } while (element && !layerManger.hasLayer(element) && element !== null); } this.xy_ = new Coordinate(x, y); return this.xy_; diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 00ebcbdc1..1cfdbbc37 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -78,6 +78,7 @@ import {ZoomControls} from './zoom_controls.js'; import {ContextMenuOption} from './contextmenu_registry.js'; import * as renderManagement from './render_management.js'; import * as deprecation from './utils/deprecation.js'; +import {LayerManager} from './layer_manager.js'; /** Margin around the top/bottom/left/right after a zoomToFit call. */ const ZOOM_TO_FIT_MARGIN = 20; @@ -305,6 +306,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { private dragTargetAreas: Array<{component: IDragTarget; clientRect: Rect}> = []; private readonly cachedParentSvgSize: Size; + private layerManager: LayerManager | null = null; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. svgGroup_!: SVGElement; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -639,7 +641,11 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { x += xy.x * scale; y += xy.y * scale; element = element.parentNode as SVGElement; - } while (element && element !== this.getParentSvg()); + } while ( + element && + element !== this.getParentSvg() && + element !== this.getInjectionDiv() + ); return new Coordinate(x, y); } @@ -709,7 +715,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @internal */ getBlockCanvas(): SVGElement | null { - return this.svgBlockCanvas_; + return this.getCanvas(); } /** @@ -728,7 +734,11 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * 'blocklyMutatorBackground'. * @returns The workspace's SVG group. */ - createDom(opt_backgroundClass?: string): Element { + createDom(opt_backgroundClass?: string, injectionDiv?: Element): Element { + if (!this.injectionDiv) { + this.injectionDiv = injectionDiv ?? null; + } + /** * * @@ -760,16 +770,11 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { ); } } - this.svgBlockCanvas_ = dom.createSvgElement( - Svg.G, - {'class': 'blocklyBlockCanvas'}, - this.svgGroup_, - ); - this.svgBubbleCanvas_ = dom.createSvgElement( - Svg.G, - {'class': 'blocklyBubbleCanvas'}, - this.svgGroup_, - ); + + this.layerManager = new LayerManager(this); + // Assign the canvases for backwards compatibility. + this.svgBlockCanvas_ = this.layerManager.getBlockLayer(); + this.svgBubbleCanvas_ = this.layerManager.getBubbleLayer(); if (!this.isFlyout) { browserEvents.conditionalBind( @@ -901,7 +906,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { addTrashcan() { this.trashcan = WorkspaceSvg.newTrashcan(this); const svgTrashcan = this.trashcan.createDom(); - this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); + this.svgGroup_.insertBefore(svgTrashcan, this.getCanvas()); } /** @@ -1074,13 +1079,22 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { } /* eslint-enable indent */ + /** + * @returns The layer manager for this workspace. + * + * @internal + */ + getLayerManager(): LayerManager | null { + return this.layerManager; + } + /** * Get the SVG element that forms the drawing surface. * * @returns SVG group element. */ getCanvas(): SVGGElement { - return this.svgBlockCanvas_ as SVGGElement; + return this.layerManager!.getBlockLayer(); } /** @@ -1113,7 +1127,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @returns SVG group element. */ getBubbleCanvas(): SVGGElement { - return this.svgBubbleCanvas_ as SVGGElement; + return this.layerManager!.getBubbleLayer(); } /** @@ -1181,15 +1195,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * the Blockly div. */ translate(x: number, y: number) { - const translation = - 'translate(' + x + ',' + y + ') ' + 'scale(' + this.scale + ')'; - this.svgBlockCanvas_.setAttribute('transform', translation); - this.svgBubbleCanvas_.setAttribute('transform', translation); - // And update the grid if we're using one. - if (this.grid) { - this.grid.moveTo(x, y); - } - + this.layerManager?.translateLayers(new Coordinate(x, y), this.scale); + this.grid?.moveTo(x, y); this.maybeFireViewportChangeEvent(); } @@ -2023,8 +2030,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @internal */ beginCanvasTransition() { - dom.addClass(this.svgBlockCanvas_, 'blocklyCanvasTransitioning'); - dom.addClass(this.svgBubbleCanvas_, 'blocklyCanvasTransitioning'); + dom.addClass(this.getCanvas(), 'blocklyCanvasTransitioning'); + dom.addClass(this.getBubbleCanvas(), 'blocklyCanvasTransitioning'); } /** @@ -2033,8 +2040,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @internal */ endCanvasTransition() { - dom.removeClass(this.svgBlockCanvas_, 'blocklyCanvasTransitioning'); - dom.removeClass(this.svgBubbleCanvas_, 'blocklyCanvasTransitioning'); + dom.removeClass(this.getCanvas(), 'blocklyCanvasTransitioning'); + dom.removeClass(this.getBubbleCanvas(), 'blocklyCanvasTransitioning'); } /** Center the workspace. */ diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 1804a7504..6c4e5ad0c 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -100,6 +100,7 @@ import './jso_serialization_test.js'; import './json_test.js'; import './keydown_test.js'; + import './layering_test.js'; import './blocks/lists_test.js'; import './blocks/logic_ternary_test.js'; import './metrics_test.js'; diff --git a/tests/mocha/layering_test.js b/tests/mocha/layering_test.js new file mode 100644 index 000000000..a25f89374 --- /dev/null +++ b/tests/mocha/layering_test.js @@ -0,0 +1,94 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +import { + sharedTestSetup, + sharedTestTeardown, +} from './test_helpers/setup_teardown.js'; + +suite('Layering', function () { + setup(function () { + sharedTestSetup.call(this); + this.workspace = Blockly.inject('blocklyDiv', {}); + this.layerManager = this.workspace.getLayerManager(); + }); + + teardown(function () { + sharedTestTeardown.call(this); + }); + + function createRenderedElement() { + const g = Blockly.utils.dom.createSvgElement('g', {}); + return { + getSvgRoot: () => g, + }; + } + + suite('appending layers', function () { + test('layer is not appended if it already exists', function () { + const elem1 = createRenderedElement(); + const elem2 = createRenderedElement(); + this.layerManager.append(elem1, 999); + + const layerCount = this.layerManager.layers.size; + this.layerManager.append(elem2, 999); + + chai.assert.equal( + this.layerManager.layers.size, + layerCount, + 'Expected the element to be appended to the existing layer', + ); + }); + + test('more positive layers are appended after less positive layers', function () { + // Checks that if the element comes after all elements, its still gets + // appended. + + const elem1 = createRenderedElement(); + const elem2 = createRenderedElement(); + + this.layerManager.append(elem1, 1000); + this.layerManager.append(elem2, 1010); + + const layer1000 = this.layerManager.layers.get(1000); + const layer1010 = this.layerManager.layers.get(1010); + chai.assert.equal( + layer1000.nextSibling, + layer1010, + 'Expected layer 1000 to be direclty before layer 1010', + ); + }); + + test('less positive layers are appended before more positive layers', function () { + const elem1 = createRenderedElement(); + const elem2 = createRenderedElement(); + + this.layerManager.append(elem1, 1010); + this.layerManager.append(elem2, 1000); + + const layer1010 = this.layerManager.layers.get(1010); + const layer1000 = this.layerManager.layers.get(1000); + chai.assert.equal( + layer1000.nextSibling, + layer1010, + 'Expected layer 1000 to be direclty before layer 1010', + ); + }); + }); + + suite('dragging', function () { + test('moving an element to the drag layer adds it to the drag group', function () { + const elem = createRenderedElement(); + + this.layerManager.moveToDragLayer(elem); + + chai.assert.equal( + this.layerManager.dragLayer.firstChild, + elem.getSvgRoot(), + 'Expected the element to be the first element in the drag layer.', + ); + }); + }); +}); diff --git a/tests/mocha/theme_test.js b/tests/mocha/theme_test.js index bd9091a37..6fab65bcc 100644 --- a/tests/mocha/theme_test.js +++ b/tests/mocha/theme_test.js @@ -126,7 +126,7 @@ suite('Theme', function () { try { const blockStyles = createBlockStyles(); const theme = new Blockly.Theme('themeName', blockStyles); - workspace = new Blockly.WorkspaceSvg(new Blockly.Options({})); + workspace = Blockly.inject('blocklyDiv', {}); const blockA = workspace.newBlock('stack_block'); blockA.setStyle = function () { diff --git a/tests/mocha/workspace_comment_test.js b/tests/mocha/workspace_comment_test.js index a1b0e38b5..f2126dea2 100644 --- a/tests/mocha/workspace_comment_test.js +++ b/tests/mocha/workspace_comment_test.js @@ -163,19 +163,6 @@ suite('Workspace comment', function () { // Nothing should go wrong the second time dispose is called. comment.dispose(); }); - - test('WorkspaceCommentSvg disposed', function () { - const comment = new Blockly.WorkspaceCommentSvg( - this.workspace, - 'comment text', - 0, - 0, - 'comment id', - ); - comment.dispose(); - // Nothing should go wrong the second time dispose is called. - comment.dispose(); - }); }); suite('Width and height', function () { From a2b895f7a9083d345f6ae54efeff0e230d6a0cae Mon Sep 17 00:00:00 2001 From: Cassidy <62119269+systemc12ashe@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:28:51 -0500 Subject: [PATCH 53/86] fix: update setShadow TSDoc for Block and BlockSvg (#7639) * fix: update setShadow TSDoc for Block and BlockSvg * fix: Wrap comment lines at col 80 * fix: Corrected formatting with Prettier --- core/block.ts | 2 ++ core/block_svg.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/block.ts b/core/block.ts index d57043e55..8f64b20a2 100644 --- a/core/block.ts +++ b/core/block.ts @@ -865,6 +865,8 @@ export class Block implements IASTNodeLocation, IDeletable { /** * Set whether this block is a shadow block or not. + * This method is internal and should not be called by users of Blockly. To + * create shadow blocks programmatically call connection.setShadowState * * @param shadow True if a shadow. * @internal diff --git a/core/block_svg.ts b/core/block_svg.ts index 5ead73340..2ec157fa8 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -755,6 +755,8 @@ export class BlockSvg /** * Sets whether this block is a shadow block or not. + * This method is internal and should not be called by users of Blockly. To + * create shadow blocks programmatically call connection.setShadowState * * @param shadow True if a shadow. * @internal From b418907e41916ac9fb14726b513631381c22ff7d Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Sat, 11 Nov 2023 18:03:35 +0000 Subject: [PATCH 54/86] refactor(generators): Migrate Python generators to TypeScript #7602 (#7617) * refactor(generators): Migrate python_generator.js to TypeScript * refactor(generators): Migrate generators/python/* to TypeScript First pass doing very mechanistic migration, not attempting to fix all the resulting type errors. * fix(generators): Fix type errors in generator functions This consists almost entirely of adding casts, so the code output by tsc should be as similar as possible to the pre-migration .js source files. * refactor(generators): Migrate generators/python.js to TypeScript The way the generator functions are added to pythonGenerator.forBlock has been modified so that incorrect generator function signatures will cause tsc to generate a type error. * chore(generator): Format One block protected with // prettier-ignore to preserve careful comment formatting. Where there are repeated concatenations prettier has made a pretty mess of things, but the correct fix is probably to use template literals instead (rather than just locally disabling prettier). This is one of the items in the to-do list in #7600. --- generators/{python.js => python.ts} | 20 +- generators/python/{colour.js => colour.ts} | 60 ++-- generators/python/{lists.js => lists.ts} | 158 +++++++---- generators/python/{logic.js => logic.ts} | 109 +++++--- generators/python/{loops.js => loops.ts} | 129 ++++++--- generators/python/{math.js => math.ts} | 262 +++++++++++------- .../python/{procedures.js => procedures.ts} | 85 +++--- ...ython_generator.js => python_generator.ts} | 257 +++++++++-------- generators/python/{text.js => text.ts} | 200 ++++++++----- generators/python/variables.js | 30 -- generators/python/variables.ts | 31 +++ ...iables_dynamic.js => variables_dynamic.ts} | 1 - 12 files changed, 821 insertions(+), 521 deletions(-) rename generators/{python.js => python.ts} (79%) rename generators/python/{colour.js => colour.ts} (58%) rename generators/python/{lists.js => lists.ts} (75%) rename generators/python/{logic.js => logic.ts} (50%) rename generators/python/{loops.js => loops.ts} (68%) rename generators/python/{math.js => math.ts} (62%) rename generators/python/{procedures.js => procedures.ts} (64%) rename generators/python/{python_generator.js => python_generator.ts} (50%) rename generators/python/{text.js => text.ts} (63%) delete mode 100644 generators/python/variables.js create mode 100644 generators/python/variables.ts rename generators/python/{variables_dynamic.js => variables_dynamic.ts} (99%) diff --git a/generators/python.js b/generators/python.ts similarity index 79% rename from generators/python.js rename to generators/python.ts index 938da3b7e..e2345a776 100644 --- a/generators/python.js +++ b/generators/python.ts @@ -36,8 +36,18 @@ export const pythonGenerator = new PythonGenerator(); pythonGenerator.addReservedWords('math,random,Number'); // Install per-block-type generator functions: -Object.assign( - pythonGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +// Install per-block-type generator functions: +const generators: typeof pythonGenerator.forBlock = { + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, +}; +for (const name in generators) { + pythonGenerator.forBlock[name] = generators[name]; +} diff --git a/generators/python/colour.js b/generators/python/colour.ts similarity index 58% rename from generators/python/colour.js rename to generators/python/colour.ts index 36cb13c97..82f9dd37b 100644 --- a/generators/python/colour.js +++ b/generators/python/colour.ts @@ -10,41 +10,62 @@ // Former goog.module ID: Blockly.Python.colour +import type {Block} from '../../core/block.js'; +import type {PythonGenerator} from './python_generator.js'; import {Order} from './python_generator.js'; - -export function colour_picker(block, generator) { +export function colour_picker( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block, generator) { +export function colour_random( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Generate a random colour. - generator.definitions_['import_random'] = 'import random'; - const code = '\'#%06x\' % random.randint(0, 2**24 - 1)'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; + const code = "'#%06x' % random.randint(0, 2**24 - 1)"; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_rgb(block, generator) { +export function colour_rgb( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. - const functionName = generator.provideFunction_('colour_rgb', ` + const functionName = generator.provideFunction_( + 'colour_rgb', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b): r = round(min(100, max(0, r)) * 2.55) g = round(min(100, max(0, g)) * 2.55) b = round(min(100, max(0, b)) * 2.55) return '#%02x%02x%02x' % (r, g, b) -`); +`, + ); const r = generator.valueToCode(block, 'RED', Order.NONE) || 0; const g = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; const b = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; const code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_blend(block, generator) { +export function colour_blend( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Blend two colours together. - const functionName = generator.provideFunction_('colour_blend', ` + const functionName = generator.provideFunction_( + 'colour_blend', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16) g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16) @@ -54,15 +75,14 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): g = round(g1 * (1 - ratio) + g2 * ratio) b = round(b1 * (1 - ratio) + b2 * ratio) return '#%02x%02x%02x' % (r, g, b) -`); +`, + ); const colour1 = - generator.valueToCode(block, 'COLOUR1', Order.NONE) - || '\'#000000\''; + generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; const colour2 = - generator.valueToCode(block, 'COLOUR2', Order.NONE) - || '\'#000000\''; + generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0; const code = - functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; + functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/python/lists.js b/generators/python/lists.ts similarity index 75% rename from generators/python/lists.js rename to generators/python/lists.ts index 9f270b78e..02bd56ee5 100644 --- a/generators/python/lists.js +++ b/generators/python/lists.ts @@ -11,49 +11,69 @@ // Former goog.module ID: Blockly.Python.lists import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; import {NameType} from '../../core/names.js'; import {Order} from './python_generator.js'; +import type {PythonGenerator} from './python_generator.js'; - -export function lists_create_empty(block, generator) { +export function lists_create_empty( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Create an empty list. return ['[]', Order.ATOMIC]; -}; +} -export function lists_create_with(block, generator) { +export function lists_create_with( + block: Block, + generator: PythonGenerator, +): [string, Order] { + const createWithBlock = block as CreateWithBlock; // Create a list with any number of elements of any type. - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; -}; +} -export function lists_repeat(block, generator) { +export function lists_repeat( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Create a list with one element repeated. const item = generator.valueToCode(block, 'ITEM', Order.NONE) || 'None'; const times = - generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; const code = '[' + item + '] * ' + times; return [code, Order.MULTIPLICATIVE]; -}; +} -export function lists_length(block, generator) { +export function lists_length( + block: Block, + generator: PythonGenerator, +): [string, Order] { // String or array length. const list = generator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; return ['len(' + list + ')', Order.FUNCTION_CALL]; -}; +} -export function lists_isEmpty(block, generator) { +export function lists_isEmpty( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Is the string null or array empty? const list = generator.valueToCode(block, 'VALUE', Order.NONE) || '[]'; const code = 'not len(' + list + ')'; return [code, Order.LOGICAL_NOT]; -}; +} -export function lists_indexOf(block, generator) { +export function lists_indexOf( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Find an item in the list. const item = generator.valueToCode(block, 'FIND', Order.NONE) || '[]'; const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; @@ -69,31 +89,39 @@ export function lists_indexOf(block, generator) { let functionName; if (block.getFieldValue('END') === 'FIRST') { - functionName = generator.provideFunction_('first_index', ` + functionName = generator.provideFunction_( + 'first_index', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): try: index = my_list.index(elem)${firstIndexAdjustment} except: index =${errorIndex} return index -`); +`, + ); } else { - functionName = generator.provideFunction_('last_index', ` + functionName = generator.provideFunction_( + 'last_index', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem): try: index = len(my_list) - my_list[::-1].index(elem)${lastIndexAdjustment} except: index =${errorIndex} return index -`); +`, + ); } const code = functionName + '(' + list + ', ' + item + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_getIndex(block, generator) { +export function lists_getIndex( + block: Block, + generator: PythonGenerator, +): [string, Order] | string { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const listOrder = - (where === 'RANDOM') ? Order.NONE : Order.MEMBER; + const listOrder = where === 'RANDOM' ? Order.NONE : Order.MEMBER; const list = generator.valueToCode(block, 'VALUE', listOrder) || '[]'; switch (where) { @@ -146,17 +174,20 @@ export function lists_getIndex(block, generator) { break; } case 'RANDOM': - generator.definitions_['import_random'] = 'import random'; + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; if (mode === 'GET') { const code = 'random.choice(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else { - const functionName = - generator.provideFunction_('lists_remove_random_item', ` + const functionName = generator.provideFunction_( + 'lists_remove_random_item', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): x = int(random.random() * len(myList)) return myList.pop(x) -`); +`, + ); const code = functionName + '(' + list + ')'; if (mode === 'GET_REMOVE') { return [code, Order.FUNCTION_CALL]; @@ -167,9 +198,9 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): break; } throw Error('Unhandled combination (lists_getIndex).'); -}; +} -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: PythonGenerator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. let list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; @@ -182,8 +213,10 @@ export function lists_setIndex(block, generator) { if (list.match(/^\w+$/)) { return ''; } - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); const code = listVar + ' = ' + list + '\n'; list = listVar; return code; @@ -223,10 +256,13 @@ export function lists_setIndex(block, generator) { break; } case 'RANDOM': { - generator.definitions_['import_random'] = 'import random'; + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; let code = cacheList(); - const xVar = - generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); code += xVar + ' = int(random.random() * len(' + list + '))\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + '\n'; @@ -239,9 +275,12 @@ export function lists_setIndex(block, generator) { } } throw Error('Unhandled combination (lists_setIndex).'); -}; +} -export function lists_getSublist(block, generator) { +export function lists_getSublist( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1'); @@ -274,7 +313,8 @@ export function lists_getSublist(block, generator) { // Ensure that if the result calculated is 0 that sub-sequence will // include all elements as expected. if (!stringUtils.isNumber(String(at2))) { - generator.definitions_['import_sys'] = 'import sys'; + (generator as AnyDuringMigration).definitions_['import_sys'] = + 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -288,14 +328,19 @@ export function lists_getSublist(block, generator) { } const code = list + '[' + at1 + ' : ' + at2 + ']'; return [code, Order.MEMBER]; -}; +} -export function lists_sort(block, generator) { +export function lists_sort( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Block for sorting a list. - const list = (generator.valueToCode(block, 'LIST', Order.NONE) || '[]'); + const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const type = block.getFieldValue('TYPE'); const reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True'; - const sortFunctionName = generator.provideFunction_('lists_sort', ` + const sortFunctionName = generator.provideFunction_( + 'lists_sort', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse): def try_float(s): try: @@ -310,37 +355,44 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse): key_func = key_funcs[type] list_cpy = list(my_list) return sorted(list_cpy, key=key_func, reverse=reverse) -`); +`, + ); const code = - sortFunctionName + '(' + list + ', "' + type + '", ' + reverse + ')'; + sortFunctionName + '(' + list + ', "' + type + '", ' + reverse + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_split(block, generator) { +export function lists_split( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. const mode = block.getFieldValue('MODE'); let code; if (mode === 'SPLIT') { const value_input = - generator.valueToCode(block, 'INPUT', Order.MEMBER) || "''"; + generator.valueToCode(block, 'INPUT', Order.MEMBER) || "''"; const value_delim = generator.valueToCode(block, 'DELIM', Order.NONE); code = value_input + '.split(' + value_delim + ')'; } else if (mode === 'JOIN') { const value_input = - generator.valueToCode(block, 'INPUT', Order.NONE) || '[]'; + generator.valueToCode(block, 'INPUT', Order.NONE) || '[]'; const value_delim = - generator.valueToCode(block, 'DELIM', Order.MEMBER) || "''"; + generator.valueToCode(block, 'DELIM', Order.MEMBER) || "''"; code = value_delim + '.join(' + value_input + ')'; } else { throw Error('Unknown mode: ' + mode); } return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_reverse(block, generator) { +export function lists_reverse( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'list(reversed(' + list + '))'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/python/logic.js b/generators/python/logic.ts similarity index 50% rename from generators/python/logic.js rename to generators/python/logic.ts index 33729b860..e562c6794 100644 --- a/generators/python/logic.js +++ b/generators/python/logic.ts @@ -10,69 +10,80 @@ // Former goog.module ID: Blockly.Python.logic +import type {Block} from '../../core/block.js'; +import type {PythonGenerator} from './python_generator.js'; import {Order} from './python_generator.js'; - -export function controls_if(block, generator) { +export function controls_if(block: Block, generator: PythonGenerator) { // If/elseif/else condition. let n = 0; - let code = '', branchCode, conditionCode; + let code = '', + branchCode, + conditionCode; if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || 'False'; - branchCode = - generator.statementToCode(block, 'DO' + n) || - generator.PASS; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'False'; + branchCode = generator.statementToCode(block, 'DO' + n) || generator.PASS; if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += (n === 0 ? 'if ' : 'elif ') + conditionCode + ':\n' + branchCode; n++; } while (block.getInput('IF' + n)); if (block.getInput('ELSE') || generator.STATEMENT_SUFFIX) { - branchCode = - generator.statementToCode(block, 'ELSE') || generator.PASS; + branchCode = generator.statementToCode(block, 'ELSE') || generator.PASS; if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += 'else:\n' + branchCode; } return code; -}; +} export const controls_ifelse = controls_if; -export function logic_compare(block, generator) { +export function logic_compare( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; + const OPERATORS = { + 'EQ': '==', + 'NEQ': '!=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const order = Order.RELATIONAL; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_operation(block, generator) { +export function logic_operation( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or'; - const order = - (operator === 'and') ? Order.LOGICAL_AND : Order.LOGICAL_OR; + const operator = block.getFieldValue('OP') === 'AND' ? 'and' : 'or'; + const order = operator === 'and' ? Order.LOGICAL_AND : Order.LOGICAL_OR; let argument0 = generator.valueToCode(block, 'A', order); let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { @@ -81,7 +92,7 @@ export function logic_operation(block, generator) { argument1 = 'False'; } else { // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === 'and') ? 'True' : 'False'; + const defaultArgument = operator === 'and' ? 'True' : 'False'; if (!argument0) { argument0 = defaultArgument; } @@ -91,35 +102,47 @@ export function logic_operation(block, generator) { } const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_negate(block, generator) { +export function logic_negate( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Negation. const argument0 = - generator.valueToCode(block, 'BOOL', Order.LOGICAL_NOT) || 'True'; + generator.valueToCode(block, 'BOOL', Order.LOGICAL_NOT) || 'True'; const code = 'not ' + argument0; return [code, Order.LOGICAL_NOT]; -}; +} -export function logic_boolean(block, generator) { +export function logic_boolean( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'True' : 'False'; + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'True' : 'False'; return [code, Order.ATOMIC]; -}; +} -export function logic_null(block, generator) { +export function logic_null( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Null data type. return ['None', Order.ATOMIC]; -}; +} -export function logic_ternary(block, generator) { +export function logic_ternary( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Ternary operator. const value_if = - generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'False'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'False'; const value_then = - generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'None'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'None'; const value_else = - generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'None'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'None'; const code = value_then + ' if ' + value_if + ' else ' + value_else; return [code, Order.CONDITIONAL]; -}; +} diff --git a/generators/python/loops.js b/generators/python/loops.ts similarity index 68% rename from generators/python/loops.js rename to generators/python/loops.ts index 824d4f2bf..1d2d3a86e 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.ts @@ -11,11 +11,13 @@ // Former goog.module ID: Blockly.Python.loops import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; +import type {PythonGenerator} from './python_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './python_generator.js'; - -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext(block: Block, generator: PythonGenerator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -32,36 +34,42 @@ export function controls_repeat_ext(block, generator) { } let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block) || generator.PASS; - const loopVar = - generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); const code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; -}; +} export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil(block: Block, generator: PythonGenerator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; - let argument0 = generator.valueToCode( - block, 'BOOL', - until ? Order.LOGICAL_NOT : Order.NONE) || - 'False'; + let argument0 = + generator.valueToCode( + block, + 'BOOL', + until ? Order.LOGICAL_NOT : Order.NONE, + ) || 'False'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block) || generator.PASS; if (until) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ':\n' + branch; -}; +} -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: PythonGenerator) { // For loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); - let argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; - let argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; - let increment = generator.valueToCode(block, 'BY', Order.NONE) || '1'; + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); + let argument0: string | number = + generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + let argument1: string | number = + generator.valueToCode(block, 'TO', Order.NONE) || '0'; + let increment: string | number = + generator.valueToCode(block, 'BY', Order.NONE) || '1'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block) || generator.PASS; @@ -69,31 +77,64 @@ export function controls_for(block, generator) { let range; // Helper functions. - const defineUpRange = function() { - return generator.provideFunction_('upRange', ` + const defineUpRange = function () { + return generator.provideFunction_( + 'upRange', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): while start <= stop: yield start start += abs(step) -`); +`, + ); }; - const defineDownRange = function() { - return generator.provideFunction_('downRange', ` + const defineDownRange = function () { + return generator.provideFunction_( + 'downRange', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): while start >= stop: yield start start -= abs(step) -`); +`, + ); }; // Arguments are legal generator code (numbers or strings returned by scrub()). - const generateUpDownRange = function(start, end, inc) { - return '(' + start + ' <= ' + end + ') and ' + defineUpRange() + '(' + - start + ', ' + end + ', ' + inc + ') or ' + defineDownRange() + '(' + - start + ', ' + end + ', ' + inc + ')'; + const generateUpDownRange = function ( + start: string, + end: string, + inc: string, + ) { + return ( + '(' + + start + + ' <= ' + + end + + ') and ' + + defineUpRange() + + '(' + + start + + ', ' + + end + + ', ' + + inc + + ') or ' + + defineDownRange() + + '(' + + start + + ', ' + + end + + ', ' + + inc + + ')' + ); }; - if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && - stringUtils.isNumber(increment)) { + if ( + stringUtils.isNumber(argument0) && + stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment) + ) { // All parameters are simple numbers. argument0 = Number(argument0); argument1 = Number(argument1); @@ -130,14 +171,16 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): } } else { // Cache non-trivial values to variables to prevent repeated look-ups. - const scrub = function(arg, suffix) { + const scrub = function (arg: string, suffix: string) { if (stringUtils.isNumber(arg)) { // Simple number. - arg = Number(arg); + arg = String(Number(arg)); } else if (!arg.match(/^\w+$/)) { // Not a variable, it's complicated. - const varName = generator.nameDB_.getDistinctName( - variable0 + suffix, NameType.VARIABLE); + const varName = generator.nameDB_!.getDistinctName( + variable0 + suffix, + NameType.VARIABLE, + ); code += varName + ' = ' + arg + '\n'; arg = varName; } @@ -161,21 +204,23 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step): } code += 'for ' + variable0 + ' in ' + range + ':\n' + branch; return code; -}; +} -export function controls_forEach(block, generator) { +export function controls_forEach(block: Block, generator: PythonGenerator) { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'LIST', Order.RELATIONAL) || '[]'; + generator.valueToCode(block, 'LIST', Order.RELATIONAL) || '[]'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block) || generator.PASS; const code = 'for ' + variable0 + ' in ' + argument0 + ':\n' + branch; return code; -}; +} -export function controls_flow_statements(block, generator) { +export function controls_flow_statements( + block: Block, + generator: PythonGenerator, +) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { @@ -188,7 +233,7 @@ export function controls_flow_statements(block, generator) { xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. @@ -203,4 +248,4 @@ export function controls_flow_statements(block, generator) { return xfix + 'continue\n'; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/python/math.js b/generators/python/math.ts similarity index 62% rename from generators/python/math.js rename to generators/python/math.ts index 0ba351187..d458b0e87 100644 --- a/generators/python/math.js +++ b/generators/python/math.ts @@ -10,38 +10,42 @@ // Former goog.module ID: Blockly.Python.math +import type {Block} from '../../core/block.js'; +import type {PythonGenerator} from './python_generator.js'; import {Order} from './python_generator.js'; - // If any new block imports any library, add that library name here. // RESERVED WORDS: 'math,random,Number' -export function math_number(block, generator) { +export function math_number( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Numeric value. - let code = Number(block.getFieldValue('NUM')); - let order; - if (code === Infinity) { - code = 'float("inf")'; - order = Order.FUNCTION_CALL; - } else if (code === -Infinity) { - code = '-float("inf")'; - order = Order.UNARY_SIGN; + let number = Number(block.getFieldValue('NUM')); + if (number === Infinity) { + return ['float("inf")', Order.FUNCTION_CALL]; + } else if (number === -Infinity) { + return ['-float("inf")', Order.UNARY_SIGN]; } else { - order = code < 0 ? Order.UNARY_SIGN : Order.ATOMIC; + return [String(number), number < 0 ? Order.UNARY_SIGN : Order.ATOMIC]; } - return [code, order]; -}; +} -export function math_arithmetic(block, generator) { +export function math_arithmetic( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITIVE], 'MINUS': [' - ', Order.ADDITIVE], 'MULTIPLY': [' * ', Order.MULTIPLICATIVE], 'DIVIDE': [' / ', Order.MULTIPLICATIVE], 'POWER': [' ** ', Order.EXPONENTIATION], }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; @@ -53,9 +57,12 @@ export function math_arithmetic(block, generator) { // guarantee identical results in all languages. To do otherwise would // require every operator to be wrapped in a function call. This would kill // legibility of the generated code. -}; +} -export function math_single(block, generator) { +export function math_single( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; @@ -65,10 +72,11 @@ export function math_single(block, generator) { code = generator.valueToCode(block, 'NUM', Order.UNARY_SIGN) || '0'; return ['-' + code, Order.UNARY_SIGN]; } - generator.definitions_['import_math'] = 'import math'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected (here and below). + (generator as AnyDuringMigration).definitions_['import_math'] = 'import math'; if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = - generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; + arg = generator.valueToCode(block, 'NUM', Order.MULTIPLICATIVE) || '0'; } else { arg = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; } @@ -131,50 +139,61 @@ export function math_single(block, generator) { throw Error('Unknown math operator: ' + operator); } return [code, Order.MULTIPLICATIVE]; -}; +} -export function math_constant(block, generator) { +export function math_constant( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['math.pi', Order.MEMBER], 'E': ['math.e', Order.MEMBER], 'GOLDEN_RATIO': ['(1 + math.sqrt(5)) / 2', Order.MULTIPLICATIVE], 'SQRT2': ['math.sqrt(2)', Order.MEMBER], 'SQRT1_2': ['math.sqrt(1.0 / 2)', Order.MEMBER], - 'INFINITY': ['float(\'inf\')', Order.ATOMIC], + 'INFINITY': ["float('inf')", Order.ATOMIC], }; - const constant = block.getFieldValue('CONSTANT'); + type ConstantOption = keyof typeof CONSTANTS; + const constant = block.getFieldValue('CONSTANT') as ConstantOption; if (constant !== 'INFINITY') { - generator.definitions_['import_math'] = 'import math'; + (generator as AnyDuringMigration).definitions_['import_math'] = + 'import math'; } return CONSTANTS[constant]; -}; +} -export function math_number_property(block, generator) { - // Check if a number is even, odd, prime, whole, positive, or negative - // or if it is divisible by certain number. Returns true or false. - const PROPERTIES = { +export function math_number_property( + block: Block, + generator: PythonGenerator, +): [string, Order] { + // Check if a number is even, odd, prime, whole, positive, or negative + // or if it is divisible by certain number. Returns true or false. + const PROPERTIES: Record = { 'EVEN': [' % 2 == 0', Order.MULTIPLICATIVE, Order.RELATIONAL], 'ODD': [' % 2 == 1', Order.MULTIPLICATIVE, Order.RELATIONAL], - 'WHOLE': [' % 1 == 0', Order.MULTIPLICATIVE, - Order.RELATIONAL], + 'WHOLE': [' % 1 == 0', Order.MULTIPLICATIVE, Order.RELATIONAL], 'POSITIVE': [' > 0', Order.RELATIONAL, Order.RELATIONAL], 'NEGATIVE': [' < 0', Order.RELATIONAL, Order.RELATIONAL], - 'DIVISIBLE_BY': [null, Order.MULTIPLICATIVE, - Order.RELATIONAL], + 'DIVISIBLE_BY': [null, Order.MULTIPLICATIVE, Order.RELATIONAL], 'PRIME': [null, Order.NONE, Order.FUNCTION_CALL], - } - const dropdownProperty = block.getFieldValue('PROPERTY'); + }; + type PropertyOption = keyof typeof PROPERTIES; + const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', - inputOrder) || '0'; + const numberToCheck = + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - generator.definitions_['import_math'] = 'import math'; - generator.definitions_['from_numbers_import_Number'] = - 'from numbers import Number'; - const functionName = generator.provideFunction_('math_isPrime', ` + (generator as AnyDuringMigration).definitions_['import_math'] = + 'import math'; + (generator as AnyDuringMigration).definitions_[ + 'from_numbers_import_Number' + ] = 'from numbers import Number'; + const functionName = generator.provideFunction_( + 'math_isPrime', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(n): # https://en.wikipedia.org/wiki/Primality_test#Naive_methods # If n is not a number but a string, try parsing it. @@ -193,11 +212,12 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(n): if n % (x - 1) == 0 or n % (x + 1) == 0: return False return True -`); - code = functionName + '(' + numberToCheck + ')'; +`, + ); + code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MULTIPLICATIVE) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; // If 'divisor' is some code that evals to 0, generator will raise an error. if (divisor === '0') { return ['False', Order.ATOMIC]; @@ -205,27 +225,38 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(n): code = numberToCheck + ' % ' + divisor + ' == 0'; } else { code = numberToCheck + suffix; - }; + } return [code, outputOrder]; -}; +} -export function math_change(block, generator) { +export function math_change(block: Block, generator: PythonGenerator) { // Add to a variable in place. - generator.definitions_['from_numbers_import_Number'] = - 'from numbers import Number'; + (generator as AnyDuringMigration).definitions_['from_numbers_import_Number'] = + 'from numbers import Number'; const argument0 = - generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; const varName = generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = (' + varName + ' if isinstance(' + varName + - ', Number) else 0) + ' + argument0 + '\n'; -}; + return ( + varName + + ' = (' + + varName + + ' if isinstance(' + + varName + + ', Number) else 0) + ' + + argument0 + + '\n' + ); +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; @@ -241,25 +272,32 @@ export function math_on_list(block, generator) { code = 'max(' + list + ')'; break; case 'AVERAGE': { - generator.definitions_['from_numbers_import_Number'] = - 'from numbers import Number'; + (generator as AnyDuringMigration).definitions_[ + 'from_numbers_import_Number' + ] = 'from numbers import Number'; // This operation excludes null and values that aren't int or float: // math_mean([null, null, "aString", 1, 9]) -> 5.0 - const functionName = generator.provideFunction_('math_mean', ` + const functionName = generator.provideFunction_( + 'math_mean', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): localList = [e for e in myList if isinstance(e, Number)] if not localList: return return float(sum(localList)) / len(localList) -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - generator.definitions_['from_numbers_import_Number'] = - 'from numbers import Number'; + (generator as AnyDuringMigration).definitions_[ + 'from_numbers_import_Number' + ] = 'from numbers import Number'; // This operation excludes null values: // math_median([null, null, 1, 3]) -> 2.0 - const functionName = generator.provideFunction_( 'math_median', ` + const functionName = generator.provideFunction_( + 'math_median', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): localList = sorted([e for e in myList if isinstance(e, Number)]) if not localList: return @@ -267,7 +305,8 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): return (localList[len(localList) // 2 - 1] + localList[len(localList) // 2]) / 2.0 else: return localList[(len(localList) - 1) // 2] -`); +`, + ); code = functionName + '(' + list + ')'; break; } @@ -275,7 +314,9 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(myList): // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1] - const functionName = generator.provideFunction_('math_modes', ` + const functionName = generator.provideFunction_( + 'math_modes', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(some_list): modes = [] # Using a lists of [item, count] to keep count rather than dict @@ -295,84 +336,99 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(some_list): if item_count == maxCount: modes.append(counted_item) return modes -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - generator.definitions_['import_math'] = 'import math'; - const functionName = - generator.provideFunction_('math_standard_deviation', ` + (generator as AnyDuringMigration).definitions_['import_math'] = + 'import math'; + const functionName = generator.provideFunction_( + 'math_standard_deviation', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(numbers): n = len(numbers) if n == 0: return mean = float(sum(numbers)) / n variance = sum((x - mean) ** 2 for x in numbers) / n return math.sqrt(variance) -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'RANDOM': - generator.definitions_['import_random'] = 'import random'; + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; code = 'random.choice(' + list + ')'; break; default: throw Error('Unknown operator: ' + func); } return [code, Order.FUNCTION_CALL]; -}; +} -export function math_modulo(block, generator) { +export function math_modulo( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Remainder computation. const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || - '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || - '0'; + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; -}; +} -export function math_constrain(block, generator) { +export function math_constrain( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Constrain a number between two limits. - const argument0 = - generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const argument1 = - generator.valueToCode(block, 'LOW', Order.NONE) || '0'; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - generator.valueToCode(block, 'HIGH', Order.NONE) || - 'float(\'inf\')'; + generator.valueToCode(block, 'HIGH', Order.NONE) || "float('inf')"; const code = - 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; + 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_int(block, generator) { +export function math_random_int( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Random integer between [X] and [Y]. - generator.definitions_['import_random'] = 'import random'; - const argument0 = - generator.valueToCode(block, 'FROM', Order.NONE) || '0'; - const argument1 = - generator.valueToCode(block, 'TO', Order.NONE) || '0'; + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; + const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; const code = 'random.randint(' + argument0 + ', ' + argument1 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_float(block, generator) { +export function math_random_float( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Random fraction between 0 and 1. - generator.definitions_['import_random'] = 'import random'; + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; return ['random.random()', Order.FUNCTION_CALL]; -}; +} -export function math_atan2(block, generator) { +export function math_atan2( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. - generator.definitions_['import_math'] = 'import math'; + (generator as AnyDuringMigration).definitions_['import_math'] = 'import math'; const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'math.atan2(' + argument1 + ', ' + argument0 + ') / math.pi * 180', - Order.MULTIPLICATIVE + Order.MULTIPLICATIVE, ]; -}; +} diff --git a/generators/python/procedures.js b/generators/python/procedures.ts similarity index 64% rename from generators/python/procedures.js rename to generators/python/procedures.ts index 4539ca296..ad45f2dfb 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.ts @@ -11,11 +11,13 @@ // Former goog.module ID: Blockly.Python.procedures import * as Variables from '../../core/variables.js'; +import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; import {NameType} from '../../core/names.js'; import {Order} from './python_generator.js'; +import type {PythonGenerator} from './python_generator.js'; - -export function procedures_defreturn(block, generator) { +export function procedures_defreturn(block: Block, generator: PythonGenerator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. @@ -33,15 +35,14 @@ export function procedures_defreturn(block, generator) { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - generator.nameDB_.getName( - devVarList[i], NameType.DEVELOPER_VARIABLE)); + generator.nameDB_!.getName(devVarList[i], NameType.DEVELOPER_VARIABLE), + ); } - const globalString = globals.length ? - generator.INDENT + 'global ' + globals.join(', ') + '\n' : - ''; - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const globalString = globals.length + ? generator.INDENT + 'global ' + globals.join(', ') + '\n' + : ''; + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); @@ -55,12 +56,12 @@ export function procedures_defreturn(block, generator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId(generator.INFINITE_LOOP_TRAP, block), - generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } let branch = generator.statementToCode(block, 'STACK'); - let returnValue = - generator.valueToCode(block, 'RETURN', Order.NONE) || ''; + let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. @@ -76,58 +77,74 @@ export function procedures_defreturn(block, generator) { for (let i = 0; i < variables.length; i++) { args[i] = generator.getVariableName(variables[i]); } - let code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + globalString + - xfix1 + loopTrap + branch + xfix2 + returnValue; + let code = + 'def ' + + funcName + + '(' + + args.join(', ') + + '):\n' + + globalString + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Call a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = - generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'None'; + args[i] = generator.valueToCode(block, 'ARG' + i, Order.NONE) || 'None'; } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn( + block: Block, + generator: PythonGenerator, +) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn'](block, generator)!; return tuple[0] + '\n'; -}; +} -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn(block: Block, generator: PythonGenerator) { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || 'False'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'False'; let code = 'if ' + condition + ':\n'; if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. code += generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), generator.INDENT); + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } - if (block.hasReturnValue_) { - const value = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'None'; + if ((block as IfReturnBlock).hasReturnValue_) { + const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'None'; code += generator.INDENT + 'return ' + value + '\n'; } else { code += generator.INDENT + 'return\n'; } return code; -}; +} diff --git a/generators/python/python_generator.js b/generators/python/python_generator.ts similarity index 50% rename from generators/python/python_generator.js rename to generators/python/python_generator.ts index 275caef46..5e5daf9f2 100644 --- a/generators/python/python_generator.js +++ b/generators/python/python_generator.ts @@ -5,49 +5,48 @@ */ /** - * @fileoverview Helper functions for generating Python for blocks. - * @suppress {checkTypes|globalThis} + * @file Python code generator class, including helper methods for + * generating Python for blocks. */ // Former goog.module ID: Blockly.Python import * as stringUtils from '../../core/utils/string.js'; import * as Variables from '../../core/variables.js'; -// import type {Block} from '../../core/block.js'; +import type {Block} from '../../core/block.js'; import {CodeGenerator} from '../../core/generator.js'; import {Names} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; +import type {Workspace} from '../../core/workspace.js'; import {inputTypes} from '../../core/inputs/input_types.js'; - /** * Order of operation ENUMs. * http://docs.python.org/reference/expressions.html#summary - * @enum {number} */ -export const Order = { - ATOMIC: 0, // 0 "" ... - COLLECTION: 1, // tuples, lists, dictionaries - STRING_CONVERSION: 1, // `expression...` - MEMBER: 2.1, // . [] - FUNCTION_CALL: 2.2, // () - EXPONENTIATION: 3, // ** - UNARY_SIGN: 4, // + - - BITWISE_NOT: 4, // ~ - MULTIPLICATIVE: 5, // * / // % - ADDITIVE: 6, // + - - BITWISE_SHIFT: 7, // << >> - BITWISE_AND: 8, // & - BITWISE_XOR: 9, // ^ - BITWISE_OR: 10, // | - RELATIONAL: 11, // in, not in, is, is not, >, >=, <>, !=, == - LOGICAL_NOT: 12, // not - LOGICAL_AND: 13, // and - LOGICAL_OR: 14, // or - CONDITIONAL: 15, // if else - LAMBDA: 16, // lambda - NONE: 99, // (...) -}; +// prettier-ignore +export enum Order { + ATOMIC = 0, // 0 "" ... + COLLECTION = 1, // tuples, lists, dictionaries + STRING_CONVERSION = 1, // `expression...` + MEMBER = 2.1, // . [] + FUNCTION_CALL = 2.2, // () + EXPONENTIATION = 3, // ** + UNARY_SIGN = 4, // + - + BITWISE_NOT = 4, // ~ + MULTIPLICATIVE = 5, // * / // % + ADDITIVE = 6, // + - + BITWISE_SHIFT = 7, // << >> + BITWISE_AND = 8, // & + BITWISE_XOR = 9, // ^ + BITWISE_OR = 10, // | + RELATIONAL = 11, // in, not in, is, is not, >, >=, <>, !=, == + LOGICAL_NOT = 12, // not + LOGICAL_AND = 13, // and + LOGICAL_OR = 14, // or + CONDITIONAL = 15, // if else + LAMBDA = 16, // lambda + NONE = 99, // (...) +} /** * PythonScript code generator class. @@ -55,9 +54,8 @@ export const Order = { export class PythonGenerator extends CodeGenerator { /** * List of outer-inner pairings that do NOT require parentheses. - * @type {!Array>} */ - ORDER_OVERRIDES = [ + ORDER_OVERRIDES: number[][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], @@ -77,11 +75,17 @@ export class PythonGenerator extends CodeGenerator { // a and (b and c) -> a and b and c [Order.LOGICAL_AND, Order.LOGICAL_AND], // a or (b or c) -> a or b or c - [Order.LOGICAL_OR, Order.LOGICAL_OR] + [Order.LOGICAL_OR, Order.LOGICAL_OR], ]; - constructor(name) { - super(name ?? 'Python'); + /** + * Empty loops or conditionals are not allowed in Python. + */ + PASS: string = ''; // Initialised by init(). + + /** @param name Name of the language the generator is for. */ + constructor(name = 'Python') { + super(name); this.isInitialized = false; // Copy Order values onto instance for backwards compatibility @@ -92,7 +96,16 @@ export class PythonGenerator extends CodeGenerator { // replace data properties with get accessors that call // deprecate.warn().) for (const key in Order) { - this['ORDER_' + key] = Order[key]; + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; } // List of illegal variable names. This is not intended to be a @@ -105,55 +118,52 @@ export class PythonGenerator extends CodeGenerator { // https://docs.python.org/3/reference/lexical_analysis.html#keywords // https://docs.python.org/2/reference/lexical_analysis.html#keywords 'False,None,True,and,as,assert,break,class,continue,def,del,elif,else,' + - 'except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,' + - 'not,or,pass,print,raise,return,try,while,with,yield,' + - // https://docs.python.org/3/library/constants.html - // https://docs.python.org/2/library/constants.html - 'NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,' + - // >>> print(','.join(sorted(dir(__builtins__)))) - // https://docs.python.org/3/library/functions.html - // https://docs.python.org/2/library/functions.html - 'ArithmeticError,AssertionError,AttributeError,BaseException,' + - 'BlockingIOError,BrokenPipeError,BufferError,BytesWarning,' + - 'ChildProcessError,ConnectionAbortedError,ConnectionError,' + - 'ConnectionRefusedError,ConnectionResetError,DeprecationWarning,' + - 'EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,' + - 'FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,' + - 'IOError,ImportError,ImportWarning,IndentationError,IndexError,' + - 'InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,' + - 'LookupError,MemoryError,ModuleNotFoundError,NameError,' + - 'NotADirectoryError,NotImplemented,NotImplementedError,OSError,' + - 'OverflowError,PendingDeprecationWarning,PermissionError,' + - 'ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,' + - 'RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,' + - 'StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,' + - 'TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,' + - 'UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,' + - 'UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,' + - '__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,' + - 'abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,' + - 'callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,' + - 'delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,' + - 'float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,' + - 'int,intern,isinstance,issubclass,iter,len,license,list,locals,long,' + - 'map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,' + - 'quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,' + - 'slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,' + - 'vars,xrange,zip' + 'except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,' + + 'not,or,pass,print,raise,return,try,while,with,yield,' + + // https://docs.python.org/3/library/constants.html + // https://docs.python.org/2/library/constants.html + 'NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,' + + // >>> print(','.join(sorted(dir(__builtins__)))) + // https://docs.python.org/3/library/functions.html + // https://docs.python.org/2/library/functions.html + 'ArithmeticError,AssertionError,AttributeError,BaseException,' + + 'BlockingIOError,BrokenPipeError,BufferError,BytesWarning,' + + 'ChildProcessError,ConnectionAbortedError,ConnectionError,' + + 'ConnectionRefusedError,ConnectionResetError,DeprecationWarning,' + + 'EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,' + + 'FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,' + + 'IOError,ImportError,ImportWarning,IndentationError,IndexError,' + + 'InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,' + + 'LookupError,MemoryError,ModuleNotFoundError,NameError,' + + 'NotADirectoryError,NotImplemented,NotImplementedError,OSError,' + + 'OverflowError,PendingDeprecationWarning,PermissionError,' + + 'ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,' + + 'RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,' + + 'StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,' + + 'TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,' + + 'UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,' + + 'UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,' + + '__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,' + + 'abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,' + + 'callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,' + + 'delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,' + + 'float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,' + + 'int,intern,isinstance,issubclass,iter,len,license,list,locals,long,' + + 'map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,' + + 'quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,' + + 'slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,' + + 'vars,xrange,zip', ); } /** * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. - * @this {CodeGenerator} + * + * @param workspace Workspace to generate code from. */ - init(workspace) { + init(workspace: Workspace) { super.init(workspace); - /** - * Empty loops or conditionals are not allowed in Python. - */ this.PASS = this.INDENT + 'pass\n'; if (!this.nameDB_) { @@ -171,16 +181,15 @@ export class PythonGenerator extends CodeGenerator { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { defvars.push( - this.nameDB_.getName(devVarList[i], Names.DEVELOPER_VARIABLE_TYPE) + - ' = None'); + this.nameDB_.getName(devVarList[i], Names.DEVELOPER_VARIABLE_TYPE) + + ' = None', + ); } // Add user variables, but only ones that are being used. const variables = Variables.allUsedVarModels(workspace); for (let i = 0; i < variables.length; i++) { - defvars.push( - this.getVariableName(variables[i].getId()) + - ' = None'); + defvars.push(this.getVariableName(variables[i].getId()) + ' = None'); } this.definitions_['variables'] = defvars.join('\n'); @@ -189,10 +198,11 @@ export class PythonGenerator extends CodeGenerator { /** * Prepend the generated code with import statements and variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. + * + * @param code Generated code. + * @returns Completed code. */ - finish(code) { + finish(code: string): string { // Convert the definitions dictionary into a list. const imports = []; const definitions = []; @@ -208,7 +218,7 @@ export class PythonGenerator extends CodeGenerator { code = super.finish(code); this.isInitialized = false; - this.nameDB_.reset(); + this.nameDB_!.reset(); const allDefs = imports.join('\n') + '\n\n' + definitions.join('\n\n'); return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code; } @@ -216,28 +226,30 @@ export class PythonGenerator extends CodeGenerator { /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. - * @param {string} line Line of generated code. - * @return {string} Legal line of code. + * + * @param line Line of generated code. + * @returns Legal line of code. */ - scrubNakedValue(line) { + scrubNakedValue(line: string): string { return line + '\n'; } /** * Encode a string as a properly escaped Python string, complete with quotes. - * @param {string} string Text to encode. - * @return {string} Python string. + * + * @param string Text to encode. + * @returns Python string. */ - quote_(string) { + quote_(string: string): string { string = string.replace(/\\/g, '\\\\').replace(/\n/g, '\\\n'); // Follow the CPython behaviour of repr() for a non-byte string. - let quote = '\''; - if (string.indexOf('\'') !== -1) { + let quote = "'"; + if (string.indexOf("'") !== -1) { if (string.indexOf('"') === -1) { quote = '"'; } else { - string = string.replace(/'/g, '\\\''); + string = string.replace(/'/g, "\\'"); } } return quote + string + quote; @@ -246,27 +258,29 @@ export class PythonGenerator extends CodeGenerator { /** * Encode a string as a properly escaped multiline Python string, complete * with quotes. - * @param {string} string Text to encode. - * @return {string} Python string. + * + * @param string Text to encode. + * @returns Python string. */ - multiline_quote_(string) { + multiline_quote_(string: string): string { const lines = string.split(/\n/g).map(this.quote_); // Join with the following, plus a newline: // + '\n' + - return lines.join(' + \'\\n\' + \n'); + return lines.join(" + '\\n' + \n"); } /** * Common tasks for generating Python from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The Python code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this statement. - * @return {string} Python code with comments and subsequent blocks added. - * @protected + * + * @param block The current block. + * @param code The Python code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns Python code with comments and subsequent blocks added. + */ - scrub_(block, code, opt_thisOnly) { + scrub_(block: Block, code: string, thisOnly = false): string { let commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { @@ -280,7 +294,7 @@ export class PythonGenerator extends CodeGenerator { // Don't collect comments for nested statements. for (let i = 0; i < block.inputList.length; i++) { if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); + const childBlock = block.inputList[i].connection!.targetBlock(); if (childBlock) { comment = this.allNestedComments(childBlock); if (comment) { @@ -290,33 +304,40 @@ export class PythonGenerator extends CodeGenerator { } } } - const nextBlock = block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); + const nextBlock = + block.nextConnection && block.nextConnection.targetBlock(); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); return commentCode + code + nextCode; } /** * Gets a property and adjusts the value, taking into account indexing. * If a static int, casts to an integer, otherwise returns a code string. - * @param {!Block} block The block. - * @param {string} atId The property ID of the element to get. - * @param {number=} opt_delta Value to add. - * @param {boolean=} opt_negate Whether to negate the value. - * @return {string|number} + * + * @param block The block. + * @param atId The ID of the input block to get (and adjust) the value of. + * @param delta Value to add. + * @param negate Whether to negate the value. + * @returns The adjusted value. */ - getAdjustedInt(block, atId, opt_delta, opt_negate) { - let delta = opt_delta || 0; + getAdjustedInt( + block: Block, + atId: string, + delta = 0, + negate = false, + ): string | number { if (block.workspace.options.oneBasedIndex) { delta--; } const defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - const atOrder = delta ? this.ORDER_ADDITIVE : this.ORDER_NONE; - let at = this.valueToCode(block, atId, atOrder) || defaultAtIndex; + const atOrder = delta ? Order.ADDITIVE : Order.NONE; + let at: string | number = + this.valueToCode(block, atId, atOrder) || defaultAtIndex; if (stringUtils.isNumber(at)) { // If the index is a naked number, adjust it right now. at = parseInt(at, 10) + delta; - if (opt_negate) { + if (negate) { at = -at; } } else { @@ -328,7 +349,7 @@ export class PythonGenerator extends CodeGenerator { } else { at = 'int(' + at + ')'; } - if (opt_negate) { + if (negate) { at = '-' + at; } } diff --git a/generators/python/text.js b/generators/python/text.ts similarity index 63% rename from generators/python/text.js rename to generators/python/text.ts index f4cd181f3..dca9e9832 100644 --- a/generators/python/text.js +++ b/generators/python/text.ts @@ -11,23 +11,30 @@ // Former goog.module ID: Blockly.Python.texts import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; import {NameType} from '../../core/names.js'; import {Order} from './python_generator.js'; +import type {PythonGenerator} from './python_generator.js'; - -export function text(block, generator) { +export function text( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block, generator) { +export function text_multiline( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; + const order = code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; return [code, order]; -}; +} /** * Regular expression to detect a single-quoted string literal. @@ -37,95 +44,113 @@ const strRegExp = /^\s*'([^']|\\')*'\s*$/; /** * Enclose the provided value in 'str(...)' function. * Leave string literals alone. - * @param {string} value Code evaluating to a value. - * @return {Array} Array containing code evaluating to a string + * + * @param value Code evaluating to a value. + * @returns Array containing code evaluating to a string * and * the order of the returned code.[string, number] */ -const forceString = function(value) { +const forceString = function (value: string): [string, Order] { if (strRegExp.test(value)) { return [value, Order.ATOMIC]; } return ['str(' + value + ')', Order.FUNCTION_CALL]; }; -export function text_join(block, generator) { +export function text_join( + block: Block, + generator: PythonGenerator, +): [string, Order] { + const joinBlock = block as JoinMutatorBlock; // Create a string made up of any number of elements of any type. // Should we allow joining by '-' or ',' or any other characters? - switch (block.itemCount_) { + switch (joinBlock.itemCount_) { case 0: return ["''", Order.ATOMIC]; case 1: { - const element = - generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const codeAndOrder = forceString(element); return codeAndOrder; } case 2: { - const element0 = - generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; - const element1 = - generator.valueToCode(block, 'ADD1', Order.NONE) || "''"; + const element0 = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; + const element1 = generator.valueToCode(block, 'ADD1', Order.NONE) || "''"; const code = forceString(element0)[0] + ' + ' + forceString(element1)[0]; return [code, Order.ADDITIVE]; } default: { const elements = []; - for (let i = 0; i < block.itemCount_; i++) { + for (let i = 0; i < joinBlock.itemCount_; i++) { elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } - const tempVar = - generator.nameDB_.getDistinctName('x', NameType.VARIABLE); - const code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' + - elements.join(', ') + ']])'; + const tempVar = generator.nameDB_!.getDistinctName( + 'x', + NameType.VARIABLE, + ); + const code = + "''.join([str(" + + tempVar + + ') for ' + + tempVar + + ' in [' + + elements.join(', ') + + ']])'; return [code, Order.FUNCTION_CALL]; } } -}; +} -export function text_append(block, generator) { +export function text_append(block: Block, generator: PythonGenerator) { // Append to a variable in place. - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + const varName = generator.getVariableName(block.getFieldValue('VAR')); const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return varName + ' = str(' + varName + ') + ' + forceString(value)[0] + '\n'; -}; +} -export function text_length(block, generator) { +export function text_length( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['len(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_isEmpty(block, generator) { +export function text_isEmpty( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; const code = 'not len(' + text + ')'; return [code, Order.LOGICAL_NOT]; -}; +} -export function text_indexOf(block, generator) { +export function text_indexOf( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Search the text for a substring. // Should we allow for non-case sensitive??? const operator = block.getFieldValue('END') === 'FIRST' ? 'find' : 'rfind'; - const substring = - generator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const text = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + const text = generator.valueToCode(block, 'VALUE', Order.MEMBER) || "''"; const code = text + '.' + operator + '(' + substring + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; } return [code, Order.FUNCTION_CALL]; -}; +} -export function text_charAt(block, generator) { +export function text_charAt( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = - (where === 'RANDOM') ? Order.NONE : Order.MEMBER; + const textOrder = where === 'RANDOM' ? Order.NONE : Order.MEMBER; const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { @@ -147,26 +172,33 @@ export function text_charAt(block, generator) { return [code, Order.MEMBER]; } case 'RANDOM': { - generator.definitions_['import_random'] = 'import random'; - const functionName = - generator.provideFunction_('text_random_letter', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected (here and below). + (generator as AnyDuringMigration).definitions_['import_random'] = + 'import random'; + const functionName = generator.provideFunction_( + 'text_random_letter', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(text): x = int(random.random() * len(text)) return text[x] -`); +`, + ); const code = functionName + '(' + text + ')'; return [code, Order.FUNCTION_CALL]; } } throw Error('Unhandled option (text_charAt).'); -}; +} -export function text_getSubstring(block, generator) { +export function text_getSubstring( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); - const text = - generator.valueToCode(block, 'STRING', Order.MEMBER) || "''"; + const text = generator.valueToCode(block, 'STRING', Order.MEMBER) || "''"; let at1; switch (where1) { case 'FROM_START': @@ -195,7 +227,8 @@ export function text_getSubstring(block, generator) { // Ensure that if the result calculated is 0 that sub-sequence will // include all elements as expected. if (!stringUtils.isNumber(String(at2))) { - generator.definitions_['import_sys'] = 'import sys'; + (generator as AnyDuringMigration).definitions_['import_sys'] = + 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -209,49 +242,63 @@ export function text_getSubstring(block, generator) { } const code = text + '[' + at1 + ' : ' + at2 + ']'; return [code, Order.MEMBER]; -}; +} -export function text_changeCase(block, generator) { +export function text_changeCase( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.upper()', 'LOWERCASE': '.lower()', - 'TITLECASE': '.title()' + 'TITLECASE': '.title()', }; - const operator = OPERATORS[block.getFieldValue('CASE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('CASE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + operator; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_trim(block, generator) { +export function text_trim( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = { 'LEFT': '.lstrip()', 'RIGHT': '.rstrip()', - 'BOTH': '.strip()' + 'BOTH': '.strip()', }; - const operator = OPERATORS[block.getFieldValue('MODE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + operator; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_print(block, generator) { +export function text_print(block: Block, generator: PythonGenerator) { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ')\n'; -}; +} -export function text_prompt_ext(block, generator) { +export function text_prompt_ext( + block: Block, + generator: PythonGenerator, +): [string, Order] { // Prompt function. - const functionName = generator.provideFunction_('text_prompt', ` + const functionName = generator.provideFunction_( + 'text_prompt', + ` def ${generator.FUNCTION_NAME_PLACEHOLDER_}(msg): try: return raw_input(msg) except NameError: return input(msg) -`); +`, + ); let msg; if (block.getField('TEXT')) { // Internal message. @@ -266,27 +313,36 @@ def ${generator.FUNCTION_NAME_PLACEHOLDER_}(msg): code = 'float(' + code + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { +export function text_count( + block: Block, + generator: PythonGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; const code = text + '.count(' + sub + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_replace(block, generator) { +export function text_replace( + block: Block, + generator: PythonGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = text + '.replace(' + from + ', ' + to + ')'; return [code, Order.MEMBER]; -}; +} -export function text_reverse(block, generator) { +export function text_reverse( + block: Block, + generator: PythonGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.MEMBER) || "''"; const code = text + '[::-1]'; return [code, Order.MEMBER]; -}; +} diff --git a/generators/python/variables.js b/generators/python/variables.js deleted file mode 100644 index 0908cd2ed..000000000 --- a/generators/python/variables.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright 2012 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Generating Python for variable blocks. - */ - -// Former goog.module ID: Blockly.Python.variables - -import {Order} from './python_generator.js'; - - -export function variables_get(block, generator) { - // Variable getter. - const code = - generator.getVariableName(block.getFieldValue('VAR')); - return [code, Order.ATOMIC]; -}; - -export function variables_set(block, generator) { - // Variable setter. - const argument0 = - generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = ' + argument0 + '\n'; -}; diff --git a/generators/python/variables.ts b/generators/python/variables.ts new file mode 100644 index 000000000..5510e5e0f --- /dev/null +++ b/generators/python/variables.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2012 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Generating Python for variable blocks. + */ + +// Former goog.module ID: Blockly.Python.variables + +import type {Block} from '../../core/block.js'; +import type {PythonGenerator} from './python_generator.js'; +import {Order} from './python_generator.js'; + +export function variables_get( + block: Block, + generator: PythonGenerator, +): [string, Order] { + // Variable getter. + const code = generator.getVariableName(block.getFieldValue('VAR')); + return [code, Order.ATOMIC]; +} + +export function variables_set(block: Block, generator: PythonGenerator) { + // Variable setter. + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + return varName + ' = ' + argument0 + '\n'; +} diff --git a/generators/python/variables_dynamic.js b/generators/python/variables_dynamic.ts similarity index 99% rename from generators/python/variables_dynamic.js rename to generators/python/variables_dynamic.ts index 36c56ca06..4ca397258 100644 --- a/generators/python/variables_dynamic.js +++ b/generators/python/variables_dynamic.ts @@ -10,7 +10,6 @@ // Former goog.module ID: Blockly.Python.variablesDynamic - // generator is dynamically typed. export { variables_get as variables_get_dynamic, From 28cbdf0f2f69ef583bede7de74f76da6c5d89b60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 08:48:37 -0800 Subject: [PATCH 55/86] chore(deps): Bump @typescript-eslint/eslint-plugin from 6.9.0 to 6.10.0 (#7642) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.10.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 130 +++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6fff44fd8..a5e516c4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1107,9 +1107,9 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/node": { @@ -1125,9 +1125,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, "node_modules/@types/vinyl": { @@ -1166,16 +1166,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz", + "integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/type-utils": "6.10.0", + "@typescript-eslint/utils": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1201,13 +1201,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1218,9 +1218,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1231,12 +1231,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1295,13 +1295,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz", + "integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/utils": "6.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1322,9 +1322,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1335,13 +1335,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1362,12 +1362,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1421,17 +1421,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz", + "integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", "semver": "^7.5.4" }, "engines": { @@ -1446,13 +1446,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1463,9 +1463,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1476,13 +1476,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1503,12 +1503,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { From ffc64ebdf3d63dd9d42cde490fb8d2a6b36d4648 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:28:47 +0000 Subject: [PATCH 56/86] chore(deps): Bump @blockly/theme-modern from 5.0.1 to 5.0.4 (#7645) Bumps [@blockly/theme-modern](https://github.com/google/blockly-samples/tree/HEAD/plugins/theme-modern) from 5.0.1 to 5.0.4. - [Release notes](https://github.com/google/blockly-samples/releases) - [Changelog](https://github.com/google/blockly-samples/blob/master/plugins/theme-modern/CHANGELOG.md) - [Commits](https://github.com/google/blockly-samples/commits/@blockly/theme-modern@5.0.4/plugins/theme-modern) --- updated-dependencies: - dependency-name: "@blockly/theme-modern" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a5e516c4c..19ba6a8d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -326,9 +326,9 @@ } }, "node_modules/@blockly/theme-modern": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-5.0.1.tgz", - "integrity": "sha512-88XtPw1cNVFTg3LDUeoERc9LZk6wZ7iFJYklPgbWUL/Dnq7/WOuB+kYy2nb7jBPReKchInNjdHM09tWQdKi+eQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-5.0.4.tgz", + "integrity": "sha512-AamkRgc5XDvENdEBol8GVUebBooAaHP/yGfixVQ3Oj48xErKisUbLuCpZ4emvahewGghJ55HVXSJKdLQ2n0h8w==", "dev": true, "engines": { "node": ">=8.17.0" From 7cb83f21f4daf524ea19763cbc2d27a26b3ffcde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:29:25 +0000 Subject: [PATCH 57/86] chore(deps): Bump eslint-plugin-jsdoc from 46.8.2 to 46.9.0 (#7643) Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 46.8.2 to 46.9.0. - [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases) - [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc) - [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.8.2...v46.9.0) --- updated-dependencies: - dependency-name: eslint-plugin-jsdoc dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 19ba6a8d7..d492655b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -350,12 +350,12 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz", - "integrity": "sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==", + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", "dev": true, "dependencies": { - "comment-parser": "1.4.0", + "comment-parser": "1.4.1", "esquery": "^1.5.0", "jsdoc-type-pratt-parser": "~4.0.0" }, @@ -3018,9 +3018,9 @@ } }, "node_modules/comment-parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.0.tgz", - "integrity": "sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -3961,14 +3961,14 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "46.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz", - "integrity": "sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ==", + "version": "46.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.0.tgz", + "integrity": "sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.40.1", + "@es-joy/jsdoccomment": "~0.41.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.0", + "comment-parser": "1.4.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "esquery": "^1.5.0", From 81b427f4ad420d07dec3454ec8b60e7abaee2df0 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Tue, 14 Nov 2023 16:13:50 +0000 Subject: [PATCH 58/86] refactor(generators): Migrate Dart generators to TypeScript (#7646) * refactor(generators): Migrate dart_generator.js to TypeScript * refactor(generators): Simplify getAdjusted Slightly simplify the implementation of getAdjusted, in part to make it more readable. Also improve its JSDoc comment. * refactor(generators): Migrate generators/dart/* to TypeScript First pass doing very mechanistic migration, not attempting to fix all the resulting type errors. * fix(generators): Fix type errors in generator functions This consists almost entirely of adding casts, so the code output by tsc should be as similar as possible to the pre-migration .js source files. * fix(generators): Fix minor inconsistencies in JS and Python The migration of the JavaScript and Python generators inadvertently introduced some inconsistencies in the code, e.g.: - Incorrect import ordering. - Putting executable code before the initial comment line that most generator functions begin with, and/or deleting or replacing these comments. - N.B. however that these inline comments should have been JSDocs; a task to convert them has been added to #7600. * refactor(generators): Migrate generators/dart.js to TypeScript The way the generator functions are added to dartGenerator.forBlock has been modified so that incorrect generator function signatures will cause tsc to generate a type error. * chore(generator): Format One block protected with // prettier-ignore to preserve careful comment formatting. Where there are repeated concatenations prettier has made a pretty mess of things, but the correct fix is probably to use template literals instead (rather than just locally disabling prettier). This is one of the items in the to-do list in #7600. * fix(generators): Fix for PR #7646 --- generators/{dart.js => dart.ts} | 19 +- generators/dart/{colour.js => colour.ts} | 79 +++-- generators/dart/dart_generator.js | 308 ----------------- generators/dart/dart_generator.ts | 321 ++++++++++++++++++ generators/dart/{lists.js => lists.ts} | 286 ++++++++++------ generators/dart/{logic.js => logic.ts} | 113 +++--- generators/dart/{loops.js => loops.ts} | 155 ++++++--- generators/dart/{math.js => math.ts} | 317 +++++++++++------ .../dart/{procedures.js => procedures.ts} | 76 +++-- generators/dart/{text.js => text.ts} | 241 ++++++++----- generators/dart/variables.js | 30 -- generators/dart/variables.ts | 32 ++ ...iables_dynamic.js => variables_dynamic.ts} | 1 - generators/javascript/lists.ts | 2 +- generators/javascript/logic.ts | 2 +- generators/javascript/text.ts | 4 +- generators/python/lists.ts | 2 +- generators/python/text.ts | 2 +- 18 files changed, 1194 insertions(+), 796 deletions(-) rename generators/{dart.js => dart.ts} (81%) rename generators/dart/{colour.js => colour.ts} (62%) delete mode 100644 generators/dart/dart_generator.js create mode 100644 generators/dart/dart_generator.ts rename generators/dart/{lists.js => lists.ts} (66%) rename generators/dart/{logic.js => logic.ts} (52%) rename generators/dart/{loops.js => loops.ts} (57%) rename generators/dart/{math.js => math.ts} (60%) rename generators/dart/{procedures.js => procedures.ts} (60%) rename generators/dart/{text.js => text.ts} (61%) delete mode 100644 generators/dart/variables.js create mode 100644 generators/dart/variables.ts rename generators/dart/{variables_dynamic.js => variables_dynamic.ts} (99%) diff --git a/generators/dart.js b/generators/dart.ts similarity index 81% rename from generators/dart.js rename to generators/dart.ts index 26a3c62c7..3bd1271ad 100644 --- a/generators/dart.js +++ b/generators/dart.ts @@ -36,8 +36,17 @@ export const dartGenerator = new DartGenerator(); dartGenerator.addReservedWords('Html,Math'); // Install per-block-type generator functions: -Object.assign( - dartGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +const generators: typeof dartGenerator.forBlock = { + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, +}; +for (const name in generators) { + dartGenerator.forBlock[name] = generators[name]; +} diff --git a/generators/dart/colour.js b/generators/dart/colour.ts similarity index 62% rename from generators/dart/colour.js rename to generators/dart/colour.ts index b5405a34f..b55fc5e6f 100644 --- a/generators/dart/colour.js +++ b/generators/dart/colour.ts @@ -10,22 +10,33 @@ // Former goog.module ID: Blockly.Dart.colour +import type {Block} from '../../core/block.js'; +import type {DartGenerator} from './dart_generator.js'; import {Order} from './dart_generator.js'; - // RESERVED WORDS: 'Math' -export function colour_picker(block, generator) { +export function colour_picker( + block: Block, + generator: DartGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block, generator) { +export function colour_random( + block: Block, + generator: DartGenerator, +): [string, Order] { // Generate a random colour. - generator.definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_('colour_random', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'colour_random', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}() { String hex = '0123456789abcdef'; var rnd = new Math.Random(); @@ -33,20 +44,28 @@ String ${generator.FUNCTION_NAME_PLACEHOLDER_}() { '\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}' '\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}'; } -`); +`, + ); const code = functionName + '()'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function colour_rgb(block, generator) { +export function colour_rgb( + block: Block, + generator: DartGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; const blue = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; - generator.definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_('colour_rgb', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'colour_rgb', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { num rn = (Math.max(Math.min(r, 100), 0) * 2.55).round(); String rs = rn.toInt().toRadixString(16); @@ -62,23 +81,28 @@ String ${generator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { bs = bs.substring(bs.length - 2); return '#$rs$gs$bs'; } -`); +`, + ); const code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function colour_blend(block, generator) { +export function colour_blend( + block: Block, + generator: DartGenerator, +): [string, Order] { // Blend two colours together. - const c1 = - generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; - const c2 = - generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; - const ratio = - generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; + const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - generator.definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_('colour_blend', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'colour_blend', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String c1, String c2, num ratio) { ratio = Math.max(Math.min(ratio, 1), 0); int r1 = int.parse('0x\${c1.substring(1, 3)}'); @@ -101,7 +125,8 @@ String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String c1, String c2, num ratio) bs = bs.substring(bs.length - 2); return '#$rs$gs$bs'; } -`); +`, + ); const code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} diff --git a/generators/dart/dart_generator.js b/generators/dart/dart_generator.js deleted file mode 100644 index 412af49ee..000000000 --- a/generators/dart/dart_generator.js +++ /dev/null @@ -1,308 +0,0 @@ -/** - * @license - * Copyright 2014 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Helper functions for generating Dart for blocks. - * @suppress {checkTypes|globalThis} - */ - -// Former goog.module ID: Blockly.Dart - -import * as Variables from '../../core/variables.js'; -import * as stringUtils from '../../core/utils/string.js'; -// import type {Block} from '../../core/block.js'; -import {CodeGenerator} from '../../core/generator.js'; -import {Names, NameType} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; -import {inputTypes} from '../../core/inputs/input_types.js'; - - -/** - * Order of operation ENUMs. - * https://dart.dev/guides/language/language-tour#operators - * @enum {number} - */ -export const Order = { - ATOMIC: 0, // 0 "" ... - UNARY_POSTFIX: 1, // expr++ expr-- () [] . ?. - UNARY_PREFIX: 2, // -expr !expr ~expr ++expr --expr - MULTIPLICATIVE: 3, // * / % ~/ - ADDITIVE: 4, // + - - SHIFT: 5, // << >> - BITWISE_AND: 6, // & - BITWISE_XOR: 7, // ^ - BITWISE_OR: 8, // | - RELATIONAL: 9, // >= > <= < as is is! - EQUALITY: 10, // == != - LOGICAL_AND: 11, // && - LOGICAL_OR: 12, // || - IF_NULL: 13, // ?? - CONDITIONAL: 14, // expr ? expr : expr - CASCADE: 15, // .. - ASSIGNMENT: 16, // = *= /= ~/= %= += -= <<= >>= &= ^= |= - NONE: 99, // (...) -}; - -/** - * Dart code generator class. - */ -export class DartGenerator extends CodeGenerator { - constructor(name) { - super(name ?? 'Dart'); - this.isInitialized = false; - - // Copy Order values onto instance for backwards compatibility - // while ensuring they are not part of the publically-advertised - // API. - // - // TODO(#7085): deprecate these in due course. (Could initially - // replace data properties with get accessors that call - // deprecate.warn().) - for (const key in Order) { - this['ORDER_' + key] = Order[key]; - } - - // List of illegal variable names. This is not intended to be a - // security feature. Blockly is 100% client-side, so bypassing - // this list is trivial. This is intended to prevent users from - // accidentally clobbering a built-in object or function. - this.addReservedWords( - // https://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf - // Section 16.1.1 - 'assert,break,case,catch,class,const,continue,default,do,else,enum,' + - 'extends,false,final,finally,for,if,in,is,new,null,rethrow,return,' + - 'super,switch,this,throw,true,try,var,void,while,with,' + - // https://api.dartlang.org/dart_core.html - 'print,identityHashCode,identical,BidirectionalIterator,Comparable,' + - 'double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,' + - 'Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,' + - 'Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,' + - 'StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,' + - 'ArgumentError,AssertionError,CastError,ConcurrentModificationError,' + - 'CyclicInitializationError,Error,Exception,FallThroughError,' + - 'FormatException,IntegerDivisionByZeroException,NoSuchMethodError,' + - 'NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,' + - 'StateError,TypeError,UnimplementedError,UnsupportedError' - ); - } - - /** - * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. - */ - init(workspace) { - super.init(); - - if (!this.nameDB_) { - this.nameDB_ = new Names(this.RESERVED_WORDS_); - } else { - this.nameDB_.reset(); - } - - this.nameDB_.setVariableMap(workspace.getVariableMap()); - this.nameDB_.populateVariables(workspace); - this.nameDB_.populateProcedures(workspace); - - const defvars = []; - // Add developer variables (not created or named by the user). - const devVarList = Variables.allDeveloperVariables(workspace); - for (let i = 0; i < devVarList.length; i++) { - defvars.push(this.nameDB_.getName(devVarList[i], - NameType.DEVELOPER_VARIABLE)); - } - - // Add user variables, but only ones that are being used. - const variables = Variables.allUsedVarModels(workspace); - for (let i = 0; i < variables.length; i++) { - defvars.push(this.nameDB_.getName(variables[i].getId(), - NameType.VARIABLE)); - } - - // Declare all of the variables. - if (defvars.length) { - this.definitions_['variables'] = - 'var ' + defvars.join(', ') + ';'; - } - this.isInitialized = true; - } - - /** - * Prepend the generated code with import statements and variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. - */ - finish(code) { - // Indent every line. - if (code) { - code = this.prefixLines(code, this.INDENT); - } - code = 'main() {\n' + code + '}'; - - // Convert the definitions dictionary into a list. - const imports = []; - const definitions = []; - for (let name in this.definitions_) { - const def = this.definitions_[name]; - if (def.match(/^import\s/)) { - imports.push(def); - } else { - definitions.push(def); - } - } - // Call Blockly.CodeGenerator's finish. - code = super.finish(code); - this.isInitialized = false; - - this.nameDB_.reset(); - const allDefs = imports.join('\n') + '\n\n' + definitions.join('\n\n'); - return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code; - } - - /** - * Naked values are top-level blocks with outputs that aren't plugged into - * anything. A trailing semicolon is needed to make this legal. - * @param {string} line Line of generated code. - * @return {string} Legal line of code. - */ - scrubNakedValue(line) { - return line + ';\n'; - } - - /** - * Encode a string as a properly escaped Dart string, complete with quotes. - * @param {string} string Text to encode. - * @return {string} Dart string. - */ - quote_(string) { - // Can't use goog.string.quote since $ must also be escaped. - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n') - .replace(/\$/g, '\\$') - .replace(/'/g, '\\\''); - return '\'' + string + '\''; - } - - /** - * Encode a string as a properly escaped multiline Dart string, complete with - * quotes. - * @param {string} string Text to encode. - * @return {string} Dart string. - */ - multiline_quote_(string) { - const lines = string.split(/\n/g).map(this.quote_); - // Join with the following, plus a newline: - // + '\n' + - return lines.join(' + \'\\n\' + \n'); - } - - /** - * Common tasks for generating Dart from blocks. - * Handles comments for the specified block and any connected value blocks. - * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The Dart code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this - * statement. - * @return {string} Dart code with comments and subsequent blocks added. - * @protected - */ - scrub_(block, code, opt_thisOnly) { - let commentCode = ''; - // Only collect comments for blocks that aren't inline. - if (!block.outputConnection || !block.outputConnection.targetConnection) { - // Collect comment for this block. - let comment = block.getCommentText(); - if (comment) { - comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3); - if (block.getProcedureDef) { - // Use documentation comment for function comments. - commentCode += this.prefixLines(comment + '\n', '/// '); - } else { - commentCode += this.prefixLines(comment + '\n', '// '); - } - } - // Collect comments for all value arguments. - // Don't collect comments for nested statements. - for (let i = 0; i < block.inputList.length; i++) { - if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); - if (childBlock) { - comment = this.allNestedComments(childBlock); - if (comment) { - commentCode += this.prefixLines(comment, '// '); - } - } - } - } - } - const nextBlock = - block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); - return commentCode + code + nextCode; - } - - /** - * Gets a property and adjusts the value while taking into account indexing. - * @param {!Block} block The block. - * @param {string} atId The property ID of the element to get. - * @param {number=} opt_delta Value to add. - * @param {boolean=} opt_negate Whether to negate the value. - * @param {number=} opt_order The highest order acting on this value. - * @return {string|number} - */ - getAdjusted(block, atId, opt_delta, opt_negate, opt_order) { - let delta = opt_delta || 0; - let order = opt_order || this.ORDER_NONE; - if (block.workspace.options.oneBasedIndex) { - delta--; - } - const defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - - /** @type {number} */ - let outerOrder; - let innerOrder; - if (delta) { - outerOrder = this.ORDER_ADDITIVE; - innerOrder = this.ORDER_ADDITIVE; - } else if (opt_negate) { - outerOrder = this.ORDER_UNARY_PREFIX; - innerOrder = this.ORDER_UNARY_PREFIX; - } else { - outerOrder = order; - } - - /** @type {string|number} */ - let at = this.valueToCode(block, atId, outerOrder) || defaultAtIndex; - - if (stringUtils.isNumber(at)) { - // If the index is a naked number, adjust it right now. - at = parseInt(at, 10) + delta; - if (opt_negate) { - at = -at; - } - } else { - // If the index is dynamic, adjust it in code. - if (delta > 0) { - at = at + ' + ' + delta; - } else if (delta < 0) { - at = at + ' - ' + -delta; - } - if (opt_negate) { - if (delta) { - at = '-(' + at + ')'; - } else { - at = '-' + at; - } - } - innerOrder = Math.floor(innerOrder); - order = Math.floor(order); - if (innerOrder && order >= innerOrder) { - at = '(' + at + ')'; - } - } - return at; - } -} diff --git a/generators/dart/dart_generator.ts b/generators/dart/dart_generator.ts new file mode 100644 index 000000000..b2eb80cdd --- /dev/null +++ b/generators/dart/dart_generator.ts @@ -0,0 +1,321 @@ +/** + * @license + * Copyright 2014 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file Dart code generator class, including helper methods for + * generating Dart for blocks. + */ + +// Former goog.module ID: Blockly.Dart + +import * as Variables from '../../core/variables.js'; +import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import {CodeGenerator} from '../../core/generator.js'; +import {Names, NameType} from '../../core/names.js'; +import type {Workspace} from '../../core/workspace.js'; +import {inputTypes} from '../../core/inputs/input_types.js'; + +/** + * Order of operation ENUMs. + * https://dart.dev/guides/language/language-tour#operators + */ +// prettier-ignore +export enum Order { + ATOMIC = 0, // 0 "" ... + UNARY_POSTFIX = 1, // expr++ expr-- () [] . ?. + UNARY_PREFIX = 2, // -expr !expr ~expr ++expr --expr + MULTIPLICATIVE = 3, // * / % ~/ + ADDITIVE = 4, // + - + SHIFT = 5, // << >> + BITWISE_AND = 6, // & + BITWISE_XOR = 7, // ^ + BITWISE_OR = 8, // | + RELATIONAL = 9, // >= > <= < as is is! + EQUALITY = 10, // == != + LOGICAL_AND = 11, // && + LOGICAL_OR = 12, // || + IF_NULL = 13, // ?? + CONDITIONAL = 14, // expr ? expr: expr + CASCADE = 15, // .. + ASSIGNMENT = 16, // = *= /= ~/= %= += -= <<= >>= &= ^= |= + NONE = 99, // (...) +} + +/** + * Dart code generator class. + */ +export class DartGenerator extends CodeGenerator { + /** @param name Name of the language the generator is for. */ + constructor(name = 'Dart') { + super(name); + this.isInitialized = false; + + // Copy Order values onto instance for backwards compatibility + // while ensuring they are not part of the publically-advertised + // API. + // + // TODO(#7085): deprecate these in due course. (Could initially + // replace data properties with get accessors that call + // deprecate.warn().) + for (const key in Order) { + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; + } + + // List of illegal variable names. This is not intended to be a + // security feature. Blockly is 100% client-side, so bypassing + // this list is trivial. This is intended to prevent users from + // accidentally clobbering a built-in object or function. + this.addReservedWords( + // https://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf + // Section 16.1.1 + 'assert,break,case,catch,class,const,continue,default,do,else,enum,' + + 'extends,false,final,finally,for,if,in,is,new,null,rethrow,return,' + + 'super,switch,this,throw,true,try,var,void,while,with,' + + // https://api.dartlang.org/dart_core.html + 'print,identityHashCode,identical,BidirectionalIterator,Comparable,' + + 'double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,' + + 'Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,' + + 'Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,' + + 'StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,' + + 'ArgumentError,AssertionError,CastError,ConcurrentModificationError,' + + 'CyclicInitializationError,Error,Exception,FallThroughError,' + + 'FormatException,IntegerDivisionByZeroException,NoSuchMethodError,' + + 'NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,' + + 'StateError,TypeError,UnimplementedError,UnsupportedError', + ); + } + + /** + * Initialise the database of variable names. + * + * @param workspace Workspace to generate code from. + */ + init(workspace: Workspace) { + super.init(workspace); + + if (!this.nameDB_) { + this.nameDB_ = new Names(this.RESERVED_WORDS_); + } else { + this.nameDB_.reset(); + } + + this.nameDB_.setVariableMap(workspace.getVariableMap()); + this.nameDB_.populateVariables(workspace); + this.nameDB_.populateProcedures(workspace); + + const defvars = []; + // Add developer variables (not created or named by the user). + const devVarList = Variables.allDeveloperVariables(workspace); + for (let i = 0; i < devVarList.length; i++) { + defvars.push( + this.nameDB_.getName(devVarList[i], NameType.DEVELOPER_VARIABLE), + ); + } + + // Add user variables, but only ones that are being used. + const variables = Variables.allUsedVarModels(workspace); + for (let i = 0; i < variables.length; i++) { + defvars.push( + this.nameDB_.getName(variables[i].getId(), NameType.VARIABLE), + ); + } + + // Declare all of the variables. + if (defvars.length) { + this.definitions_['variables'] = 'var ' + defvars.join(', ') + ';'; + } + this.isInitialized = true; + } + + /** + * Prepend the generated code with import statements and variable definitions. + * + * @param code Generated code. + * @returns Completed code. + */ + finish(code: string): string { + // Indent every line. + if (code) { + code = this.prefixLines(code, this.INDENT); + } + code = 'main() {\n' + code + '}'; + + // Convert the definitions dictionary into a list. + const imports = []; + const definitions = []; + for (let name in this.definitions_) { + const def = this.definitions_[name]; + if (def.match(/^import\s/)) { + imports.push(def); + } else { + definitions.push(def); + } + } + // Call Blockly.CodeGenerator's finish. + code = super.finish(code); + this.isInitialized = false; + + this.nameDB_!.reset(); + const allDefs = imports.join('\n') + '\n\n' + definitions.join('\n\n'); + return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code; + } + + /** + * Naked values are top-level blocks with outputs that aren't plugged into + * anything. + * + * @param line Line of generated code. + * @returns Legal line of code. + */ + scrubNakedValue(line: string): string { + return line + ';\n'; + } + + /** + * Encode a string as a properly escaped Dart string, complete with quotes. + * + * @param string Text to encode. + * @returns Dart string. + */ + quote_(string: string): string { + // Can't use goog.string.quote since $ must also be escaped. + string = string + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\\n') + .replace(/\$/g, '\\$') + .replace(/'/g, "\\'"); + return "'" + string + "'"; + } + + /** + * Encode a string as a properly escaped multiline Dart string, complete + * with quotes. + * + * @param string Text to encode. + * @returns Dart string. + */ + multiline_quote_(string: string): string { + const lines = string.split(/\n/g).map(this.quote_); + // Join with the following, plus a newline: + // + '\n' + + return lines.join(" + '\\n' + \n"); + } + + /** + * Common tasks for generating Dart from blocks. + * Handles comments for the specified block and any connected value blocks. + * Calls any statements following this block. + * + * @param block The current block. + * @param code The Dart code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns Dart code with comments and subsequent blocks added. + */ + scrub_(block: Block, code: string, thisOnly = false): string { + let commentCode = ''; + // Only collect comments for blocks that aren't inline. + if (!block.outputConnection || !block.outputConnection.targetConnection) { + // Collect comment for this block. + let comment = block.getCommentText(); + if (comment) { + comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3); + if ((block as AnyDuringMigration).getProcedureDef) { + // Use documentation comment for function comments. + commentCode += this.prefixLines(comment + '\n', '/// '); + } else { + commentCode += this.prefixLines(comment + '\n', '// '); + } + } + // Collect comments for all value arguments. + // Don't collect comments for nested statements. + for (let i = 0; i < block.inputList.length; i++) { + if (block.inputList[i].type === inputTypes.VALUE) { + const childBlock = block.inputList[i].connection!.targetBlock(); + if (childBlock) { + comment = this.allNestedComments(childBlock); + if (comment) { + commentCode += this.prefixLines(comment, '// '); + } + } + } + } + } + const nextBlock = + block.nextConnection && block.nextConnection.targetBlock(); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); + return commentCode + code + nextCode; + } + + /** + * Generate code representing the specified value input, adjusted to take into + * account indexing (zero- or one-based) and optionally by a specified delta + * and/or by negation. + * + * @param block The block. + * @param atId The ID of the input block to get (and adjust) the value of. + * @param delta Value to add. + * @param negate Whether to negate the value. + * @param order The highest order acting on this value. + * @returns The adjusted value. + */ + getAdjusted( + block: Block, + atId: string, + delta = 0, + negate = false, + order = Order.NONE, + ): string | number { + if (block.workspace.options.oneBasedIndex) { + delta--; + } + const defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; + + let orderForInput = order; + if (delta) { + orderForInput = Order.ADDITIVE; + } else if (negate) { + orderForInput = Order.UNARY_PREFIX; + } + + let at = this.valueToCode(block, atId, orderForInput) || defaultAtIndex; + + // Easy case: no adjustments. + if (delta === 0 && !negate) { + return at; + } + // If the index is a naked number, adjust it right now. + if (stringUtils.isNumber(at)) { + at = String(Number(at) + delta); + if (negate) { + at = String(-Number(at)); + } + return at; + } + // If the index is dynamic, adjust it in code. + if (delta > 0) { + at = `${at} + ${delta}`; + } else if (delta < 0) { + at = `${at} - ${-delta}`; + } + if (negate) { + at = delta ? `-(${at})` : `-${at}`; + } + if (Math.floor(order) >= Math.floor(orderForInput)) { + at = `(${at})`; + } + return at; + } +} diff --git a/generators/dart/lists.js b/generators/dart/lists.ts similarity index 66% rename from generators/dart/lists.js rename to generators/dart/lists.ts index c7a540b69..d1b65cc53 100644 --- a/generators/dart/lists.js +++ b/generators/dart/lists.ts @@ -10,80 +10,104 @@ // Former goog.module ID: Blockly.Dart.lists +import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; +import type {DartGenerator} from './dart_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './dart_generator.js'; - // RESERVED WORDS: 'Math' -export function lists_create_empty(block, generator) { +export function lists_create_empty( + block: Block, + generator: DartGenerator, +): [string, Order] { // Create an empty list. return ['[]', Order.ATOMIC]; -}; +} -export function lists_create_with(block, generator) { +export function lists_create_with( + block: Block, + generator: DartGenerator, +): [string, Order] { // Create a list with any number of elements of any type. - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; + const createWithBlock = block as CreateWithBlock; + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } const code = '[' + elements.join(', ') + ']'; return [code, Order.ATOMIC]; -}; +} -export function lists_repeat(block, generator) { +export function lists_repeat( + block: Block, + generator: DartGenerator, +): [string, Order] { // Create a list with one element repeated. - const element = - generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; - const repeatCount = - generator.valueToCode(block, 'NUM', Order.NONE) || '0'; + const element = generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; + const repeatCount = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = 'new List.filled(' + repeatCount + ', ' + element + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function lists_length(block, generator) { +export function lists_length( + block: Block, + generator: DartGenerator, +): [string, Order] { // String or array length. const list = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; return [list + '.length', Order.UNARY_POSTFIX]; -}; +} -export function lists_isEmpty(block, generator) { +export function lists_isEmpty( + block: Block, + generator: DartGenerator, +): [string, Order] { // Is the string null or array empty? const list = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; return [list + '.isEmpty', Order.UNARY_POSTFIX]; -}; +} -export function lists_indexOf(block, generator) { +export function lists_indexOf( + block: Block, + generator: DartGenerator, +): [string, Order] { // Find an item in the list. const operator = - block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; + block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; const item = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const list = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || '[]'; const code = list + '.' + operator + '(' + item + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; } return [code, Order.UNARY_POSTFIX]; -}; +} -export function lists_getIndex(block, generator) { +export function lists_getIndex( + block: Block, + generator: DartGenerator, +): [string, Order] | string { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const listOrder = (where === 'RANDOM' || where === 'FROM_END') ? - Order.NONE : - Order.UNARY_POSTFIX; + const listOrder = + where === 'RANDOM' || where === 'FROM_END' + ? Order.NONE + : Order.UNARY_POSTFIX; let list = generator.valueToCode(block, 'VALUE', listOrder) || '[]'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); const code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -91,51 +115,60 @@ export function lists_getIndex(block, generator) { // If `list` would be evaluated more than once (which is the case for // RANDOM REMOVE and FROM_END) and is non-trivial, make sure to access it // only once. - if (((where === 'RANDOM' && mode === 'REMOVE') || where === 'FROM_END') && - !list.match(/^\w+$/)) { + if ( + ((where === 'RANDOM' && mode === 'REMOVE') || where === 'FROM_END') && + !list.match(/^\w+$/) + ) { // `list` is an expression, so we may not evaluate it more than once. if (where === 'RANDOM') { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; // We can use multiple statements. let code = cacheList(); - const xVar = - generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); - code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + - '.length);\n'; + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); + code += + 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; return code; - } else { // where === 'FROM_END' + } else { + // where === 'FROM_END' if (mode === 'REMOVE') { // We can use multiple statements. - const at = - generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + const at = generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); let code = cacheList(); - code += list + '.removeAt(' + list + '.length' + - ' - ' + at + ');\n'; + code += list + '.removeAt(' + list + '.length' + ' - ' + at + ');\n'; return code; - } else if (mode === 'GET') { const at = generator.getAdjusted(block, 'AT', 1); // We need to create a procedure to avoid reevaluating values. - const functionName = generator.provideFunction_('lists_get_from_end', ` + const functionName = generator.provideFunction_( + 'lists_get_from_end', + ` dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { x = my_list.length - x; return my_list[x]; } -`); +`, + ); const code = functionName + '(' + list + ', ' + at + ')'; return [code, Order.UNARY_POSTFIX]; } else if (mode === 'GET_REMOVE') { const at = generator.getAdjusted(block, 'AT', 1); // We need to create a procedure to avoid reevaluating values. - const functionName = - generator.provideFunction_('lists_remove_from_end', ` + const functionName = generator.provideFunction_( + 'lists_remove_from_end', + ` dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { x = my_list.length - x; return my_list.removeAt(x); } -`); +`, + ); const code = functionName + '(' + list + ', ' + at + ')'; return [code, Order.UNARY_POSTFIX]; } @@ -180,8 +213,7 @@ dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { break; } case 'FROM_END': { - const at = - generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + const at = generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); if (mode === 'GET') { const code = list + '[' + list + '.length - ' + at + ']'; return [code, Order.UNARY_POSTFIX]; @@ -196,34 +228,46 @@ dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list, num x) { break; } case 'RANDOM': - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; if (mode === 'REMOVE') { // We can use multiple statements. - const xVar = - generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); - let code = 'int ' + xVar + ' = new Math.Random().nextInt(' + list + - '.length);\n'; + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); + let code = + 'int ' + + xVar + + ' = new Math.Random().nextInt(' + + list + + '.length);\n'; code += list + '.removeAt(' + xVar + ');\n'; return code; } else if (mode === 'GET') { - const functionName = - generator.provideFunction_('lists_get_random_item', ` + const functionName = generator.provideFunction_( + 'lists_get_random_item', + ` dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { int x = new Math.Random().nextInt(my_list.length); return my_list[x]; } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.UNARY_POSTFIX]; } else if (mode === 'GET_REMOVE') { - const functionName = - generator.provideFunction_('lists_remove_random_item', ` + const functionName = generator.provideFunction_( + 'lists_remove_random_item', + ` dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { int x = new Math.Random().nextInt(my_list.length); return my_list.removeAt(x); } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.UNARY_POSTFIX]; } @@ -231,25 +275,25 @@ dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List my_list) { } } throw Error('Unhandled combination (lists_getIndex).'); -}; +} -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: DartGenerator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - let list = - generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; - const value = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; + let list = generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; + const value = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); const code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; @@ -281,27 +325,30 @@ export function lists_setIndex(block, generator) { break; } case 'FROM_END': { - const at = - generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); + const at = generator.getAdjusted(block, 'AT', 1, false, Order.ADDITIVE); let code = cacheList(); if (mode === 'SET') { code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n'; return code; } else if (mode === 'INSERT') { - code += list + '.insert(' + list + '.length - ' + at + ', ' + value + - ');\n'; + code += + list + '.insert(' + list + '.length - ' + at + ', ' + value + ');\n'; return code; } break; } case 'RANDOM': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; let code = cacheList(); - const xVar = - generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); - code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + - '.length);\n'; + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); + code += + 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; return code; @@ -313,17 +360,22 @@ export function lists_setIndex(block, generator) { } } throw Error('Unhandled combination (lists_setIndex).'); -}; +} -export function lists_getSublist(block, generator) { +export function lists_getSublist( + block: Block, + generator: DartGenerator, +): [string, Order] { // Get sublist. const list = - generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; + generator.valueToCode(block, 'LIST', Order.UNARY_POSTFIX) || '[]'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let code; - if (list.match(/^\w+$/) || - (where1 !== 'FROM_END' && where2 === 'FROM_START')) { + if ( + list.match(/^\w+$/) || + (where1 !== 'FROM_END' && where2 === 'FROM_START') + ) { // If the list is a is a variable or doesn't require a call for length, // don't generate a helper function. let at1; @@ -364,7 +416,9 @@ export function lists_getSublist(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = generator.provideFunction_('lists_get_sublist', ` + const functionName = generator.provideFunction_( + 'lists_get_sublist', + ` List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String where1, num at1, String where2, num at2) { int getAt(String where, num at) { if (where == 'FROM_END') { @@ -382,19 +436,36 @@ List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String where1, num at1, at2 = getAt(where2, at2) + 1; return list.sublist(at1, at2); } -`); - code = functionName + '(' + list + ', \'' + where1 + '\', ' + at1 + ', \'' + - where2 + '\', ' + at2 + ')'; +`, + ); + code = + functionName + + '(' + + list + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; } return [code, Order.UNARY_POSTFIX]; -}; +} -export function lists_sort(block, generator) { +export function lists_sort( + block: Block, + generator: DartGenerator, +): [string, Order] { // Block for sorting a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const sortFunctionName = generator.provideFunction_('lists_sort', ` + const sortFunctionName = generator.provideFunction_( + 'lists_sort', + ` List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String type, int direction) { var compareFuncs = { 'NUMERIC': (a, b) => (direction * a.compareTo(b)).toInt(), @@ -408,19 +479,21 @@ List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List list, String type, int directi list.sort(compare); return list; } -`); +`, + ); return [ - sortFunctionName + '(' + list + ', ' + - '"' + type + '", ' + direction + ')', - Order.UNARY_POSTFIX + sortFunctionName + '(' + list + ', ' + '"' + type + '", ' + direction + ')', + Order.UNARY_POSTFIX, ]; -}; +} -export function lists_split(block, generator) { +export function lists_split( + block: Block, + generator: DartGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. let input = generator.valueToCode(block, 'INPUT', Order.UNARY_POSTFIX); - const delimiter = - generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + const delimiter = generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -438,12 +511,15 @@ export function lists_split(block, generator) { } const code = input + '.' + functionName + '(' + delimiter + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function lists_reverse(block, generator) { +export function lists_reverse( + block: Block, + generator: DartGenerator, +): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; // XXX What should the operator precedence be for a `new`? const code = 'new List.from(' + list + '.reversed)'; return [code, Order.UNARY_POSTFIX]; -}; +} diff --git a/generators/dart/logic.js b/generators/dart/logic.ts similarity index 52% rename from generators/dart/logic.js rename to generators/dart/logic.ts index f3cbcb8ae..82d9d563b 100644 --- a/generators/dart/logic.js +++ b/generators/dart/logic.ts @@ -10,30 +10,38 @@ // Former goog.module ID: Blockly.Dart.logic +import type {Block} from '../../core/block.js'; +import type {DartGenerator} from './dart_generator.js'; import {Order} from './dart_generator.js'; - -export function controls_if(block, generator) { +export function controls_if(block: Block, generator: DartGenerator) { // If/elseif/else condition. let n = 0; - let code = '', branchCode, conditionCode; + let code = '', + branchCode, + conditionCode; if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; branchCode = generator.statementToCode(block, 'DO' + n); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } - code += (n > 0 ? 'else ' : '') + 'if (' + conditionCode + ') {\n' + - branchCode + '}'; + code += + (n > 0 ? 'else ' : '') + + 'if (' + + conditionCode + + ') {\n' + + branchCode + + '}'; n++; } while (block.getInput('IF' + n)); @@ -41,37 +49,48 @@ export function controls_if(block, generator) { branchCode = generator.statementToCode(block, 'ELSE'); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += ' else {\n' + branchCode + '}'; } return code + '\n'; -}; +} export const controls_ifelse = controls_if; -export function logic_compare(block, generator) { +export function logic_compare( + block: Block, + generator: DartGenerator, +): [string, Order] { // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; - const order = (operator === '==' || operator === '!=') ? - Order.EQUALITY : - Order.RELATIONAL; + const OPERATORS = { + 'EQ': '==', + 'NEQ': '!=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; + const order = + operator === '==' || operator === '!=' ? Order.EQUALITY : Order.RELATIONAL; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_operation(block, generator) { +export function logic_operation( + block: Block, + generator: DartGenerator, +): [string, Order] { // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; - const order = - (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; + const operator = block.getFieldValue('OP') === 'AND' ? '&&' : '||'; + const order = operator === '&&' ? Order.LOGICAL_AND : Order.LOGICAL_OR; let argument0 = generator.valueToCode(block, 'A', order); let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { @@ -80,7 +99,7 @@ export function logic_operation(block, generator) { argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === '&&') ? 'true' : 'false'; + const defaultArgument = operator === '&&' ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } @@ -90,35 +109,47 @@ export function logic_operation(block, generator) { } const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_negate(block, generator) { +export function logic_negate( + block: Block, + generator: DartGenerator, +): [string, Order] { // Negation. const order = Order.UNARY_PREFIX; const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; -}; +} -export function logic_boolean(block, generator) { +export function logic_boolean( + block: Block, + generator: DartGenerator, +): [string, Order] { // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false'; return [code, Order.ATOMIC]; -}; +} -export function logic_null(block, generator) { +export function logic_null( + block: Block, + generator: DartGenerator, +): [string, Order] { // Null data type. return ['null', Order.ATOMIC]; -}; +} -export function logic_ternary(block, generator) { +export function logic_ternary( + block: Block, + generator: DartGenerator, +): [string, Order] { // Ternary operator. const value_if = - generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; const code = value_if + ' ? ' + value_then + ' : ' + value_else; return [code, Order.CONDITIONAL]; -}; +} diff --git a/generators/dart/loops.js b/generators/dart/loops.ts similarity index 57% rename from generators/dart/loops.js rename to generators/dart/loops.ts index 1ead2d7e8..5f54d2018 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.ts @@ -10,12 +10,14 @@ // Former goog.module ID: Blockly.Dart.loops -import {Order} from './dart_generator.js'; import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; +import type {DartGenerator} from './dart_generator.js'; import {NameType} from '../../core/names.js'; +import {Order} from './dart_generator.js'; - -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext(block: Block, generator: DartGenerator) { let repeats; // Repeat n times. if (block.getField('TIMES')) { @@ -23,61 +25,85 @@ export function controls_repeat_ext(block, generator) { repeats = String(Number(block.getFieldValue('TIMES'))); } else { // External number. - repeats = - generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; + repeats = generator.valueToCode(block, 'TIMES', Order.ASSIGNMENT) || '0'; } let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; - const loopVar = - generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { - endVar = - generator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + 'repeat_end', + NameType.VARIABLE, + ); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } - code += 'for (int ' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + - loopVar + '++) {\n' + branch + '}\n'; + code += + 'for (int ' + + loopVar + + ' = 0; ' + + loopVar + + ' < ' + + endVar + + '; ' + + loopVar + + '++) {\n' + + branch + + '}\n'; return code; -}; +} export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil(block: Block, generator: DartGenerator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - generator.valueToCode( - block, 'BOOL', until ? Order.UNARY_PREFIX : Order.NONE) || - 'false'; + generator.valueToCode( + block, + 'BOOL', + until ? Order.UNARY_PREFIX : Order.NONE, + ) || 'false'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; -}; +} -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: DartGenerator) { // For loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; - const argument1 = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; - const increment = - generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + const increment = generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code; - if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && - stringUtils.isNumber(increment)) { + if ( + stringUtils.isNumber(argument0) && + stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment) + ) { // All arguments are simple numbers. const up = Number(argument0) <= Number(argument1); - code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + - (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; + code = + 'for (' + + variable0 + + ' = ' + + argument0 + + '; ' + + variable0 + + (up ? ' <= ' : ' >= ') + + argument1 + + '; ' + + variable0; const step = Math.abs(Number(increment)); if (step === 1) { code += up ? '++' : '--'; @@ -90,54 +116,77 @@ export function controls_for(block, generator) { // Cache non-trivial values to variables to prevent repeated look-ups. let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { - startVar = - generator.nameDB_.getDistinctName( - variable0 + '_start', NameType.VARIABLE); + startVar = generator.nameDB_!.getDistinctName( + variable0 + '_start', + NameType.VARIABLE, + ); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { - endVar = - generator.nameDB_.getDistinctName( - variable0 + '_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + variable0 + '_end', + NameType.VARIABLE, + ); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. - const incVar = - generator.nameDB_.getDistinctName( - variable0 + '_inc', NameType.VARIABLE); + const incVar = generator.nameDB_!.getDistinctName( + variable0 + '_inc', + NameType.VARIABLE, + ); code += 'num ' + incVar + ' = '; if (stringUtils.isNumber(increment)) { - code += Math.abs(increment) + ';\n'; + code += Math.abs(Number(increment)) + ';\n'; } else { code += '(' + increment + ').abs();\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; - code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + - ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + - ' >= ' + endVar + '; ' + variable0 + ' += ' + incVar + ') {\n' + - branch + '}\n'; + code += + 'for (' + + variable0 + + ' = ' + + startVar + + '; ' + + incVar + + ' >= 0 ? ' + + variable0 + + ' <= ' + + endVar + + ' : ' + + variable0 + + ' >= ' + + endVar + + '; ' + + variable0 + + ' += ' + + incVar + + ') {\n' + + branch + + '}\n'; } return code; -}; +} -export function controls_forEach(block, generator) { +export function controls_forEach(block: Block, generator: DartGenerator) { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); const code = - 'for (var ' + variable0 + ' in ' + argument0 + ') {\n' + branch + '}\n'; + 'for (var ' + variable0 + ' in ' + argument0 + ') {\n' + branch + '}\n'; return code; -}; +} -export function controls_flow_statements(block, generator) { +export function controls_flow_statements( + block: Block, + generator: DartGenerator, +) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { @@ -150,7 +199,7 @@ export function controls_flow_statements(block, generator) { xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. @@ -165,4 +214,4 @@ export function controls_flow_statements(block, generator) { return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/dart/math.js b/generators/dart/math.ts similarity index 60% rename from generators/dart/math.js rename to generators/dart/math.ts index 8541b95a8..01830a0b1 100644 --- a/generators/dart/math.js +++ b/generators/dart/math.ts @@ -10,39 +10,44 @@ // Former goog.module ID: Blockly.Dart.math +import type {Block} from '../../core/block.js'; +import type {DartGenerator} from './dart_generator.js'; import {Order} from './dart_generator.js'; - // RESERVED WORDS: 'Math' -export function math_number(block, generator) { +export function math_number( + block: Block, + generator: DartGenerator, +): [string, Order] { // Numeric value. - let code = Number(block.getFieldValue('NUM')); - let order; - if (code === Infinity) { - code = 'double.infinity'; - order = Order.UNARY_POSTFIX; - } else if (code === -Infinity) { - code = '-double.infinity'; - order = Order.UNARY_PREFIX; + const number = Number(block.getFieldValue('NUM')); + if (number === Infinity) { + return ['double.infinity', Order.UNARY_POSTFIX]; + } else if (number === -Infinity) { + return ['-double.infinity', Order.UNARY_PREFIX]; } else { - // -4.abs() returns -4 in generator due to strange order of operation choices. - // -4 is actually an operator and a number. Reflect this in the order. - order = code < 0 ? Order.UNARY_PREFIX : Order.ATOMIC; + // -4.abs() returns -4 in generator due to strange order of + // operation choices. 4 is actually an operator and a number. + // Reflect this in the order. + return [String(number), number < 0 ? Order.UNARY_PREFIX : Order.ATOMIC]; } - return [code, order]; -}; +} -export function math_arithmetic(block, generator) { +export function math_arithmetic( + block: Block, + generator: DartGenerator, +): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITIVE], 'MINUS': [' - ', Order.ADDITIVE], 'MULTIPLY': [' * ', Order.MULTIPLICATIVE], 'DIVIDE': [' / ', Order.MULTIPLICATIVE], - 'POWER': [null, Order.NONE], // Handle power separately. + 'POWER': [null, Order.NONE], // Handle power separately. }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; @@ -50,16 +55,21 @@ export function math_arithmetic(block, generator) { let code; // Power in generator requires a special case since it has no operator. if (!operator) { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; code = 'Math.pow(' + argument0 + ', ' + argument1 + ')'; return [code, Order.UNARY_POSTFIX]; } code = argument0 + operator + argument1; return [code, order]; -}; +} -export function math_single(block, generator) { +export function math_single( + block: Block, + generator: DartGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; @@ -74,8 +84,10 @@ export function math_single(block, generator) { code = '-' + arg; return [code, Order.UNARY_PREFIX]; } - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; if (operator === 'ABS' || operator.substring(0, 5) === 'ROUND') { arg = generator.valueToCode(block, 'NUM', Order.UNARY_POSTFIX) || '0'; } else if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { @@ -142,11 +154,14 @@ export function math_single(block, generator) { throw Error('Unknown math operator: ' + operator); } return [code, Order.MULTIPLICATIVE]; -}; +} -export function math_constant(block, generator) { +export function math_constant( + block: Block, + generator: DartGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['Math.pi', Order.UNARY_POSTFIX], 'E': ['Math.e', Order.UNARY_POSTFIX], 'GOLDEN_RATIO': ['(1 + Math.sqrt(5)) / 2', Order.MULTIPLICATIVE], @@ -154,18 +169,24 @@ export function math_constant(block, generator) { 'SQRT1_2': ['Math.sqrt1_2', Order.UNARY_POSTFIX], 'INFINITY': ['double.infinity', Order.ATOMIC], }; - const constant = block.getFieldValue('CONSTANT'); + type ConstantOption = keyof typeof CONSTANTS; + const constant = block.getFieldValue('CONSTANT') as ConstantOption; if (constant !== 'INFINITY') { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; } return CONSTANTS[constant]; -}; +} -export function math_number_property(block, generator) { +export function math_number_property( + block: Block, + generator: DartGenerator, +): [string, Order] { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. - const PROPERTIES = { + const PROPERTIES: Record = { 'EVEN': [' % 2 == 0', Order.MULTIPLICATIVE, Order.EQUALITY], 'ODD': [' % 2 == 1', Order.MULTIPLICATIVE, Order.EQUALITY], 'WHOLE': [' % 1 == 0', Order.MULTIPLICATIVE, Order.EQUALITY], @@ -174,16 +195,21 @@ export function math_number_property(block, generator) { 'DIVISIBLE_BY': [null, Order.MULTIPLICATIVE, Order.EQUALITY], 'PRIME': [null, Order.NONE, Order.UNARY_POSTFIX], }; - const dropdownProperty = block.getFieldValue('PROPERTY'); + type PropertyOption = keyof typeof PROPERTIES; + const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', - inputOrder) || '0'; + const numberToCheck = + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = generator.provideFunction_('math_isPrime', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'math_isPrime', + ` bool ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if (n == 2 || n == 3) { @@ -202,11 +228,12 @@ bool ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { } return true; } -`); +`, + ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MULTIPLICATIVE) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; } @@ -215,72 +242,97 @@ bool ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) { code = numberToCheck + suffix; } return [code, outputOrder]; -}; +} -export function math_change(block, generator) { +export function math_change(block: Block, generator: DartGenerator) { // Add to a variable in place. const argument0 = - generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = (' + varName + ' is num ? ' + varName + ' : 0) + ' + - argument0 + ';\n'; -}; + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + return ( + varName + + ' = (' + + varName + + ' is num ? ' + + varName + + ' : 0) + ' + + argument0 + + ';\n' + ); +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list( + block: Block, + generator: DartGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; let code; switch (func) { case 'SUM': { - const functionName = generator.provideFunction_('math_sum', ` + const functionName = generator.provideFunction_( + 'math_sum', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { num sumVal = 0; myList.forEach((num entry) {sumVal += entry;}); return sumVal; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'MIN': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = generator.provideFunction_('math_min', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'math_min', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { if (myList.isEmpty) return null; num minVal = myList[0]; myList.forEach((num entry) {minVal = Math.min(minVal, entry);}); return minVal; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'MAX': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = generator.provideFunction_('math_max', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'math_max', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { if (myList.isEmpty) return null; num maxVal = myList[0]; myList.forEach((num entry) {maxVal = Math.max(maxVal, entry);}); return maxVal; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'AVERAGE': { // This operation exclude null and values that are not int or float: // math_mean([null,null,"aString",1,9]) -> 5.0 - const functionName = generator.provideFunction_('math_mean', ` + const functionName = generator.provideFunction_( + 'math_mean', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only. List localList = new List.from(myList); @@ -290,12 +342,15 @@ num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { localList.forEach((var entry) {sumVal += entry;}); return sumVal / localList.length; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - const functionName = generator.provideFunction_('math_median', ` + const functionName = generator.provideFunction_( + 'math_median', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only, then sort, then return middle value // or the average of two middle values if list has an even number of elements. @@ -310,17 +365,22 @@ num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { return (localList[index - 1] + localList[index]) / 2; } } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'MODE': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1] - const functionName = generator.provideFunction_('math_modes', ` + const functionName = generator.provideFunction_( + 'math_modes', + ` List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List values) { List modes = []; List counts = []; @@ -349,15 +409,19 @@ List ${generator.FUNCTION_NAME_PLACEHOLDER_}(List values) { } return modes; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = - generator.provideFunction_('math_standard_deviation', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'math_standard_deviation', + ` num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { // First filter list for numbers only. List numbers = new List.from(myList); @@ -371,19 +435,25 @@ num ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { numbers.forEach((x) => sumSquare += Math.pow(x - mean, 2)); return Math.sqrt(sumSquare / n); } -`); +`, + ); code = functionName + '(' + list + ')'; break; } case 'RANDOM': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = generator.provideFunction_('math_random_item', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'math_random_item', + ` dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { int x = new Math.Random().nextInt(myList.length); return myList[x]; } -`); +`, + ); code = functionName + '(' + list + ')'; break; } @@ -391,39 +461,59 @@ dynamic ${generator.FUNCTION_NAME_PLACEHOLDER_}(List myList) { throw Error('Unknown operator: ' + func); } return [code, Order.UNARY_POSTFIX]; -}; +} -export function math_modulo(block, generator) { +export function math_modulo( + block: Block, + generator: DartGenerator, +): [string, Order] { // Remainder computation. const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; -}; +} -export function math_constrain(block, generator) { +export function math_constrain( + block: Block, + generator: DartGenerator, +): [string, Order] { // Constrain a number between two limits. - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const argument0 = - generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - generator.valueToCode(block, 'HIGH', Order.NONE) || 'double.infinity'; - const code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + - argument2 + ')'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'double.infinity'; + const code = + 'Math.min(Math.max(' + + argument0 + + ', ' + + argument1 + + '), ' + + argument2 + + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function math_random_int(block, generator) { +export function math_random_int( + block: Block, + generator: DartGenerator, +): [string, Order] { // Random integer between [X] and [Y]. - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; - const functionName = generator.provideFunction_('math_random_int', ` + const functionName = generator.provideFunction_( + 'math_random_int', + ` int ${generator.FUNCTION_NAME_PLACEHOLDER_}(num a, num b) { if (a > b) { // Swap a and b to ensure a is smaller. @@ -433,26 +523,37 @@ int ${generator.FUNCTION_NAME_PLACEHOLDER_}(num a, num b) { } return new Math.Random().nextInt(b - a + 1) + a; } -`); +`, + ); const code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function math_random_float(block, generator) { +export function math_random_float( + block: Block, + generator: DartGenerator, +): [string, Order] { // Random fraction between 0 and 1. - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; return ['new Math.Random().nextDouble()', Order.UNARY_POSTFIX]; -}; +} -export function math_atan2(block, generator) { +export function math_atan2( + block: Block, + generator: DartGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'Math.atan2(' + argument1 + ', ' + argument0 + ') / Math.pi * 180', - Order.MULTIPLICATIVE + Order.MULTIPLICATIVE, ]; -}; +} diff --git a/generators/dart/procedures.js b/generators/dart/procedures.ts similarity index 60% rename from generators/dart/procedures.js rename to generators/dart/procedures.ts index e782abb68..934e52318 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.ts @@ -10,13 +10,14 @@ // Former goog.module ID: Blockly.Dart.procedures +import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; +import type {DartGenerator} from './dart_generator.js'; import {Order} from './dart_generator.js'; - -export function procedures_defreturn(block, generator) { +export function procedures_defreturn(block: Block, generator: DartGenerator) { // Define a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); @@ -30,12 +31,12 @@ export function procedures_defreturn(block, generator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId(generator.INFINITE_LOOP_TRAP, block), - generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } const branch = generator.statementToCode(block, 'STACK'); - let returnValue = - generator.valueToCode(block, 'RETURN', Order.NONE) || ''; + let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. @@ -50,22 +51,37 @@ export function procedures_defreturn(block, generator) { for (let i = 0; i < variables.length; i++) { args[i] = generator.getVariableName(variables[i]); } - let code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' + - xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; + let code = + returnType + + ' ' + + funcName + + '(' + + args.join(', ') + + ') {\n' + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue + + '}'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn( + block: Block, + generator: DartGenerator, +): [string, Order] { // Call a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { @@ -73,35 +89,41 @@ export function procedures_callreturn(block, generator) { } let code = funcName + '(' + args.join(', ') + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn( + block: Block, + generator: DartGenerator, +) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn']( + block, + generator, + ) as [string, Order]; return tuple[0] + ';\n'; -}; +} -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn(block: Block, generator: DartGenerator) { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. code += generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), generator.INDENT); + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } - if (block.hasReturnValue_) { - const value = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; + if ((block as IfReturnBlock).hasReturnValue_) { + const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; code += generator.INDENT + 'return ' + value + ';\n'; } else { code += generator.INDENT + 'return;\n'; } code += '}\n'; return code; -}; +} diff --git a/generators/dart/text.js b/generators/dart/text.ts similarity index 61% rename from generators/dart/text.js rename to generators/dart/text.ts index 69ffbf7df..e8c9be637 100644 --- a/generators/dart/text.js +++ b/generators/dart/text.ts @@ -10,92 +10,111 @@ // Former goog.module ID: Blockly.Dart.texts +import type {Block} from '../../core/block.js'; +import type {DartGenerator} from './dart_generator.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; import {Order} from './dart_generator.js'; - // RESERVED WORDS: 'Html,Math' -export function text(block, generator) { +export function text(block: Block, generator: DartGenerator): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block, generator) { +export function text_multiline( + block: Block, + generator: DartGenerator, +): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; + const order = code.indexOf('+') !== -1 ? Order.ADDITIVE : Order.ATOMIC; return [code, order]; -}; +} -export function text_join(block, generator) { +export function text_join( + block: Block, + generator: DartGenerator, +): [string, Order] { // Create a string made up of any number of elements of any type. - switch (block.itemCount_) { + const joinBlock = block as JoinMutatorBlock; + switch (joinBlock.itemCount_) { case 0: return ["''", Order.ATOMIC]; case 1: { const element = - generator.valueToCode(block, 'ADD0', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'ADD0', Order.UNARY_POSTFIX) || "''"; const code = element + '.toString()'; return [code, Order.UNARY_POSTFIX]; } default: { - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { + const elements = new Array(joinBlock.itemCount_); + for (let i = 0; i < joinBlock.itemCount_; i++) { elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = '[' + elements.join(',') + '].join()'; return [code, Order.UNARY_POSTFIX]; } } -}; +} -export function text_append(block, generator) { +export function text_append(block: Block, generator: DartGenerator) { // Append to a variable in place. - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + const varName = generator.getVariableName(block.getFieldValue('VAR')); const value = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return varName + ' = [' + varName + ', ' + value + '].join();\n'; -}; +} -export function text_length(block, generator) { +export function text_length( + block: Block, + generator: DartGenerator, +): [string, Order] { // String or array length. const text = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; return [text + '.length', Order.UNARY_POSTFIX]; -}; +} -export function text_isEmpty(block, generator) { +export function text_isEmpty( + block: Block, + generator: DartGenerator, +): [string, Order] { // Is the string null or array empty? const text = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; return [text + '.isEmpty', Order.UNARY_POSTFIX]; -}; +} -export function text_indexOf(block, generator) { +export function text_indexOf( + block: Block, + generator: DartGenerator, +): [string, Order] { // Search the text for a substring. const operator = - block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; - const substring = - generator.valueToCode(block, 'FIND', Order.NONE) || "''"; + block.getFieldValue('END') === 'FIRST' ? 'indexOf' : 'lastIndexOf'; + const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = - generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'VALUE', Order.UNARY_POSTFIX) || "''"; const code = text + '.' + operator + '(' + substring + ')'; if (block.workspace.options.oneBasedIndex) { return [code + ' + 1', Order.ADDITIVE]; } return [code, Order.UNARY_POSTFIX]; -}; +} -export function text_charAt(block, generator) { +export function text_charAt( + block: Block, + generator: DartGenerator, +): [string, Order] { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = (where === 'FIRST' || where === 'FROM_START') ? - Order.UNARY_POSTFIX : - Order.NONE; + const textOrder = + where === 'FIRST' || where === 'FROM_START' + ? Order.UNARY_POSTFIX + : Order.NONE; const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; let at; switch (where) { @@ -110,41 +129,50 @@ export function text_charAt(block, generator) { } case 'LAST': at = 1; - // Fall through. + // Fall through. case 'FROM_END': { at = generator.getAdjusted(block, 'AT', 1); - const functionName = generator.provideFunction_('text_get_from_end', ` + const functionName = generator.provideFunction_( + 'text_get_from_end', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text, num x) { return text[text.length - x]; } -`); +`, + ); const code = functionName + '(' + text + ', ' + at + ')'; return [code, Order.UNARY_POSTFIX]; } case 'RANDOM': { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; - const functionName = - generator.provideFunction_('text_random_letter', ` + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; + const functionName = generator.provideFunction_( + 'text_random_letter', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text) { int x = new Math.Random().nextInt(text.length); return text[x]; } -`); +`, + ); const code = functionName + '(' + text + ')'; return [code, Order.UNARY_POSTFIX]; } } throw Error('Unhandled option (text_charAt).'); -}; +} -export function text_getSubstring(block, generator) { +export function text_getSubstring( + block: Block, + generator: DartGenerator, +): [string, Order] { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); - const requiresLengthCall = (where1 !== 'FROM_END' && where2 === 'FROM_START'); - const textOrder = - requiresLengthCall ? Order.UNARY_POSTFIX : Order.NONE; + const requiresLengthCall = where1 !== 'FROM_END' && where2 === 'FROM_START'; + const textOrder = requiresLengthCall ? Order.UNARY_POSTFIX : Order.NONE; const text = generator.valueToCode(block, 'STRING', textOrder) || "''"; let code; if (where1 === 'FIRST' && where2 === 'LAST') { @@ -191,8 +219,9 @@ export function text_getSubstring(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = - generator.provideFunction_('text_get_substring', ` + const functionName = generator.provideFunction_( + 'text_get_substring', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text, String where1, num at1, String where2, num at2) { int getAt(String where, num at) { if (where == 'FROM_END') { @@ -210,21 +239,37 @@ String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String text, String where1, num a at2 = getAt(where2, at2) + 1; return text.substring(at1, at2); } -`); - code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 + ', \'' + - where2 + '\', ' + at2 + ')'; +`, + ); + code = + functionName + + '(' + + text + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; } return [code, Order.UNARY_POSTFIX]; -}; +} -export function text_changeCase(block, generator) { +export function text_changeCase( + block: Block, + generator: DartGenerator, +): [string, Order] { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.toUpperCase()', 'LOWERCASE': '.toLowerCase()', - 'TITLECASE': null + 'TITLECASE': null, }; - const operator = OPERATORS[block.getFieldValue('CASE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('CASE') as OperatorOption]; const textOrder = operator ? Order.UNARY_POSTFIX : Order.NONE; const text = generator.valueToCode(block, 'TEXT', textOrder) || "''"; let code; @@ -233,7 +278,9 @@ export function text_changeCase(block, generator) { code = text + operator; } else { // Title case is not a native generator function. Define one. - const functionName = generator.provideFunction_('text_toTitleCase', ` + const functionName = generator.provideFunction_( + 'text_toTitleCase', + ` String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String str) { RegExp exp = new RegExp(r'\\b'); List list = str.split(exp); @@ -248,35 +295,45 @@ String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String str) { } return title.toString(); } -`); +`, + ); code = functionName + '(' + text + ')'; } return [code, Order.UNARY_POSTFIX]; -}; +} -export function text_trim(block, generator) { +export function text_trim( + block: Block, + generator: DartGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = { - 'LEFT': '.replaceFirst(new RegExp(r\'^\\s+\'), \'\')', - 'RIGHT': '.replaceFirst(new RegExp(r\'\\s+$\'), \'\')', - 'BOTH': '.trim()' + 'LEFT': ".replaceFirst(new RegExp(r'^\\s+'), '')", + 'RIGHT': ".replaceFirst(new RegExp(r'\\s+$'), '')", + 'BOTH': '.trim()', }; - const operator = OPERATORS[block.getFieldValue('MODE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = - generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; return [text + operator, Order.UNARY_POSTFIX]; -}; +} -export function text_print(block, generator) { +export function text_print(block: Block, generator: DartGenerator) { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; -}; +} -export function text_prompt_ext(block, generator) { +export function text_prompt_ext( + block: Block, + generator: DartGenerator, +): [string, Order] { // Prompt function. - generator.definitions_['import_dart_html'] = - 'import \'dart:html\' as Html;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_html'] = + "import 'dart:html' as Html;"; let msg; if (block.getField('TEXT')) { // Internal message. @@ -285,23 +342,30 @@ export function text_prompt_ext(block, generator) { // External message. msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } - let code = 'Html.window.prompt(' + msg + ', \'\')'; + let code = 'Html.window.prompt(' + msg + ", '')"; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; if (toNumber) { - generator.definitions_['import_dart_math'] = - 'import \'dart:math\' as Math;'; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['import_dart_math'] = + "import 'dart:math' as Math;"; code = 'Math.parseDouble(' + code + ')'; } return [code, Order.UNARY_POSTFIX]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { +export function text_count( + block: Block, + generator: DartGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; // Substring count is not a native generator function. Define one. - const functionName = generator.provideFunction_('text_count', ` + const functionName = generator.provideFunction_( + 'text_count', + ` int ${generator.FUNCTION_NAME_PLACEHOLDER_}(String haystack, String needle) { if (needle.length == 0) { return haystack.length + 1; @@ -317,26 +381,33 @@ int ${generator.FUNCTION_NAME_PLACEHOLDER_}(String haystack, String needle) { } return count; } -`); +`, + ); const code = functionName + '(' + text + ', ' + sub + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function text_replace(block, generator) { +export function text_replace( + block: Block, + generator: DartGenerator, +): [string, Order] { const text = - generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = text + '.replaceAll(' + from + ', ' + to + ')'; return [code, Order.UNARY_POSTFIX]; -}; +} -export function text_reverse(block, generator) { +export function text_reverse( + block: Block, + generator: DartGenerator, +): [string, Order] { // There isn't a sensible way to do this in generator. See: // http://stackoverflow.com/a/21613700/3529104 // Implementing something is possibly better than not implementing anything? const text = - generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; + generator.valueToCode(block, 'TEXT', Order.UNARY_POSTFIX) || "''"; const code = 'new String.fromCharCodes(' + text + '.runes.toList().reversed)'; return [code, Order.UNARY_PREFIX]; -}; +} diff --git a/generators/dart/variables.js b/generators/dart/variables.js deleted file mode 100644 index c08843760..000000000 --- a/generators/dart/variables.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright 2014 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Generating Dart for variable blocks. - */ - -// Former goog.module ID: Blockly.Dart.variables - -import {Order} from './dart_generator.js'; - - -export function variables_get(block, generator) { - // Variable getter. - const code = - generator.getVariableName(block.getFieldValue('VAR')); - return [code, Order.ATOMIC]; -}; - -export function variables_set(block, generator) { - // Variable setter. - const argument0 = - generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = ' + argument0 + ';\n'; -}; diff --git a/generators/dart/variables.ts b/generators/dart/variables.ts new file mode 100644 index 000000000..1910befc9 --- /dev/null +++ b/generators/dart/variables.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2014 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Generating Dart for variable blocks. + */ + +// Former goog.module ID: Blockly.Dart.variables + +import type {Block} from '../../core/block.js'; +import type {DartGenerator} from './dart_generator.js'; +import {Order} from './dart_generator.js'; + +export function variables_get( + block: Block, + generator: DartGenerator, +): [string, Order] { + // Variable getter. + const code = generator.getVariableName(block.getFieldValue('VAR')); + return [code, Order.ATOMIC]; +} + +export function variables_set(block: Block, generator: DartGenerator) { + // Variable setter. + const argument0 = + generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + return varName + ' = ' + argument0 + ';\n'; +} diff --git a/generators/dart/variables_dynamic.js b/generators/dart/variables_dynamic.ts similarity index 99% rename from generators/dart/variables_dynamic.js rename to generators/dart/variables_dynamic.ts index 22be966dc..6a92fff91 100644 --- a/generators/dart/variables_dynamic.js +++ b/generators/dart/variables_dynamic.ts @@ -10,7 +10,6 @@ // Former goog.module ID: Blockly.Dart.variablesDynamic - // generator is dynamically typed. export { variables_get as variables_get_dynamic, diff --git a/generators/javascript/lists.ts b/generators/javascript/lists.ts index 6283f1d27..0a1fcc87f 100644 --- a/generators/javascript/lists.ts +++ b/generators/javascript/lists.ts @@ -29,8 +29,8 @@ export function lists_create_with( block: Block, generator: JavascriptGenerator, ): [string, Order] { - const createWithBlock = block as CreateWithBlock; // Create a list with any number of elements of any type. + const createWithBlock = block as CreateWithBlock; const elements = new Array(createWithBlock.itemCount_); for (let i = 0; i < createWithBlock.itemCount_; i++) { elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; diff --git a/generators/javascript/logic.ts b/generators/javascript/logic.ts index 36604ea7d..bdc51f997 100644 --- a/generators/javascript/logic.ts +++ b/generators/javascript/logic.ts @@ -63,7 +63,7 @@ export function logic_compare( block: Block, generator: JavascriptGenerator, ): [string, Order] { - // Dictionary of OP comparison operators and their implementations. + // Comparison operator. const OPERATORS = { 'EQ': '==', 'NEQ': '!=', diff --git a/generators/javascript/text.ts b/generators/javascript/text.ts index 79008cba9..7e3b0e4c1 100644 --- a/generators/javascript/text.ts +++ b/generators/javascript/text.ts @@ -11,8 +11,8 @@ // Former goog.module ID: Blockly.JavaScript.texts import type {Block} from '../../core/block.js'; -import type {JoinMutatorBlock} from '../../blocks/text.js'; import type {JavascriptGenerator} from './javascript_generator.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; import {Order} from './javascript_generator.js'; /** @@ -80,8 +80,8 @@ export function text_join( block: Block, generator: JavascriptGenerator, ): [string, Order] { - const joinBlock = block as JoinMutatorBlock; // Create a string made up of any number of elements of any type. + const joinBlock = block as JoinMutatorBlock; switch (joinBlock.itemCount_) { case 0: return ["''", Order.ATOMIC]; diff --git a/generators/python/lists.ts b/generators/python/lists.ts index 02bd56ee5..7577cc417 100644 --- a/generators/python/lists.ts +++ b/generators/python/lists.ts @@ -29,8 +29,8 @@ export function lists_create_with( block: Block, generator: PythonGenerator, ): [string, Order] { - const createWithBlock = block as CreateWithBlock; // Create a list with any number of elements of any type. + const createWithBlock = block as CreateWithBlock; const elements = new Array(createWithBlock.itemCount_); for (let i = 0; i < createWithBlock.itemCount_; i++) { elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; diff --git a/generators/python/text.ts b/generators/python/text.ts index dca9e9832..7b554efda 100644 --- a/generators/python/text.ts +++ b/generators/python/text.ts @@ -61,9 +61,9 @@ export function text_join( block: Block, generator: PythonGenerator, ): [string, Order] { - const joinBlock = block as JoinMutatorBlock; // Create a string made up of any number of elements of any type. // Should we allow joining by '-' or ',' or any other characters? + const joinBlock = block as JoinMutatorBlock; switch (joinBlock.itemCount_) { case 0: return ["''", Order.ATOMIC]; From bf91422c980c408fb07a136f7bfb451b701f47cc Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Fri, 17 Nov 2023 15:22:48 -0800 Subject: [PATCH 59/86] chore: run build before and during interactive mocha (#7651) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4428b0b5c..a82008d76 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "test": "gulp test", "test:browser": "cd tests/browser && npx mocha", "test:generators": "gulp testGenerators", - "test:mocha:interactive": "http-server ./ -o /tests/mocha/index.html -c-1", + "test:mocha:interactive": "npm run build && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"http-server ./ -o /tests/mocha/index.html -c-1\"", "test:compile:advanced": "gulp buildAdvancedCompilationTest --debug", "updateGithubPages": "npm ci && gulp gitUpdateGithubPages" }, From e6de8581dd8a2e8587c7dac73a86d26b23ff4757 Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Fri, 17 Nov 2023 15:58:35 -0800 Subject: [PATCH 60/86] fix: disabled render status after serialization (#7650) * fix: disabled render status after serialization * chore: format * chore: better names * chore: format --- core/block_svg.ts | 5 ++ core/serialization/blocks.ts | 1 - core/xml.ts | 1 - tests/mocha/block_test.js | 138 ++++++++++++++++++++++++++++++++++- 4 files changed, 139 insertions(+), 6 deletions(-) diff --git a/core/block_svg.ts b/core/block_svg.ts index 2ec157fa8..2655642d7 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -1623,6 +1623,11 @@ export class BlockSvg if (this.isCollapsed()) { this.updateCollapsed_(); } + + if (!this.isEnabled()) { + this.updateDisabled(); + } + this.workspace.getRenderer().render(this); this.tightenChildrenEfficiently(); diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index 498f6000c..229686a0d 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -733,7 +733,6 @@ function initBlock(block: Block, rendered: boolean) { blockSvg.initSvg(); blockSvg.queueRender(); - blockSvg.updateDisabled(); // fixes #6076 JSO deserialization doesn't // set .iconXY_ property so here it will be set diff --git a/core/xml.ts b/core/xml.ts index ca8f6c8f4..c3b2d3ebc 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -592,7 +592,6 @@ export function domToBlockInternal( topBlockSvg.setConnectionTracking(true); } }, 1); - topBlockSvg.updateDisabled(); // Allow the scrollbars to resize and move based on the new contents. // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. (workspace as WorkspaceSvg).resizeContents(); diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index 2cf50fea0..f5b2e6a82 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -2242,21 +2242,151 @@ suite('Blocks', function () { chai.assert.isTrue(blockB.disabled); }); test('Disabled blocks from JSON should have proper disabled status', function () { + // Nested c-shaped blocks, inner block is disabled const blockJson = { 'type': 'controls_if', - 'enabled': false, + 'inputs': { + 'DO0': { + 'block': { + 'type': 'controls_if', + 'enabled': false, + }, + }, + }, }; Blockly.serialization.blocks.append(blockJson, this.workspace); - const block = this.workspace.getTopBlocks(false)[0]; + const innerBlock = this.workspace + .getTopBlocks(false)[0] + .getChildren()[0]; chai.assert.isTrue( - block.visuallyDisabled, + innerBlock.visuallyDisabled, 'block should have visuallyDisabled set because it is disabled', ); chai.assert.isFalse( - block.isEnabled(), + innerBlock.isEnabled(), 'block should be marked disabled because enabled json property was set to false', ); }); + test('Disabled blocks from XML should have proper disabled status', function () { + // Nested c-shaped blocks, inner block is disabled + const blockXml = ` + + + + + + `; + Blockly.Xml.domToWorkspace( + Blockly.utils.xml.textToDom(blockXml), + this.workspace, + ); + const innerBlock = this.workspace + .getTopBlocks(false)[0] + .getChildren()[0]; + chai.assert.isTrue( + innerBlock.visuallyDisabled, + 'block should have visuallyDisabled set because it is disabled', + ); + chai.assert.isFalse( + innerBlock.isEnabled(), + 'block should be marked disabled because enabled xml property was set to false', + ); + }); + suite('Disabling blocks with children and neighbors', function () { + setup(function () { + // c-shape block with a stack of 4 blocks in the input + const blockJson = { + 'type': 'controls_if', + 'id': 'parent', + 'inputs': { + 'DO0': { + 'block': { + 'type': 'controls_repeat_ext', + 'id': 'child1', + 'next': { + 'block': { + 'type': 'controls_for', + 'id': 'child2', + 'enabled': false, + 'next': { + 'block': { + 'type': 'controls_whileUntil', + 'id': 'child3', + 'next': { + 'block': { + 'type': 'controls_forEach', + 'id': 'child4', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }; + Blockly.serialization.blocks.append(blockJson, this.workspace); + this.parent = this.workspace.getBlockById('parent'); + this.child1 = this.workspace.getBlockById('child1'); + this.child2 = this.workspace.getBlockById('child2'); + this.child3 = this.workspace.getBlockById('child3'); + this.child4 = this.workspace.getBlockById('child4'); + }); + test('Disabling parent block visually disables all descendants', async function () { + this.parent.setEnabled(false); + await Blockly.renderManagement.finishQueuedRenders(); + for (const child of this.parent.getDescendants(false)) { + chai.assert.isTrue( + child.visuallyDisabled, + `block ${child.id} should be visually disabled`, + ); + } + }); + test('Child blocks regain original status after parent is re-enabled', async function () { + this.parent.setEnabled(false); + await Blockly.renderManagement.finishQueuedRenders(); + this.parent.setEnabled(true); + await Blockly.renderManagement.finishQueuedRenders(); + + // child2 is disabled, rest should be enabled + chai.assert.isTrue( + this.child1.isEnabled(), + 'child1 should be enabled', + ); + chai.assert.isFalse( + this.child1.visuallyDisabled, + 'child1 should not be visually disabled', + ); + + chai.assert.isFalse( + this.child2.isEnabled(), + 'child2 should be disabled', + ); + chai.assert.isTrue( + this.child2.visuallyDisabled, + 'child2 should be visually disabled', + ); + + chai.assert.isTrue( + this.child3.isEnabled(), + 'child3 should be enabled', + ); + chai.assert.isFalse( + this.child3.visuallyDisabled, + 'child3 should not be visually disabled', + ); + + chai.assert.isTrue( + this.child4.isEnabled(), + 'child34 should be enabled', + ); + chai.assert.isFalse( + this.child4.visuallyDisabled, + 'child4 should not be visually disabled', + ); + }); + }); }); }); From 149f95ecb4681ccc81d439cc4686ef12bded23ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:29:29 -0800 Subject: [PATCH 61/86] chore(deps): Bump @blockly/dev-tools from 7.1.0 to 7.1.3 (#7657) Bumps [@blockly/dev-tools](https://github.com/google/blockly-samples/tree/HEAD/plugins/dev-tools) from 7.1.0 to 7.1.3. - [Release notes](https://github.com/google/blockly-samples/releases) - [Changelog](https://github.com/google/blockly-samples/blob/master/plugins/dev-tools/CHANGELOG.md) - [Commits](https://github.com/google/blockly-samples/commits/@blockly/dev-tools@7.1.3/plugins/dev-tools) --- updated-dependencies: - dependency-name: "@blockly/dev-tools" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index d492655b3..de6a4501d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -253,9 +253,9 @@ } }, "node_modules/@blockly/block-test": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-5.0.2.tgz", - "integrity": "sha512-oZUc7DAdZZcYLUmx6Rqq9VkTyTj0vR9rrExmI6dqiOV0Jip12/244e05HrGQioz2MMN1xmsU8LmM89NnTj6uzw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-5.0.3.tgz", + "integrity": "sha512-iY8aIh+rTJGZMT/mvEeqjRXAlN7jOso/kQsQ5BrdyH+8UEQ+K4IJdjyFou18ydktnfpeXnBkqw6P4wzc/0jtcA==", "dev": true, "engines": { "node": ">=8.17.0" @@ -265,16 +265,16 @@ } }, "node_modules/@blockly/dev-tools": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-7.1.0.tgz", - "integrity": "sha512-6Z3RfYcFRWhVhSjOwnE3vFr5xPW7WPQb2POjOCzvaPoevHZf7mSkCAOcyuNck5gLCms9TK96B1ezzimMAuo8Sg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-7.1.3.tgz", + "integrity": "sha512-KdC9ZUwnuzqYNaxAHgj2pFEgtCMhf/w8u5wNHUScReLWXPqc9wQSIUCq6QsDbN1EiT6BaL8dYwqcHoLl+fgUXA==", "dev": true, "dependencies": { - "@blockly/block-test": "^5.0.0", - "@blockly/theme-dark": "^6.0.1", - "@blockly/theme-deuteranopia": "^5.0.1", - "@blockly/theme-highcontrast": "^5.0.1", - "@blockly/theme-tritanopia": "^5.0.1", + "@blockly/block-test": "^5.0.3", + "@blockly/theme-dark": "^6.0.4", + "@blockly/theme-deuteranopia": "^5.0.4", + "@blockly/theme-highcontrast": "^5.0.4", + "@blockly/theme-tritanopia": "^5.0.4", "chai": "^4.2.0", "dat.gui": "^0.7.7", "lodash.assign": "^4.2.0", @@ -290,9 +290,9 @@ } }, "node_modules/@blockly/theme-dark": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-6.0.1.tgz", - "integrity": "sha512-fZa834SKstG31PNkoZ26DLIpevNVBWLDwDT/g99a6EtwqnkZg2VjCjbJDLA0xzrCmxN8AH6zmZU/lAdMoBH8sw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-6.0.4.tgz", + "integrity": "sha512-G0A+9cMlMiv0/H6/FjQTK+tsqXLmR/FGAfO4gByaTt/ocBmOFeoSlQZdTI23L9ZEvnfO11ZaqH6pqUxY0GSusw==", "dev": true, "engines": { "node": ">=8.17.0" @@ -302,9 +302,9 @@ } }, "node_modules/@blockly/theme-deuteranopia": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-5.0.1.tgz", - "integrity": "sha512-xGBYGkr170VzODnio41UOZwDSjUofbNWiJwTSA5rm3jbWyeeERL8raCPJN+AB3kZ8Vfvt6BSUBobYGKcsxFGNw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-5.0.4.tgz", + "integrity": "sha512-QzJN/2MFtXAdeGFT77fVnQAHYVAn3+HBPI9UPvzhu2l6Tod9v6pnrQ51+8Xiw/wGTklFeZzModJkajCnb6RDCg==", "dev": true, "engines": { "node": ">=8.17.0" @@ -314,9 +314,9 @@ } }, "node_modules/@blockly/theme-highcontrast": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-5.0.1.tgz", - "integrity": "sha512-090W+FL4mCwf3fEasERHmypJbYdoP1zjlPnnDsrvkXw5EoSEY6b8PhIgzD63JeZMjWOFjWyCgoZWsBvI9IbVCA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-5.0.4.tgz", + "integrity": "sha512-JFSYmEzGeh3KdUqZLScktdFRTxgYoTqLWIeBLOWEU1AFoFMUbKN8G2ChW3Rzq5snbu3pHNBsisswMEp/vuRbUw==", "dev": true, "engines": { "node": ">=8.17.0" @@ -338,9 +338,9 @@ } }, "node_modules/@blockly/theme-tritanopia": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-5.0.1.tgz", - "integrity": "sha512-0cfmzjb/2aCga16CO1QDjKxoOwucU29v9P+Dwgr16j8IoNKpFOUnnN2xt7yYw4CeJaOVGZEcHljjzgU52oRPXA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-5.0.4.tgz", + "integrity": "sha512-ex4WlFLidLNY0Zpvf18ZOnBrQ7HRnupvumpajVmpEVhnm1O7h6H6IdHCgBvL4hFb72q+7/xKxAkxG0+lSfih1w==", "dev": true, "engines": { "node": ">=8.17.0" From dc61e487b4e0024a53866e8aff652c0b108a0340 Mon Sep 17 00:00:00 2001 From: Blake Thomas Williams <49404493+btw17@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:46:32 -0600 Subject: [PATCH 62/86] refactor(generators): Migrate Lua generators to TypeScript (#7654) * refactor(generators): Migrate lua_generator.js to TypeScript * refactor(generators): Migrate generators/lua/* to TypeScript * fix(generators): Fix type errors in generator functions * refactor(generators): Migrate generators/lua.js to TypeScript * chore(generator): Format * chore(generators): JSDoc and formatting tweaks for PR #7654 --------- Co-authored-by: Christopher Allen --- generators/{lua.js => lua.ts} | 23 +- generators/lua/{colour.js => colour.ts} | 53 +++- generators/lua/{lists.js => lists.ts} | 299 ++++++++++++------ generators/lua/{logic.js => logic.ts} | 103 +++--- generators/lua/{loops.js => loops.ts} | 97 +++--- .../{lua_generator.js => lua_generator.ts} | 175 +++++----- generators/lua/{math.js => math.ts} | 194 ++++++++---- .../lua/{procedures.js => procedures.ts} | 80 +++-- generators/lua/{text.js => text.ts} | 198 ++++++++---- generators/lua/variables.js | 29 -- generators/lua/variables.ts | 31 ++ ...iables_dynamic.js => variables_dynamic.ts} | 3 +- 12 files changed, 813 insertions(+), 472 deletions(-) rename generators/{lua.js => lua.ts} (72%) rename generators/lua/{colour.js => colour.ts} (68%) rename generators/lua/{lists.js => lists.ts} (59%) rename generators/lua/{logic.js => logic.ts} (51%) rename generators/lua/{loops.js => loops.ts} (70%) rename generators/lua/{lua_generator.js => lua_generator.ts} (50%) rename generators/lua/{math.js => math.ts} (75%) rename generators/lua/{procedures.js => procedures.ts} (61%) rename generators/lua/{text.js => text.ts} (69%) delete mode 100644 generators/lua/variables.js create mode 100644 generators/lua/variables.ts rename generators/lua/{variables_dynamic.js => variables_dynamic.ts} (82%) diff --git a/generators/lua.js b/generators/lua.ts similarity index 72% rename from generators/lua.js rename to generators/lua.ts index a4b8b1a51..5c5b0af00 100644 --- a/generators/lua.js +++ b/generators/lua.ts @@ -5,9 +5,8 @@ */ /** - * @fileoverview Complete helper functions for generating Lua for + * @file Complete helper functions for generating Lua for * blocks. This is the entrypoint for lua_compressed.js. - * @suppress {extraRequire} */ // Former goog.module ID: Blockly.Lua.all @@ -27,13 +26,21 @@ export * from './lua/lua_generator.js'; /** * Lua code generator instance. - * @type {!LuaGenerator} */ export const luaGenerator = new LuaGenerator(); // Install per-block-type generator functions: -Object.assign( - luaGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +const generators: typeof luaGenerator.forBlock = { + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, +}; +for (const name in generators) { + luaGenerator.forBlock[name] = generators[name]; +} diff --git a/generators/lua/colour.js b/generators/lua/colour.ts similarity index 68% rename from generators/lua/colour.js rename to generators/lua/colour.ts index b9298e345..f4a6a8ea9 100644 --- a/generators/lua/colour.js +++ b/generators/lua/colour.ts @@ -5,46 +5,64 @@ */ /** - * @fileoverview Generating Lua for colour blocks. + * @file Generating Lua for colour blocks. */ // Former goog.module ID: Blockly.Lua.colour +import type {Block} from '../../core/block.js'; +import type {LuaGenerator} from './lua_generator.js'; import {Order} from './lua_generator.js'; - -export function colour_picker(block, generator) { +export function colour_picker( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block, generator) { +export function colour_random( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Generate a random colour. const code = 'string.format("#%06x", math.random(0, 2^24 - 1))'; return [code, Order.HIGH]; -}; +} -export function colour_rgb(block, generator) { +export function colour_rgb( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. - const functionName = generator.provideFunction_('colour_rgb', ` + const functionName = generator.provideFunction_( + 'colour_rgb', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) r = math.floor(math.min(100, math.max(0, r)) * 2.55 + .5) g = math.floor(math.min(100, math.max(0, g)) * 2.55 + .5) b = math.floor(math.min(100, math.max(0, b)) * 2.55 + .5) return string.format("#%02x%02x%02x", r, g, b) end -`); +`, + ); const r = generator.valueToCode(block, 'RED', Order.NONE) || 0; const g = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; const b = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; const code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; return [code, Order.HIGH]; -}; +} -export function colour_blend(block, generator) { +export function colour_blend( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Blend two colours together. - const functionName = generator.provideFunction_('colour_blend', ` + const functionName = generator.provideFunction_( + 'colour_blend', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio) local r1 = tonumber(string.sub(colour1, 2, 3), 16) local r2 = tonumber(string.sub(colour2, 2, 3), 16) @@ -58,13 +76,14 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio) local b = math.floor(b1 * (1 - ratio) + b2 * ratio + .5) return string.format("#%02x%02x%02x", r, g, b) end -`); +`, + ); const colour1 = - generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; const colour2 = - generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0; const code = - functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; + functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; return [code, Order.HIGH]; -}; +} diff --git a/generators/lua/lists.js b/generators/lua/lists.ts similarity index 59% rename from generators/lua/lists.js rename to generators/lua/lists.ts index 1402a54c6..1af18b955 100644 --- a/generators/lua/lists.js +++ b/generators/lua/lists.ts @@ -5,34 +5,48 @@ */ /** - * @fileoverview Generating Lua for list blocks. + * @file Generating Lua for list blocks. */ // Former goog.module ID: Blockly.Lua.lists +import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; +import type {LuaGenerator} from './lua_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './lua_generator.js'; - -export function lists_create_empty(block, generator) { +export function lists_create_empty( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Create an empty list. return ['{}', Order.HIGH]; -}; +} -export function lists_create_with(block, generator) { +export function lists_create_with( + block: Block, + generator: LuaGenerator, +): [string, Order] { + const createWithBlock = block as CreateWithBlock; // Create a list with any number of elements of any type. - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None'; + generator.valueToCode(createWithBlock, 'ADD' + i, Order.NONE) || 'None'; } const code = '{' + elements.join(', ') + '}'; return [code, Order.HIGH]; -}; +} -export function lists_repeat(block, generator) { +export function lists_repeat( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Create a list with one element repeated. - const functionName = generator.provideFunction_('create_list_repeated', ` + const functionName = generator.provideFunction_( + 'create_list_repeated', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(item, count) local t = {} for i = 1, count do @@ -40,33 +54,45 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(item, count) end return t end - `); + `, + ); const element = generator.valueToCode(block, 'ITEM', Order.NONE) || 'None'; const repeatCount = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = functionName + '(' + element + ', ' + repeatCount + ')'; return [code, Order.HIGH]; -}; +} -export function lists_length(block, generator) { +export function lists_length( + block: Block, + generator: LuaGenerator, +): [string, Order] { // String or array length. const list = generator.valueToCode(block, 'VALUE', Order.UNARY) || '{}'; return ['#' + list, Order.UNARY]; -}; +} -export function lists_isEmpty(block, generator) { +export function lists_isEmpty( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Is the string null or array empty? const list = generator.valueToCode(block, 'VALUE', Order.UNARY) || '{}'; const code = '#' + list + ' == 0'; return [code, Order.RELATIONAL]; -}; +} -export function lists_indexOf(block, generator) { +export function lists_indexOf( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Find an item in the list. const item = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const list = generator.valueToCode(block, 'VALUE', Order.NONE) || '{}'; let functionName; if (block.getFieldValue('END') === 'FIRST') { - functionName = generator.provideFunction_('first_index', ` + functionName = generator.provideFunction_( + 'first_index', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t, elem) for k, v in ipairs(t) do if v == elem then @@ -75,9 +101,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t, elem) end return 0 end -`); +`, + ); } else { - functionName = generator.provideFunction_('last_index', ` + functionName = generator.provideFunction_( + 'last_index', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t, elem) for i = #t, 1, -1 do if t[i] == elem then @@ -86,20 +115,26 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t, elem) end return 0 end -`); +`, + ); } const code = functionName + '(' + list + ', ' + item + ')'; return [code, Order.HIGH]; -}; +} /** * Returns an expression calculating the index into a list. - * @param {string} listName Name of the list, used to calculate length. - * @param {string} where The method of indexing, selected by dropdown in Blockly - * @param {string=} opt_at The optional offset when indexing from start/end. - * @return {string|undefined} Index expression. + * + * @param listName Name of the list, used to calculate length. + * @param where The method of indexing, selected by dropdown in Blockly + * @param opt_at The optional offset when indexing from start/end. + * @returns Index expression. */ -const getListIndex = function(listName, where, opt_at) { +const getListIndex = function ( + listName: string, + where: string, + opt_at: string, +): string { if (where === 'FIRST') { return '1'; } else if (where === 'FROM_END') { @@ -113,7 +148,10 @@ const getListIndex = function(listName, where, opt_at) { } }; -export function lists_getIndex(block, generator) { +export function lists_getIndex( + block: Block, + generator: LuaGenerator, +): [string, Order] | string { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; @@ -122,19 +160,30 @@ export function lists_getIndex(block, generator) { // If `list` would be evaluated more than once (which is the case for LAST, // FROM_END, and RANDOM) and is non-trivial, make sure to access it only once. - if ((where === 'LAST' || where === 'FROM_END' || where === 'RANDOM') && - !list.match(/^\w+$/)) { + if ( + (where === 'LAST' || where === 'FROM_END' || where === 'RANDOM') && + !list.match(/^\w+$/) + ) { // `list` is an expression, so we may not evaluate it more than once. if (mode === 'REMOVE') { // We can use multiple statements. - const atOrder = - (where === 'FROM_END') ? Order.ADDITIVE : Order.NONE; + const atOrder = where === 'FROM_END' ? Order.ADDITIVE : Order.NONE; let at = generator.valueToCode(block, 'AT', atOrder) || '1'; - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); at = getListIndex(listVar, where, at); - const code = listVar + ' = ' + list + '\n' + - 'table.remove(' + listVar + ', ' + at + ')\n'; + const code = + listVar + + ' = ' + + list + + '\n' + + 'table.remove(' + + listVar + + ', ' + + at + + ')\n'; return code; } else { // We need to create a procedure to avoid reevaluating values. @@ -142,41 +191,49 @@ export function lists_getIndex(block, generator) { let functionName; if (mode === 'GET') { functionName = generator.provideFunction_( - 'list_get_' + where.toLowerCase(), [ - 'function ' + generator.FUNCTION_NAME_PLACEHOLDER_ + '(t' + + 'list_get_' + where.toLowerCase(), + [ + 'function ' + + generator.FUNCTION_NAME_PLACEHOLDER_ + + '(t' + // The value for 'FROM_END' and'FROM_START' depends on `at` so // we add it as a parameter. - ((where === 'FROM_END' || where === 'FROM_START') ? ', at)' : - ')'), - ' return t[' + getListIndex('t', where, 'at') + ']', 'end' - ]); - } else { // `mode` === 'GET_REMOVE' - functionName = - generator.provideFunction_( - 'list_remove_' + where.toLowerCase(), [ - 'function ' + generator.FUNCTION_NAME_PLACEHOLDER_ + '(t' + - // The value for 'FROM_END' and'FROM_START' depends on `at` so - // we add it as a parameter. - ((where === 'FROM_END' || where === 'FROM_START') ? ', at)' : - ')'), - ' return table.remove(t, ' + getListIndex('t', where, 'at') + - ')', - 'end' - ]); + (where === 'FROM_END' || where === 'FROM_START' ? ', at)' : ')'), + ' return t[' + getListIndex('t', where, 'at') + ']', + 'end', + ], + ); + } else { + // `mode` === 'GET_REMOVE' + functionName = generator.provideFunction_( + 'list_remove_' + where.toLowerCase(), + [ + 'function ' + + generator.FUNCTION_NAME_PLACEHOLDER_ + + '(t' + + // The value for 'FROM_END' and'FROM_START' depends on `at` so + // we add it as a parameter. + (where === 'FROM_END' || where === 'FROM_START' ? ', at)' : ')'), + ' return table.remove(t, ' + getListIndex('t', where, 'at') + ')', + 'end', + ], + ); } - const code = functionName + '(' + list + - // The value for 'FROM_END' and 'FROM_START' depends on `at` so we - // pass it. - ((where === 'FROM_END' || where === 'FROM_START') ? ', ' + at : '') + - ')'; + const code = + functionName + + '(' + + list + + // The value for 'FROM_END' and 'FROM_START' depends on `at` so we + // pass it. + (where === 'FROM_END' || where === 'FROM_START' ? ', ' + at : '') + + ')'; return [code, Order.HIGH]; } } else { // Either `list` is a simple variable, or we only need to refer to `list` // once. - const atOrder = (mode === 'GET' && where === 'FROM_END') ? - Order.ADDITIVE : - Order.NONE; + const atOrder = + mode === 'GET' && where === 'FROM_END' ? Order.ADDITIVE : Order.NONE; let at = generator.valueToCode(block, 'AT', atOrder) || '1'; at = getListIndex(list, where, at); if (mode === 'GET') { @@ -186,14 +243,15 @@ export function lists_getIndex(block, generator) { const code = 'table.remove(' + list + ', ' + at + ')'; if (mode === 'GET_REMOVE') { return [code, Order.HIGH]; - } else { // `mode` === 'REMOVE' + } else { + // `mode` === 'REMOVE' return code + '\n'; } } } -}; +} -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: LuaGenerator): string { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. let list = generator.valueToCode(block, 'LIST', Order.HIGH) || '{}'; @@ -205,28 +263,41 @@ export function lists_setIndex(block, generator) { let code = ''; // If `list` would be evaluated more than once (which is the case for LAST, // FROM_END, and RANDOM) and is non-trivial, make sure to access it only once. - if ((where === 'LAST' || where === 'FROM_END' || where === 'RANDOM') && - !list.match(/^\w+$/)) { + if ( + (where === 'LAST' || where === 'FROM_END' || where === 'RANDOM') && + !list.match(/^\w+$/) + ) { // `list` is an expression, so we may not evaluate it more than once. // We can use multiple statements. - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); code = listVar + ' = ' + list + '\n'; list = listVar; } if (mode === 'SET') { code += list + '[' + getListIndex(list, where, at) + '] = ' + value; - } else { // `mode` === 'INSERT' + } else { + // `mode` === 'INSERT' // LAST is a special case, because we want to insert // *after* not *before*, the existing last element. - code += 'table.insert(' + list + ', ' + - (getListIndex(list, where, at) + (where === 'LAST' ? ' + 1' : '')) + - ', ' + value + ')'; + code += + 'table.insert(' + + list + + ', ' + + (getListIndex(list, where, at) + (where === 'LAST' ? ' + 1' : '')) + + ', ' + + value + + ')'; } return code + '\n'; -}; +} -export function lists_getSublist(block, generator) { +export function lists_getSublist( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; const where1 = block.getFieldValue('WHERE1'); @@ -237,11 +308,12 @@ export function lists_getSublist(block, generator) { // The value for 'FROM_END' and'FROM_START' depends on `at` so // we add it as a parameter. const at1Param = - (where1 === 'FROM_END' || where1 === 'FROM_START') ? ', at1' : ''; + where1 === 'FROM_END' || where1 === 'FROM_START' ? ', at1' : ''; const at2Param = - (where2 === 'FROM_END' || where2 === 'FROM_START') ? ', at2' : ''; + where2 === 'FROM_END' || where2 === 'FROM_START' ? ', at2' : ''; const functionName = generator.provideFunction_( - 'list_sublist_' + where1.toLowerCase() + '_' + where2.toLowerCase(), ` + 'list_sublist_' + where1.toLowerCase() + '_' + where2.toLowerCase(), + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(source${at1Param}${at2Param}) local t = {} local start = ${getListIndex('source', where1, 'at1')} @@ -251,23 +323,32 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(source${at1Param}${at2Param}) end return t end -`); - const code = functionName + '(' + list + - // The value for 'FROM_END' and 'FROM_START' depends on `at` so we - // pass it. - ((where1 === 'FROM_END' || where1 === 'FROM_START') ? ', ' + at1 : '') + - ((where2 === 'FROM_END' || where2 === 'FROM_START') ? ', ' + at2 : '') + - ')'; +`, + ); + const code = + functionName + + '(' + + list + + // The value for 'FROM_END' and 'FROM_START' depends on `at` so we + // pass it. + (where1 === 'FROM_END' || where1 === 'FROM_START' ? ', ' + at1 : '') + + (where2 === 'FROM_END' || where2 === 'FROM_START' ? ', ' + at2 : '') + + ')'; return [code, Order.HIGH]; -}; +} -export function lists_sort(block, generator) { +export function lists_sort( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Block for sorting a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const functionName = generator.provideFunction_('list_sort', ` + const functionName = generator.provideFunction_( + 'list_sort', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, typev, direction) local t = {} for n,v in pairs(list) do table.insert(t, v) end @@ -288,25 +369,30 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list, typev, direction) table.sort(t, compare) return t end -`); +`, + ); const code = - functionName + '(' + list + ',"' + type + '", ' + direction + ')'; + functionName + '(' + list + ',"' + type + '", ' + direction + ')'; return [code, Order.HIGH]; -}; +} -export function lists_split(block, generator) { +export function lists_split( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. let input = generator.valueToCode(block, 'INPUT', Order.NONE); - const delimiter = - generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + const delimiter = generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { if (!input) { input = "''"; } - functionName = generator.provideFunction_('list_string_split', ` + functionName = generator.provideFunction_( + 'list_string_split', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(input, delim) local t = {} local pos = 1 @@ -322,7 +408,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(input, delim) end return t end -`); +`, + ); } else if (mode === 'JOIN') { if (!input) { input = '{}'; @@ -333,12 +420,17 @@ end } const code = functionName + '(' + input + ', ' + delimiter + ')'; return [code, Order.HIGH]; -}; +} -export function lists_reverse(block, generator) { +export function lists_reverse( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; - const functionName = generator.provideFunction_('list_reverse', ` + const functionName = generator.provideFunction_( + 'list_reverse', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(input) local reversed = {} for i = #input, 1, -1 do @@ -346,7 +438,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(input) end return reversed end -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.HIGH]; -}; +} diff --git a/generators/lua/logic.js b/generators/lua/logic.ts similarity index 51% rename from generators/lua/logic.js rename to generators/lua/logic.ts index e540a460e..b6448445c 100644 --- a/generators/lua/logic.js +++ b/generators/lua/logic.ts @@ -5,15 +5,16 @@ */ /** - * @fileoverview Generating Lua for logic blocks. + * @file Generating Lua for logic blocks. */ // Former goog.module ID: Blockly.Lua.logic +import type {Block} from '../../core/block.js'; +import type {LuaGenerator} from './lua_generator.js'; import {Order} from './lua_generator.js'; - -export function controls_if(block, generator) { +export function controls_if(block: Block, generator: LuaGenerator): string { // If/elseif/else condition. let n = 0; let code = ''; @@ -23,15 +24,17 @@ export function controls_if(block, generator) { } do { const conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; let branchCode = generator.statementToCode(block, 'DO' + n); if (generator.STATEMENT_SUFFIX) { - branchCode = generator.prefixLines( + branchCode = + generator.prefixLines( generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + branchCode; + generator.INDENT, + ) + branchCode; } code += - (n > 0 ? 'else' : '') + 'if ' + conditionCode + ' then\n' + branchCode; + (n > 0 ? 'else' : '') + 'if ' + conditionCode + ' then\n' + branchCode; n++; } while (block.getInput('IF' + n)); @@ -39,36 +42,46 @@ export function controls_if(block, generator) { let branchCode = generator.statementToCode(block, 'ELSE'); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId( - generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += 'else\n' + branchCode; } return code + 'end\n'; -}; +} export const controls_ifelse = controls_if; -export function logic_compare(block, generator) { +export function logic_compare( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '~=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; - const argument0 = - generator.valueToCode(block, 'A', Order.RELATIONAL) || '0'; - const argument1 = - generator.valueToCode(block, 'B', Order.RELATIONAL) || '0'; + const OPERATORS = { + 'EQ': '==', + 'NEQ': '~=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; + const argument0 = generator.valueToCode(block, 'A', Order.RELATIONAL) || '0'; + const argument1 = generator.valueToCode(block, 'B', Order.RELATIONAL) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, Order.RELATIONAL]; -}; +} -export function logic_operation(block, generator) { +export function logic_operation( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or'; - const order = (operator === 'and') ? Order.AND : Order.OR; + const operator = block.getFieldValue('OP') === 'AND' ? 'and' : 'or'; + const order = operator === 'and' ? Order.AND : Order.OR; let argument0 = generator.valueToCode(block, 'A', order); let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { @@ -77,7 +90,7 @@ export function logic_operation(block, generator) { argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === 'and') ? 'true' : 'false'; + const defaultArgument = operator === 'and' ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } @@ -87,33 +100,43 @@ export function logic_operation(block, generator) { } const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_negate(block, generator) { +export function logic_negate( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Negation. - const argument0 = - generator.valueToCode(block, 'BOOL', Order.UNARY) || 'true'; + const argument0 = generator.valueToCode(block, 'BOOL', Order.UNARY) || 'true'; const code = 'not ' + argument0; return [code, Order.UNARY]; -}; +} -export function logic_boolean(block, generator) { +export function logic_boolean( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false'; return [code, Order.ATOMIC]; -}; +} -export function logic_null(block, generator) { +export function logic_null( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Null data type. return ['nil', Order.ATOMIC]; -}; +} -export function logic_ternary(block, generator) { +export function logic_ternary( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Ternary operator. const value_if = generator.valueToCode(block, 'IF', Order.AND) || 'false'; - const value_then = - generator.valueToCode(block, 'THEN', Order.AND) || 'nil'; + const value_then = generator.valueToCode(block, 'THEN', Order.AND) || 'nil'; const value_else = generator.valueToCode(block, 'ELSE', Order.OR) || 'nil'; const code = value_if + ' and ' + value_then + ' or ' + value_else; return [code, Order.OR]; -}; +} diff --git a/generators/lua/loops.js b/generators/lua/loops.ts similarity index 70% rename from generators/lua/loops.js rename to generators/lua/loops.ts index b7f9311c7..fec175b48 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.ts @@ -5,21 +5,22 @@ */ /** - * @fileoverview Generating Lua for loop blocks. + * @file Generating Lua for loop blocks. */ // Former goog.module ID: Blockly.Lua.loops import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; +import type {LuaGenerator} from './lua_generator.js'; import {NameType} from '../../core/names.js'; import {Order} from './lua_generator.js'; - /** * This is the text used to implement a
continue
. * It is also used to recognise
continue
s in generated code so that * the appropriate label can be put at the end of the loop body. - * @const {string} */ const CONTINUE_STATEMENT = 'goto continue\n'; @@ -29,20 +30,23 @@ const CONTINUE_STATEMENT = 'goto continue\n'; * in all outer loops, but this is safer than duplicating the logic of * blockToCode. * - * @param {string} branch Generated code of the loop body - * @param {string} indent Whitespace by which to indent a continue statement. - * @return {string} Generated label or '' if unnecessary + * @param branch Generated code of the loop body + * @param indent Whitespace by which to indent a continue statement. + * @returns Generated label or '' if unnecessary */ -function addContinueLabel(branch, indent) { +function addContinueLabel(branch: string, indent: string): string { if (branch.indexOf(CONTINUE_STATEMENT) !== -1) { // False positives are possible (e.g. a string literal), but are harmless. return branch + indent + '::continue::\n'; } else { return branch; } -}; +} -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext( + block: Block, + generator: LuaGenerator, +): string { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -60,21 +64,26 @@ export function controls_repeat_ext(block, generator) { let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); branch = addContinueLabel(branch, generator.INDENT); - const loopVar = generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); const code = - 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n'; + 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n'; return code; -}; +} export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil( + block: Block, + generator: LuaGenerator, +): string { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - generator.valueToCode( - block, 'BOOL', until ? Order.UNARY : Order.NONE) || - 'false'; + generator.valueToCode(block, 'BOOL', until ? Order.UNARY : Order.NONE) || + 'false'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); branch = addContinueLabel(branch, generator.INDENT); @@ -82,12 +91,11 @@ export function controls_whileUntil(block, generator) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ' do\n' + branch + 'end\n'; -}; +} -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: LuaGenerator): string { // For loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const startVar = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const endVar = generator.valueToCode(block, 'TO', Order.NONE) || '0'; const increment = generator.valueToCode(block, 'BY', Order.NONE) || '1'; @@ -96,8 +104,11 @@ export function controls_for(block, generator) { branch = addContinueLabel(branch, generator.INDENT); let code = ''; let incValue; - if (stringUtils.isNumber(startVar) && stringUtils.isNumber(endVar) && - stringUtils.isNumber(increment)) { + if ( + stringUtils.isNumber(startVar) && + stringUtils.isNumber(endVar) && + stringUtils.isNumber(increment) + ) { // All arguments are simple numbers. const up = Number(startVar) <= Number(endVar); const step = Math.abs(Number(increment)); @@ -106,12 +117,13 @@ export function controls_for(block, generator) { code = ''; // Determine loop direction at start, in case one of the bounds // changes during loop execution. - incValue = - generator.nameDB_.getDistinctName( - variable0 + '_inc', NameType.VARIABLE); + incValue = generator.nameDB_!.getDistinctName( + variable0 + '_inc', + NameType.VARIABLE, + ); code += incValue + ' = '; if (stringUtils.isNumber(increment)) { - code += Math.abs(increment) + '\n'; + code += Math.abs(increment as unknown as number) + '\n'; } else { code += 'math.abs(' + increment + ')\n'; } @@ -120,25 +132,36 @@ export function controls_for(block, generator) { code += 'end\n'; } code += - 'for ' + variable0 + ' = ' + startVar + ', ' + endVar + ', ' + incValue; + 'for ' + variable0 + ' = ' + startVar + ', ' + endVar + ', ' + incValue; code += ' do\n' + branch + 'end\n'; return code; -}; +} -export function controls_forEach(block, generator) { +export function controls_forEach( + block: Block, + generator: LuaGenerator, +): string { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); branch = addContinueLabel(branch, generator.INDENT); - const code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' + - branch + 'end\n'; + const code = + 'for _, ' + + variable0 + + ' in ipairs(' + + argument0 + + ') do \n' + + branch + + 'end\n'; return code; -}; +} -export function controls_flow_statements(block, generator) { +export function controls_flow_statements( + block: Block, + generator: LuaGenerator, +): string { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { @@ -151,7 +174,7 @@ export function controls_flow_statements(block, generator) { xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. @@ -166,4 +189,4 @@ export function controls_flow_statements(block, generator) { return xfix + CONTINUE_STATEMENT; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/lua/lua_generator.js b/generators/lua/lua_generator.ts similarity index 50% rename from generators/lua/lua_generator.js rename to generators/lua/lua_generator.ts index ea8caab87..76517c77d 100644 --- a/generators/lua/lua_generator.js +++ b/generators/lua/lua_generator.ts @@ -5,40 +5,40 @@ */ /** - * @fileoverview Helper functions for generating Lua for blocks. + * @file Lua code generator class, including helper methods for + * generating Lua for blocks. + * * Based on Ellen Spertus's blocky-lua project. - * @suppress {checkTypes|globalThis} */ // Former goog.module ID: Blockly.Lua import * as stringUtils from '../../core/utils/string.js'; -// import type {Block} from '../../core/block.js'; +import type {Block} from '../../core/block.js'; import {CodeGenerator} from '../../core/generator.js'; import {Names} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; +import type {Workspace} from '../../core/workspace.js'; import {inputTypes} from '../../core/inputs/input_types.js'; - /** * Order of operation ENUMs. * http://www.lua.org/manual/5.3/manual.html#3.4.8 - * @enum {number} */ -export const Order = { - ATOMIC: 0, // literals +// prettier-ignore +export enum Order { + ATOMIC = 0, // literals // The next level was not explicit in documentation and inferred by Ellen. - HIGH: 1, // Function calls, tables[] - EXPONENTIATION: 2, // ^ - UNARY: 3, // not # - ~ - MULTIPLICATIVE: 4, // * / % - ADDITIVE: 5, // + - - CONCATENATION: 6, // .. - RELATIONAL: 7, // < > <= >= ~= == - AND: 8, // and - OR: 9, // or - NONE: 99, -}; + HIGH = 1, // Function calls, tables[] + EXPONENTIATION = 2, // ^ + UNARY = 3, // not # - ~ + MULTIPLICATIVE = 4, // * / % + ADDITIVE = 5, // + - + CONCATENATION = 6, // .. + RELATIONAL = 7, // < > <= >= ~= == + AND = 8, // and + OR = 9, // or + NONE = 99, +} /** * Lua code generator class. @@ -48,8 +48,8 @@ export const Order = { * option used for lists and text. */ export class LuaGenerator extends CodeGenerator { - constructor(name) { - super(name ?? 'Lua'); + constructor(name = 'Lua') { + super(name); this.isInitialized = false; // Copy Order values onto instance for backwards compatibility @@ -60,7 +60,16 @@ export class LuaGenerator extends CodeGenerator { // replace data properties with get accessors that call // deprecate.warn().) for (const key in Order) { - this['ORDER_' + key] = Order[key]; + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; } // List of illegal variable names. This is not intended to be a @@ -70,38 +79,39 @@ export class LuaGenerator extends CodeGenerator { this.addReservedWords( // Special character '_,' + - // From theoriginalbit's script: - // https://github.com/espertus/blockly-lua/issues/6 - '__inext,assert,bit,colors,colours,coroutine,disk,dofile,error,fs,' + - 'fetfenv,getmetatable,gps,help,io,ipairs,keys,loadfile,loadstring,math,' + - 'native,next,os,paintutils,pairs,parallel,pcall,peripheral,print,' + - 'printError,rawequal,rawget,rawset,read,rednet,redstone,rs,select,' + - 'setfenv,setmetatable,sleep,string,table,term,textutils,tonumber,' + - 'tostring,turtle,type,unpack,vector,write,xpcall,_VERSION,__indext,' + - // Not included in the script, probably because it wasn't enabled: - 'HTTP,' + - // Keywords (http://www.lua.org/pil/1.3.html). - 'and,break,do,else,elseif,end,false,for,function,if,in,local,nil,not,' + - 'or,repeat,return,then,true,until,while,' + - // Metamethods (http://www.lua.org/manual/5.2/manual.html). - 'add,sub,mul,div,mod,pow,unm,concat,len,eq,lt,le,index,newindex,call,' + - // Basic functions (http://www.lua.org/manual/5.2/manual.html, - // section 6.1). - 'assert,collectgarbage,dofile,error,_G,getmetatable,inpairs,load,' + - 'loadfile,next,pairs,pcall,print,rawequal,rawget,rawlen,rawset,select,' + - 'setmetatable,tonumber,tostring,type,_VERSION,xpcall,' + - // Modules (http://www.lua.org/manual/5.2/manual.html, section 6.3). - 'require,package,string,table,math,bit32,io,file,os,debug' + // From theoriginalbit's script: + // https://github.com/espertus/blockly-lua/issues/6 + '__inext,assert,bit,colors,colours,coroutine,disk,dofile,error,fs,' + + 'fetfenv,getmetatable,gps,help,io,ipairs,keys,loadfile,loadstring,math,' + + 'native,next,os,paintutils,pairs,parallel,pcall,peripheral,print,' + + 'printError,rawequal,rawget,rawset,read,rednet,redstone,rs,select,' + + 'setfenv,setmetatable,sleep,string,table,term,textutils,tonumber,' + + 'tostring,turtle,type,unpack,vector,write,xpcall,_VERSION,__indext,' + + // Not included in the script, probably because it wasn't enabled: + 'HTTP,' + + // Keywords (http://www.lua.org/pil/1.3.html). + 'and,break,do,else,elseif,end,false,for,function,if,in,local,nil,not,' + + 'or,repeat,return,then,true,until,while,' + + // Metamethods (http://www.lua.org/manual/5.2/manual.html). + 'add,sub,mul,div,mod,pow,unm,concat,len,eq,lt,le,index,newindex,call,' + + // Basic functions (http://www.lua.org/manual/5.2/manual.html, + // section 6.1). + 'assert,collectgarbage,dofile,error,_G,getmetatable,inpairs,load,' + + 'loadfile,next,pairs,pcall,print,rawequal,rawget,rawlen,rawset,select,' + + 'setmetatable,tonumber,tostring,type,_VERSION,xpcall,' + + // Modules (http://www.lua.org/manual/5.2/manual.html, section 6.3). + 'require,package,string,table,math,bit32,io,file,os,debug', ); } /** * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. + * + * @param workspace Workspace to generate code from. */ - init(workspace) { + init(workspace: Workspace) { // Call Blockly.CodeGenerator's init. - super.init(); + super.init(workspace); if (!this.nameDB_) { this.nameDB_ = new Names(this.RESERVED_WORDS_); @@ -113,73 +123,77 @@ export class LuaGenerator extends CodeGenerator { this.nameDB_.populateProcedures(workspace); this.isInitialized = true; - }; + } /** * Prepend the generated code with the variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. + * + * @param code Generated code. + * @returns Completed code. */ - finish(code) { + finish(code: string): string { // Convert the definitions dictionary into a list. const definitions = Object.values(this.definitions_); // Call Blockly.CodeGenerator's finish. code = super.finish(code); this.isInitialized = false; - this.nameDB_.reset(); + this.nameDB_!.reset(); return definitions.join('\n\n') + '\n\n\n' + code; - }; + } /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. In Lua, an expression is not a legal statement, so we must assign * the value to the (conventionally ignored) _. * http://lua-users.org/wiki/ExpressionsAsStatements - * @param {string} line Line of generated code. - * @return {string} Legal line of code. + * + * @param line Line of generated code. + * @return Legal line of code. */ - scrubNakedValue(line) { + scrubNakedValue(line: string): string { return 'local _ = ' + line + '\n'; - }; + } /** * Encode a string as a properly escaped Lua string, complete with * quotes. - * @param {string} string Text to encode. - * @return {string} Lua string. + * + * @param string Text to encode. + * @returns Lua string. */ - quote_(string) { - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n') - .replace(/'/g, '\\\''); - return '\'' + string + '\''; - }; + quote_(string: string): string { + string = string + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\\n') + .replace(/'/g, "\\'"); + return "'" + string + "'"; + } /** * Encode a string as a properly escaped multiline Lua string, complete with * quotes. - * @param {string} string Text to encode. - * @return {string} Lua string. + * + * @param string Text to encode. + * @returns Lua string. */ - multiline_quote_(string) { + multiline_quote_(string: string): string { const lines = string.split(/\n/g).map(this.quote_); // Join with the following, plus a newline: // .. '\n' .. - return lines.join(' .. \'\\n\' ..\n'); - }; + return lines.join(" .. '\\n' ..\n"); + } /** * Common tasks for generating Lua from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The Lua code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this statement. - * @return {string} Lua code with comments and subsequent blocks added. - * @protected + * @param block The current block. + * @param code The Lua code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns Lua code with comments and subsequent blocks added. */ - scrub_(block, code, opt_thisOnly) { + scrub_(block: Block, code: string, thisOnly = false): string { let commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { @@ -193,7 +207,7 @@ export class LuaGenerator extends CodeGenerator { // Don't collect comments for nested statements. for (let i = 0; i < block.inputList.length; i++) { if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); + const childBlock = block.inputList[i].connection!.targetBlock(); if (childBlock) { comment = this.allNestedComments(childBlock); if (comment) { @@ -203,8 +217,9 @@ export class LuaGenerator extends CodeGenerator { } } } - const nextBlock = block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); + const nextBlock = + block.nextConnection && block.nextConnection.targetBlock(); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); return commentCode + code + nextCode; - }; + } } diff --git a/generators/lua/math.js b/generators/lua/math.ts similarity index 75% rename from generators/lua/math.js rename to generators/lua/math.ts index af1ff738f..8cf87cc6b 100644 --- a/generators/lua/math.js +++ b/generators/lua/math.ts @@ -5,40 +5,51 @@ */ /** - * @fileoverview Generating Lua for math blocks. + * @file Generating Lua for math blocks. */ // Former goog.module ID: Blockly.Lua.math +import type {Block} from '../../core/block.js'; +import type {LuaGenerator} from './lua_generator.js'; import {Order} from './lua_generator.js'; - -export function math_number(block, generator) { +export function math_number( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Numeric value. const code = Number(block.getFieldValue('NUM')); const order = code < 0 ? Order.UNARY : Order.ATOMIC; - return [code, order]; -}; + return [String(code), order]; +} -export function math_arithmetic(block, generator) { +export function math_arithmetic( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITIVE], 'MINUS': [' - ', Order.ADDITIVE], 'MULTIPLY': [' * ', Order.MULTIPLICATIVE], 'DIVIDE': [' / ', Order.MULTIPLICATIVE], 'POWER': [' ^ ', Order.EXPONENTIATION], }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; -}; +} -export function math_single(block, generator) { +export function math_single( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let arg; @@ -106,11 +117,14 @@ export function math_single(block, generator) { throw Error('Unknown math operator: ' + operator); } return [code, Order.HIGH]; -}; +} -export function math_constant(block, generator) { +export function math_constant( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['math.pi', Order.HIGH], 'E': ['math.exp(1)', Order.HIGH], 'GOLDEN_RATIO': ['(1 + math.sqrt(5)) / 2', Order.MULTIPLICATIVE], @@ -119,12 +133,15 @@ export function math_constant(block, generator) { 'INFINITY': ['math.huge', Order.HIGH], }; return CONSTANTS[block.getFieldValue('CONSTANT')]; -}; +} -export function math_number_property(block, generator) { +export function math_number_property( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. - const PROPERTIES = { + const PROPERTIES: Record = { 'EVEN': [' % 2 == 0', Order.MULTIPLICATIVE, Order.RELATIONAL], 'ODD': [' % 2 == 1', Order.MULTIPLICATIVE, Order.RELATIONAL], 'WHOLE': [' % 1 == 0', Order.MULTIPLICATIVE, Order.RELATIONAL], @@ -135,12 +152,14 @@ export function math_number_property(block, generator) { }; const dropdownProperty = block.getFieldValue('PROPERTY'); const [suffix, inputOrder, outputOrder] = PROPERTIES[dropdownProperty]; - const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', - inputOrder) || '0'; + const numberToCheck = + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = generator.provideFunction_('math_isPrime', ` + const functionName = generator.provideFunction_( + 'math_isPrime', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) -- https://en.wikipedia.org/wiki/Primality_test#Naive_methods if n == 2 or n == 3 then @@ -159,11 +178,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(n) end return true end -`); +`, + ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MULTIPLICATIVE) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; // If 'divisor' is some code that evals to 0, generator will produce a nan. // Let's produce nil if we can determine this at compile-time. if (divisor === '0') { @@ -177,23 +197,25 @@ end code = numberToCheck + suffix; } return [code, outputOrder]; -}; +} -export function math_change(block, generator) { +export function math_change(block: Block, generator: LuaGenerator): string { // Add to a variable in place. const argument0 = - generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + generator.valueToCode(block, 'DELTA', Order.ADDITIVE) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); return varName + ' = ' + varName + ' + ' + argument0 + '\n'; -}; +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); const list = generator.valueToCode(block, 'LIST', Order.NONE) || '{}'; @@ -201,7 +223,9 @@ export function math_on_list(block, generator) { // Functions needed in more than one case. function provideSum() { - return generator.provideFunction_('math_sum', ` + return generator.provideFunction_( + 'math_sum', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) local result = 0 for _, v in ipairs(t) do @@ -209,7 +233,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) end return result end -`); +`, + ); } switch (func) { @@ -219,7 +244,9 @@ end case 'MIN': // Returns 0 for the empty list. - functionName = generator.provideFunction_('math_min', ` + functionName = generator.provideFunction_( + 'math_min', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 @@ -232,24 +259,30 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) end return result end -`); +`, + ); break; case 'AVERAGE': // Returns 0 for the empty list. - functionName = generator.provideFunction_('math_average', ` + functionName = generator.provideFunction_( + 'math_average', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 end return ${provideSum()}(t) / #t end -`); +`, + ); break; case 'MAX': // Returns 0 for the empty list. - functionName = generator.provideFunction_('math_max', ` + functionName = generator.provideFunction_( + 'math_max', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return 0 @@ -262,12 +295,15 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) end return result end -`); +`, + ); break; case 'MEDIAN': // This operation excludes non-numbers. - functionName = generator.provideFunction_('math_median', ` + functionName = generator.provideFunction_( + 'math_median', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) -- Source: http://lua-users.org/wiki/SimpleStats if #t == 0 then @@ -286,14 +322,17 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) return temp[math.ceil(#temp / 2)] end end -`); +`, + ); break; case 'MODE': // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // The generator version includes non-numbers. - functionName = generator.provideFunction_('math_modes', ` + functionName = generator.provideFunction_( + 'math_modes', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) -- Source: http://lua-users.org/wiki/SimpleStats local counts = {} @@ -318,11 +357,14 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) end return temp end -`); +`, + ); break; case 'STD_DEV': - functionName = generator.provideFunction_('math_standard_deviation', ` + functionName = generator.provideFunction_( + 'math_standard_deviation', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) local m local vm @@ -340,66 +382,92 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) result = math.sqrt(total / (count-1)) return result end -`); +`, + ); break; case 'RANDOM': - functionName = generator.provideFunction_('math_random_list', ` + functionName = generator.provideFunction_( + 'math_random_list', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(t) if #t == 0 then return nil end return t[math.random(#t)] end -`); +`, + ); break; default: throw Error('Unknown operator: ' + func); } return [functionName + '(' + list + ')', Order.HIGH]; -}; +} -export function math_modulo(block, generator) { +export function math_modulo( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Remainder computation. const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MULTIPLICATIVE) || '0'; const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MULTIPLICATIVE]; -}; +} -export function math_constrain(block, generator) { +export function math_constrain( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Constrain a number between two limits. const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = - generator.valueToCode(block, 'LOW', Order.NONE) || '-math.huge'; + generator.valueToCode(block, 'LOW', Order.NONE) || '-math.huge'; const argument2 = - generator.valueToCode(block, 'HIGH', Order.NONE) || 'math.huge'; - const code = 'math.min(math.max(' + argument0 + ', ' + argument1 + '), ' + - argument2 + ')'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'math.huge'; + const code = + 'math.min(math.max(' + + argument0 + + ', ' + + argument1 + + '), ' + + argument2 + + ')'; return [code, Order.HIGH]; -}; +} -export function math_random_int(block, generator) { +export function math_random_int( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Random integer between [X] and [Y]. const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; const code = 'math.random(' + argument0 + ', ' + argument1 + ')'; return [code, Order.HIGH]; -}; +} -export function math_random_float(block, generator) { +export function math_random_float( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Random fraction between 0 and 1. return ['math.random()', Order.HIGH]; -}; +} -export function math_atan2(block, generator) { +export function math_atan2( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ - 'math.deg(math.atan2(' + argument1 + ', ' + argument0 + '))', Order.HIGH + 'math.deg(math.atan2(' + argument1 + ', ' + argument0 + '))', + Order.HIGH, ]; -}; +} diff --git a/generators/lua/procedures.js b/generators/lua/procedures.ts similarity index 61% rename from generators/lua/procedures.js rename to generators/lua/procedures.ts index 935ca1136..07003aee9 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.ts @@ -5,18 +5,22 @@ */ /** - * @fileoverview Generating Lua for procedure blocks. + * @file Generating Lua for procedure blocks. */ // Former goog.module ID: Blockly.Lua.procedures +import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; +import type {LuaGenerator} from './lua_generator.js'; import {Order} from './lua_generator.js'; - -export function procedures_defreturn(block, generator) { +export function procedures_defreturn( + block: Block, + generator: LuaGenerator, +): null { // Define a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); @@ -30,8 +34,9 @@ export function procedures_defreturn(block, generator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId( - generator.INFINITE_LOOP_TRAP, block), generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } let branch = generator.statementToCode(block, 'STACK'); let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; @@ -50,22 +55,36 @@ export function procedures_defreturn(block, generator) { for (let i = 0; i < variables.length; i++) { args[i] = generator.getVariableName(variables[i]); } - let code = 'function ' + funcName + '(' + args.join(', ') + ')\n' + xfix1 + - loopTrap + branch + xfix2 + returnValue + 'end\n'; + let code = + 'function ' + + funcName + + '(' + + args.join(', ') + + ')\n' + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue + + 'end\n'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Call a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { @@ -73,30 +92,39 @@ export function procedures_callreturn(block, generator) { } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.HIGH]; -}; +} -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn( + block: Block, + generator: LuaGenerator, +): string { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn']( + block, + generator, + ) as [string, number]; return tuple[0] + '\n'; -}; +} -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn( + block: Block, + generator: LuaGenerator, +): string { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if ' + condition + ' then\n'; if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT); + code += generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } - if (block.hasReturnValue_) { + if ((block as IfReturnBlock).hasReturnValue_) { const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'nil'; code += generator.INDENT + 'return ' + value + '\n'; } else { @@ -104,4 +132,4 @@ export function procedures_ifreturn(block, generator) { } code += 'end\n'; return code; -}; +} diff --git a/generators/lua/text.js b/generators/lua/text.ts similarity index 69% rename from generators/lua/text.js rename to generators/lua/text.ts index 606fcce32..ff65327cf 100644 --- a/generators/lua/text.js +++ b/generators/lua/text.ts @@ -5,82 +5,99 @@ */ /** - * @fileoverview Generating Lua for text blocks. + * @file Generating Lua for text blocks. */ // Former goog.module ID: Blockly.Lua.texts +import type {Block} from '../../core/block.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; +import type {LuaGenerator} from './lua_generator.js'; import {Order} from './lua_generator.js'; - -export function text(block, generator) { +export function text(block: Block, generator: LuaGenerator): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block, generator) { +export function text_multiline( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('..') !== -1 ? Order.CONCATENATION : Order.ATOMIC; + const order = code.indexOf('..') !== -1 ? Order.CONCATENATION : Order.ATOMIC; return [code, order]; -}; +} -export function text_join(block, generator) { +export function text_join( + block: Block, + generator: LuaGenerator, +): [string, Order] { + const joinBlock = block as JoinMutatorBlock; // Create a string made up of any number of elements of any type. - if (block.itemCount_ === 0) { + if (joinBlock.itemCount_ === 0) { return ["''", Order.ATOMIC]; - } else if (block.itemCount_ === 1) { + } else if (joinBlock.itemCount_ === 1) { const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const code = 'tostring(' + element + ')'; return [code, Order.HIGH]; - } else if (block.itemCount_ === 2) { + } else if (joinBlock.itemCount_ === 2) { const element0 = - generator.valueToCode(block, 'ADD0', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'ADD0', Order.CONCATENATION) || "''"; const element1 = - generator.valueToCode(block, 'ADD1', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'ADD1', Order.CONCATENATION) || "''"; const code = element0 + ' .. ' + element1; return [code, Order.CONCATENATION]; } else { const elements = []; - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + for (let i = 0; i < joinBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } const code = 'table.concat({' + elements.join(', ') + '})'; return [code, Order.HIGH]; } -}; +} -export function text_append(block, generator) { +export function text_append(block: Block, generator: LuaGenerator): string { // Append to a variable in place. - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + const varName = generator.getVariableName(block.getFieldValue('VAR')); const value = - generator.valueToCode(block, 'TEXT', Order.CONCATENATION) || "''"; + generator.valueToCode(block, 'TEXT', Order.CONCATENATION) || "''"; return varName + ' = ' + varName + ' .. ' + value + '\n'; -}; +} -export function text_length(block, generator) { +export function text_length( + block: Block, + generator: LuaGenerator, +): [string, Order] { // String or array length. const text = generator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; return ['#' + text, Order.UNARY]; -}; +} -export function text_isEmpty(block, generator) { +export function text_isEmpty( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.UNARY) || "''"; return ['#' + text + ' == 0', Order.RELATIONAL]; -}; +} -export function text_indexOf(block, generator) { +export function text_indexOf( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Search the text for a substring. const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let functionName; if (block.getFieldValue('END') === 'FIRST') { - functionName = generator.provideFunction_('firstIndexOf', ` + functionName = generator.provideFunction_( + 'firstIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) local i = string.find(str, substr, 1, true) if i == nil then @@ -88,9 +105,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) end return i end -`); +`, + ); } else { - functionName = generator.provideFunction_('lastIndexOf', ` + functionName = generator.provideFunction_( + 'lastIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) local i = string.find(string.reverse(str), string.reverse(substr), 1, true) if i then @@ -98,27 +118,34 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, substr) end return 0 end -`); +`, + ); } const code = functionName + '(' + text + ', ' + substring + ')'; return [code, Order.HIGH]; -}; +} -export function text_charAt(block, generator) { +export function text_charAt( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const atOrder = (where === 'FROM_END') ? Order.UNARY : Order.NONE; + const atOrder = where === 'FROM_END' ? Order.UNARY : Order.NONE; const at = generator.valueToCode(block, 'AT', atOrder) || '1'; const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let code; if (where === 'RANDOM') { - const functionName = generator.provideFunction_('text_random_letter', ` + const functionName = generator.provideFunction_( + 'text_random_letter', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) local index = math.random(string.len(str)) return string.sub(str, index, index) end -`); +`, + ); code = functionName + '(' + text + ')'; } else { let start; @@ -139,24 +166,30 @@ end code = 'string.sub(' + text + ', ' + start + ', ' + start + ')'; } else { // use function to avoid reevaluation - const functionName = generator.provideFunction_('text_char_at', ` + const functionName = generator.provideFunction_( + 'text_char_at', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str, index) return string.sub(str, index, index) end -`); +`, + ); code = functionName + '(' + text + ', ' + start + ')'; } } return [code, Order.HIGH]; -}; +} -export function text_getSubstring(block, generator) { +export function text_getSubstring( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Get substring. const text = generator.valueToCode(block, 'STRING', Order.NONE) || "''"; // Get start index. const where1 = block.getFieldValue('WHERE1'); - const at1Order = (where1 === 'FROM_END') ? Order.UNARY : Order.NONE; + const at1Order = where1 === 'FROM_END' ? Order.UNARY : Order.NONE; const at1 = generator.valueToCode(block, 'AT1', at1Order) || '1'; let start; if (where1 === 'FIRST') { @@ -171,7 +204,7 @@ export function text_getSubstring(block, generator) { // Get end index. const where2 = block.getFieldValue('WHERE2'); - const at2Order = (where2 === 'FROM_END') ? Order.UNARY : Order.NONE; + const at2Order = where2 === 'FROM_END' ? Order.UNARY : Order.NONE; const at2 = generator.valueToCode(block, 'AT2', at2Order) || '1'; let end; if (where2 === 'LAST') { @@ -185,9 +218,12 @@ export function text_getSubstring(block, generator) { } const code = 'string.sub(' + text + ', ' + start + ', ' + end + ')'; return [code, Order.HIGH]; -}; +} -export function text_changeCase(block, generator) { +export function text_changeCase( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Change capitalization. const operator = block.getFieldValue('CASE'); const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; @@ -200,7 +236,9 @@ export function text_changeCase(block, generator) { // There are shorter versions at // http://lua-users.org/wiki/SciteTitleCase // that do not preserve whitespace. - functionName = generator.provideFunction_('text_titlecase', ` + functionName = generator.provideFunction_( + 'text_titlecase', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) local buf = {} local inWord = false @@ -218,28 +256,36 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(str) end return table.concat(buf) end -`); +`, + ); } const code = functionName + '(' + text + ')'; return [code, Order.HIGH]; -}; +} -export function text_trim(block, generator) { +export function text_trim( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = {LEFT: '^%s*(,-)', RIGHT: '(.-)%s*$', BOTH: '^%s*(.-)%s*$'}; - const operator = OPERATORS[block.getFieldValue('MODE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'string.gsub(' + text + ', "' + operator + '", "%1")'; return [code, Order.HIGH]; -}; +} -export function text_print(block, generator) { +export function text_print(block: Block, generator: LuaGenerator): string { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ')\n'; -}; +} -export function text_prompt_ext(block, generator) { +export function text_prompt_ext( + block: Block, + generator: LuaGenerator, +): [string, Order] { // Prompt function. let msg; if (block.getField('TEXT')) { @@ -250,13 +296,16 @@ export function text_prompt_ext(block, generator) { msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; } - const functionName = generator.provideFunction_('text_prompt', ` + const functionName = generator.provideFunction_( + 'text_prompt', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(msg) io.write(msg) io.flush() return io.read() end -`); +`, + ); let code = functionName + '(' + msg + ')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; @@ -264,14 +313,19 @@ end code = 'tonumber(' + code + ', 10)'; } return [code, Order.HIGH]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { +export function text_count( + block: Block, + generator: LuaGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; - const functionName = generator.provideFunction_('text_count', ` + const functionName = generator.provideFunction_( + 'text_count', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) if #needle == 0 then return #haystack + 1 @@ -288,16 +342,22 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle) end return count end -`); +`, + ); const code = functionName + '(' + text + ', ' + sub + ')'; return [code, Order.HIGH]; -}; +} -export function text_replace(block, generator) { +export function text_replace( + block: Block, + generator: LuaGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; - const functionName = generator.provideFunction_('text_replace', ` + const functionName = generator.provideFunction_( + 'text_replace', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) local buf = {} local i = 1 @@ -314,13 +374,17 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(haystack, needle, replacement) end return table.concat(buf) end -`); +`, + ); const code = functionName + '(' + text + ', ' + from + ', ' + to + ')'; return [code, Order.HIGH]; -}; +} -export function text_reverse(block, generator) { +export function text_reverse( + block: Block, + generator: LuaGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'string.reverse(' + text + ')'; return [code, Order.HIGH]; -}; +} diff --git a/generators/lua/variables.js b/generators/lua/variables.js deleted file mode 100644 index 1913321c9..000000000 --- a/generators/lua/variables.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright 2016 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Generating Lua for variable blocks. - */ - -// Former goog.module ID: Blockly.Lua.variables - -import {Order} from './lua_generator.js'; - - -export function variables_get(block, generator) { - // Variable getter. - const code = - generator.getVariableName(block.getFieldValue('VAR')); - return [code, Order.ATOMIC]; -}; - -export function variables_set(block, generator) { - // Variable setter. - const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = ' + argument0 + '\n'; -}; diff --git a/generators/lua/variables.ts b/generators/lua/variables.ts new file mode 100644 index 000000000..b70f6892b --- /dev/null +++ b/generators/lua/variables.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file Generating Lua for variable blocks. + */ + +// Former goog.module ID: Blockly.Lua.variables + +import type {Block} from '../../core/block.js'; +import type {LuaGenerator} from './lua_generator.js'; +import {Order} from './lua_generator.js'; + +export function variables_get( + block: Block, + generator: LuaGenerator, +): [string, Order] { + // Variable getter. + const code = generator.getVariableName(block.getFieldValue('VAR')); + return [code, Order.ATOMIC]; +} + +export function variables_set(block: Block, generator: LuaGenerator): string { + // Variable setter. + const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + return varName + ' = ' + argument0 + '\n'; +} diff --git a/generators/lua/variables_dynamic.js b/generators/lua/variables_dynamic.ts similarity index 82% rename from generators/lua/variables_dynamic.js rename to generators/lua/variables_dynamic.ts index 4b42be990..62b981b31 100644 --- a/generators/lua/variables_dynamic.js +++ b/generators/lua/variables_dynamic.ts @@ -5,12 +5,11 @@ */ /** - * @fileoverview Generating Lua for dynamic variable blocks. + * @file Generating Lua for dynamic variable blocks. */ // Former goog.module ID: Blockly.Lua.variablesDynamic - // Lua is dynamically typed. export { variables_get as variables_get_dynamic, From d059270f258fa814f89399abd132f51dc409a379 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:26:16 -0800 Subject: [PATCH 63/86] chore(deps): Bump actions/setup-node from 3 to 4 (#7613) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/browser_test.yml | 2 +- .github/workflows/build.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/browser_test.yml b/.github/workflows/browser_test.yml index 5fccc9c11..3675af7b0 100644 --- a/.github/workflows/browser_test.yml +++ b/.github/workflows/browser_test.yml @@ -34,7 +34,7 @@ jobs: ssh://git@github.com/ - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04eba7308..ad62722e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: ssh://git@github.com/ - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x @@ -74,7 +74,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x From 58c7f096d84de86f85f08dd067e9db5cab1b386c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:13:16 -0800 Subject: [PATCH 64/86] chore(deps): Bump eslint from 8.52.0 to 8.54.0 (#7655) Bumps [eslint](https://github.com/eslint/eslint) from 8.52.0 to 8.54.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.52.0...v8.54.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index de6a4501d..94cb43941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -388,9 +388,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -411,9 +411,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1794,9 +1794,9 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3882,15 +3882,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5544,9 +5544,9 @@ } }, "node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" From 5c434d81b411f31837437b27f89f331203bb1a21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:13:38 -0800 Subject: [PATCH 65/86] chore(deps): Bump actions/github-script from 6 to 7 (#7659) Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/assign_reviewers.yml | 2 +- .github/workflows/tag_module_cleanup.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/assign_reviewers.yml b/.github/workflows/assign_reviewers.yml index 765f0e655..33bd9e778 100644 --- a/.github/workflows/assign_reviewers.yml +++ b/.github/workflows/assign_reviewers.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Assign requested reviewer - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | try { diff --git a/.github/workflows/tag_module_cleanup.yml b/.github/workflows/tag_module_cleanup.yml index e0186af67..d83d0e937 100644 --- a/.github/workflows/tag_module_cleanup.yml +++ b/.github/workflows/tag_module_cleanup.yml @@ -15,7 +15,7 @@ jobs: # Add the type: cleanup label runs-on: ubuntu-latest steps: - - uses: actions/github-script@v6 + - uses: actions/github-script@v7 with: script: | // Note that pull requests are considered issues and "shared" From b6a7ffbb76eaa79961cb07baabc9d57694fadc33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:14:30 -0800 Subject: [PATCH 66/86] chore(deps): Bump webdriverio from 8.20.4 to 8.24.2 (#7668) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.20.4 to 8.24.2. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.24.2/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 525 +++++----------------------------------------- 1 file changed, 54 insertions(+), 471 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94cb43941..4867f75fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,184 +62,6 @@ "node": ">=0.10.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/runtime": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", @@ -1101,9 +923,9 @@ "dev": true }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", - "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, "node_modules/@types/json-schema": { @@ -1118,12 +940,6 @@ "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", "dev": true }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", - "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", @@ -1147,9 +963,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", - "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, "dependencies": { "@types/node": "*" @@ -1544,19 +1360,18 @@ "dev": true }, "node_modules/@wdio/config": { - "version": "8.20.3", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.20.3.tgz", - "integrity": "sha512-UaPjDjdXztrWgpoodSjZc1/9oXX1WpjhZSW55ZA2PKzCO7QuS/Fory5lMMpJD4v6/9fNUiRp7A4/rd+w7am1vA==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.24.2.tgz", + "integrity": "sha512-qMTU40PBtEZEdj+vTkK2mRxaT07gcEGundlj+u08brYNT2LHPtEw5Vp0jReCz29Wlq4zsrv9qHpgluiSnRTHQw==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", - "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.3", + "@wdio/types": "8.24.2", + "@wdio/utils": "8.24.2", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", - "import-meta-resolve": "^3.0.0", - "read-pkg-up": "^10.0.0" + "import-meta-resolve": "^3.0.0" }, "engines": { "node": "^16.13 || >=18" @@ -1629,15 +1444,15 @@ } }, "node_modules/@wdio/protocols": { - "version": "8.20.4", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.20.4.tgz", - "integrity": "sha512-9PwA2xgjsoB/9Fm8UWRhJlw61O69ckRICuBn0bzoHmMF7uMzYgDvDTekzYKn8JfjzvLm/MnWXL8raCZfQQ0P5g==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.23.0.tgz", + "integrity": "sha512-2XTzD+lqQP3g8BWn+Bn5BTFzjHqzZNwq7DjlYrb27Bq8nOA+1DEcj3WzQ6V6CktTnKI/LAYKA1IFAF//Azrp/Q==", "dev": true }, "node_modules/@wdio/repl": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.10.1.tgz", - "integrity": "sha512-VZ1WFHTNKjR8Ga97TtV2SZM6fvRjWbYI2i/f4pJB4PtusorKvONAMJf2LQcUBIyzbVobqr7KSrcjmSwRolI+yw==", + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.23.1.tgz", + "integrity": "sha512-u6zG2cgBm67V5/WlQzadWqLGXs3moH8MOsgoljULQncelSBBZGZ5DyLB4p7jKcUAsKtMjgmFQmIvpQoqmyvdfg==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1647,9 +1462,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.20.0.tgz", - "integrity": "sha512-y0En5V5PPF48IHJMetaNYQobhCr3ddsgp2aX/crLL51UccWqnFpCL8pCh6cP01gRgCchCasa2JCBMB+PucbYmA==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.24.2.tgz", + "integrity": "sha512-x7iWF5NM8NfVxziGwLdQ+3sstgSxRoqfmmFEDTDps0oFrN5CgkqcoLkqXJ5u166gvpxpEq0gxZwxkbPC/Lp0cw==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1659,14 +1474,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.20.3", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.20.3.tgz", - "integrity": "sha512-McGS9TFNfjS3cGJkF8hXyajGE5LKFJnPg/fbdXTIBzYohiAzQ1rUMyllPdxxHslnpQPkflBHI6XSYBxU7yB9Lw==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.24.2.tgz", + "integrity": "sha512-YsQunFrAqZO7Retkzfhqa7N/zY21FdnI4iFYCAeIeL3spRIGRFsXjrbE8vEXu9/Tr+h5Xxgn5Lj3Dc/7HD8EPg==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.20.0", + "@wdio/types": "8.24.2", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -2409,9 +2224,9 @@ } }, "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, "engines": { "node": ">=0.6" @@ -3525,9 +3340,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1209236", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1209236.tgz", - "integrity": "sha512-z4eehc+fhmptqhxwreLcg9iydszZGU4Q5FzaaElXVGp3KyfXbjtXeUCmo4l8FxBJbyXtCz4VRIJsGW2ekApyUQ==", + "version": "0.0.1213968", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1213968.tgz", + "integrity": "sha512-o4n/beY+3CcZwFctYapjGelKptR4AuQT5gXS1Kvgbig+ArwkxK7f8wDVuD1wsoswiJWCwV6OK+Qb7vhNzNmABQ==", "dev": true }, "node_modules/dir-glob": { @@ -6429,27 +6244,6 @@ "node": ">=0.10.0" } }, - "node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -6522,9 +6316,9 @@ } }, "node_modules/http2-wrapper": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", - "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, "dependencies": { "quick-lru": "^5.1.1", @@ -6601,9 +6395,9 @@ } }, "node_modules/import-meta-resolve": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-3.0.0.tgz", - "integrity": "sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-3.1.1.tgz", + "integrity": "sha512-qeywsE/KC3w9Fd2ORrRDUw6nS/nLwZpXgfrOc2IILvZYnCaEMd+D56Vfg9k4G29gIeVi3XKql1RQatME8iYsiw==", "dev": true, "funding": { "type": "github", @@ -7058,12 +6852,6 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -7179,15 +6967,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7410,15 +7189,6 @@ "node": ">=0.10.0" } }, - "node_modules/lines-and-columns": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -8277,21 +8047,6 @@ } } }, - "node_modules/normalize-package-data": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", - "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", - "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -8757,37 +8512,6 @@ "node": ">=0.8" } }, - "node_modules/parse-json": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", - "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "error-ex": "^1.3.2", - "json-parse-even-better-errors": "^3.0.0", - "lines-and-columns": "^2.0.3", - "type-fest": "^3.8.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-json/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", @@ -9445,147 +9169,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", - "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^6.0.0", - "parse-json": "^7.0.0", - "type-fest": "^4.2.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz", - "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==", - "dev": true, - "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^8.1.0", - "type-fest": "^4.2.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.6.0.tgz", - "integrity": "sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.6.0.tgz", - "integrity": "sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -11728,18 +11311,18 @@ } }, "node_modules/webdriver": { - "version": "8.20.4", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.20.4.tgz", - "integrity": "sha512-X/6l+zGXn1trqA1LRwYETIJgkJQTVZ/xE1SrTlSxk2BE7Tq40voxfbDKUyauaCyRyABhA0ZgK5/1UOqeCKW15w==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.24.2.tgz", + "integrity": "sha512-UZzXIRXd+Ja7F2gfgwgaFiRxnHhX7q+WS7DRP2x/HJPZGWuoRwuqhPdTJ3SgsCKgDgwRUWwmh7yKCcfiGR1/lg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.20.3", + "@wdio/config": "8.24.2", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.20.4", - "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.3", + "@wdio/protocols": "8.23.0", + "@wdio/types": "8.24.2", + "@wdio/utils": "8.24.2", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11787,23 +11370,23 @@ } }, "node_modules/webdriverio": { - "version": "8.20.4", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.20.4.tgz", - "integrity": "sha512-+iyYK0NTviXv3Lyws07CaX9pLET9l0bh8aPICfCyf7f0NZLUDvUoEKvjviMCfLq4lbDu7CFIEyDZUJeuqlRwlw==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.24.2.tgz", + "integrity": "sha512-zHQNI27Ltd3HpNHYil0U7VKqa+ESN264RSsOLfY9vlnmFAwPXLM7MFaFSx/u6OPG/mcQ2j8W49px2n+yeDHvuw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.20.3", + "@wdio/config": "8.24.2", "@wdio/logger": "8.16.17", - "@wdio/protocols": "8.20.4", - "@wdio/repl": "8.10.1", - "@wdio/types": "8.20.0", - "@wdio/utils": "8.20.3", + "@wdio/protocols": "8.23.0", + "@wdio/repl": "8.23.1", + "@wdio/types": "8.24.2", + "@wdio/utils": "8.24.2", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools-protocol": "^0.0.1209236", + "devtools-protocol": "^0.0.1213968", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^3.0.0", "is-plain-obj": "^4.1.0", @@ -11815,7 +11398,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.20.4" + "webdriver": "8.24.2" }, "engines": { "node": "^16.13 || >=18" From 80be8bc04c818a1f1ff8ecd5284e6a6005ae77c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:25:51 -0800 Subject: [PATCH 67/86] chore(deps): Bump prettier from 3.0.3 to 3.1.0 (#7658) * chore(deps): Bump prettier from 3.0.3 to 3.1.0 Bumps [prettier](https://github.com/prettier/prettier) from 3.0.3 to 3.1.0. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.0.3...3.1.0) --- updated-dependencies: - dependency-name: prettier dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore: format --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Beka Westberg --- core/field.ts | 4 +- package-lock.json | 8 +-- package.json | 2 +- scripts/migration/js2ts | 130 +++++++++++++++++++++------------------- 4 files changed, 77 insertions(+), 67 deletions(-) diff --git a/core/field.ts b/core/field.ts index cfae1429b..a3afb7062 100644 --- a/core/field.ts +++ b/core/field.ts @@ -810,8 +810,8 @@ export abstract class Field margin !== undefined ? margin : !this.isFullBlockField() - ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING - : 0; + ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING + : 0; let totalWidth = xOffset * 2; let totalHeight = constants!.FIELD_TEXT_HEIGHT; diff --git a/package-lock.json b/package-lock.json index 4867f75fd..731af9e80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,7 +45,7 @@ "markdown-tables-to-json": "^0.1.7", "mocha": "^10.0.0", "patch-package": "^8.0.0", - "prettier": "3.0.3", + "prettier": "3.1.0", "readline-sync": "^1.4.10", "rimraf": "^5.0.0", "typescript": "^5.0.2", @@ -8917,9 +8917,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" diff --git a/package.json b/package.json index a82008d76..8f972c170 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "markdown-tables-to-json": "^0.1.7", "mocha": "^10.0.0", "patch-package": "^8.0.0", - "prettier": "3.0.3", + "prettier": "3.1.0", "readline-sync": "^1.4.10", "rimraf": "^5.0.0", "typescript": "^5.0.2", diff --git a/scripts/migration/js2ts b/scripts/migration/js2ts index a8d941e01..068871df5 100755 --- a/scripts/migration/js2ts +++ b/scripts/migration/js2ts @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); -const filenames = process.argv.slice(2); // Trim off node and script name. +const filenames = process.argv.slice(2); // Trim off node and script name. ////////////////////////////////////////////////////////////////////// // Load deps files via require (since they're executalbe .js files). @@ -40,7 +40,7 @@ globalThis.goog = {}; * to {'module': 'goog'} for backwards-compatibility. Valid properties * and values include {'module': 'goog'} and {'lang': 'es6'}. */ -goog.addDependency = function(relPath, provides, _requires, opt_loadFlags) { +goog.addDependency = function (relPath, provides, _requires, opt_loadFlags) { // Ignore any non-ESM files, as they can't be imported. if (opt_loadFlags?.module !== 'es6') return; @@ -61,7 +61,7 @@ require(path.resolve(__dirname, '../../build/deps.js')); /** RegExp matching goog.require statements. */ const requireRE = - /(?:const\s+(?:([$\w]+)|(\{[^}]*\}))\s+=\s+)?goog.require(Type)?\('([^']+)'\);/mg; + /(?:const\s+(?:([$\w]+)|(\{[^}]*\}))\s+=\s+)?goog.require(Type)?\('([^']+)'\);/gm; /** RegExp matching key: value pairs in destructuring assignments. */ const keyValueRE = /([$\w]+)\s*:\s*([$\w]+)\s*(?=,|})/g; @@ -80,72 +80,82 @@ for (const filename of filenames) { contents = contents.replace(/^\s*["']use strict["']\s*; *\n/m, ''); // Migrate from goog.module to goog.declareModuleId. - const closurePathRelative = - path.relative(path.dirname(path.resolve(filename)), closurePath); + const closurePathRelative = path.relative( + path.dirname(path.resolve(filename)), + closurePath, + ); contents = contents.replace( - /^goog.module\('([$\w.]+)'\);$/m, - `import * as goog from '${closurePathRelative}/goog.js';\n` + - `goog.declareModuleId('$1');`); + /^goog.module\('([$\w.]+)'\);$/m, + `import * as goog from '${closurePathRelative}/goog.js';\n` + + `goog.declareModuleId('$1');`, + ); // Migrate from goog.require to import. contents = contents.replace( - requireRE, - function( - orig, // Whole statement to be replaced. - name, // Name of named import of whole module (if applicable). - names, // {}-enclosed list of destructured imports. - type, // If truthy, it is a requireType not require. - moduleId, // goog.module ID that was goog.require()d. - ) { - const importPath = modulePaths[moduleId]; - type = type ? ' type' : ''; - if (!importPath) { - console.warn(`Unable to migrate goog.require('${ - moduleId}') as no ES module path known.`); - return orig; - } - let relativePath = - path.relative(path.dirname(path.resolve(filename)), importPath); - if (relativePath[0] !== '.') relativePath = './' + relativePath; - if (name) { - return `import${type} * as ${name} from '${relativePath}';`; - } else if (names) { - names = names.replace(keyValueRE, '$1 as $2'); - return `import${type} ${names} from '${relativePath}';`; - } else { // Side-effect only require. - return `import${type} '${relativePath}';`; - } - }); + requireRE, + function ( + orig, // Whole statement to be replaced. + name, // Name of named import of whole module (if applicable). + names, // {}-enclosed list of destructured imports. + type, // If truthy, it is a requireType not require. + moduleId, // goog.module ID that was goog.require()d. + ) { + const importPath = modulePaths[moduleId]; + type = type ? ' type' : ''; + if (!importPath) { + console.warn( + `Unable to migrate goog.require('${moduleId}') as no ES module path known.`, + ); + return orig; + } + let relativePath = path.relative( + path.dirname(path.resolve(filename)), + importPath, + ); + if (relativePath[0] !== '.') relativePath = './' + relativePath; + if (name) { + return `import${type} * as ${name} from '${relativePath}';`; + } else if (names) { + names = names.replace(keyValueRE, '$1 as $2'); + return `import${type} ${names} from '${relativePath}';`; + } else { + // Side-effect only require. + return `import${type} '${relativePath}';`; + } + }, + ); // Find and update or remove old-style export assignemnts. /** @type {!Array<{name: string, re: RegExp>}>} */ const easyExports = []; contents = contents.replace( - /^\s*exports\.([$\w]+)\s*=\s*([$\w]+)\s*;\n/gm, - function( - orig, // Whole statement to be replaced. - exportName, // Name to export item as. - declName, // Already-declared name for item being exported. - ) { - // Renamed exports have to be transalted as-is. - if (exportName !== declName) { - return `export {${declName} as ${exportName}};\n`; - } - // OK, we're doing "export.foo = foo;". Can we update the - // declaration? We can't actualy modify it yet as we're in - // the middle of a search-and-replace on contents already, but - // we can delete the old export and later update the - // declaration into an export. - const declRE = new RegExp( - `^(\\s*)((?:const|let|var|function|class)\\s+${declName})\\b`, - 'gm'); - if (contents.match(declRE)) { - easyExports.push({exportName, declRE}); - return ''; // Delete existing export assignment. - } else { - return `export ${exportName};\n`; // Safe fallback. - } - }); + /^\s*exports\.([$\w]+)\s*=\s*([$\w]+)\s*;\n/gm, + function ( + orig, // Whole statement to be replaced. + exportName, // Name to export item as. + declName, // Already-declared name for item being exported. + ) { + // Renamed exports have to be transalted as-is. + if (exportName !== declName) { + return `export {${declName} as ${exportName}};\n`; + } + // OK, we're doing "export.foo = foo;". Can we update the + // declaration? We can't actualy modify it yet as we're in + // the middle of a search-and-replace on contents already, but + // we can delete the old export and later update the + // declaration into an export. + const declRE = new RegExp( + `^(\\s*)((?:const|let|var|function|class)\\s+${declName})\\b`, + 'gm', + ); + if (contents.match(declRE)) { + easyExports.push({exportName, declRE}); + return ''; // Delete existing export assignment. + } else { + return `export ${exportName};\n`; // Safe fallback. + } + }, + ); // Add 'export' to existing declarations where appropriate. for (const {exportName, declRE} of easyExports) { contents = contents.replace(declRE, '$1export $2'); From 0d40bad833504ec21a5a54f92be514afd561536c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:26:31 -0800 Subject: [PATCH 68/86] chore(deps): Bump @microsoft/api-documenter from 7.23.9 to 7.23.12 (#7644) Bumps [@microsoft/api-documenter](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-documenter) from 7.23.9 to 7.23.12. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-documenter/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-documenter_v7.23.12/apps/api-documenter) --- updated-dependencies: - dependency-name: "@microsoft/api-documenter" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 731af9e80..10f3a7b8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -536,15 +536,15 @@ } }, "node_modules/@microsoft/api-documenter": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.9.tgz", - "integrity": "sha512-CvOy3JF0oCDm3GDqce3uFS9QGO72lfOEgVbvpje32O+ug/WoL8ITOg2jZszMtowuClasPbpEcEoVsHJJLePirg==", + "version": "7.23.12", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.12.tgz", + "integrity": "sha512-ZFQGHNs8fSe3KoSCNa+jt/HLTN8IdTRGd0TZqmSeHpz2cSvUYHJeyQKhv8s7yi2flr1LezBq5/ig65ITZPSSqw==", "dev": true, "dependencies": { "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", "@rushstack/node-core-library": "3.61.0", - "@rushstack/ts-command-line": "4.16.1", + "@rushstack/ts-command-line": "4.17.1", "colors": "~1.2.1", "js-yaml": "~3.13.1", "resolve": "~1.22.1" @@ -553,6 +553,18 @@ "api-documenter": "bin/api-documenter" } }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", + "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", + "dev": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, "node_modules/@microsoft/api-documenter/node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", From ac362fd57a2edefa739aa3ff49d3c566c1f94483 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:37:33 +0000 Subject: [PATCH 69/86] chore(deps): Bump jsdom from 22.1.0 to 23.0.0 (#7667) Bumps [jsdom](https://github.com/jsdom/jsdom) from 22.1.0 to 23.0.0. - [Release notes](https://github.com/jsdom/jsdom/releases) - [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md) - [Commits](https://github.com/jsdom/jsdom/compare/22.1.0...23.0.0) --- updated-dependencies: - dependency-name: jsdom dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 588 ++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 329 insertions(+), 261 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10f3a7b8d..b0585e583 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "jsdom": "22.1.0" + "jsdom": "23.0.0" }, "devDependencies": { "@blockly/block-test": "^5.0.0", @@ -897,6 +897,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "peer": true, "engines": { "node": ">= 10" } @@ -1531,18 +1533,6 @@ "node": ">=16.3.0" } }, - "node_modules/@wdio/utils/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@wdio/utils/node_modules/decamelize": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", @@ -1555,32 +1545,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/utils/node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@wdio/utils/node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@wdio/utils/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -1618,7 +1582,10 @@ "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "peer": true }, "node_modules/acorn": { "version": "8.11.2", @@ -1642,14 +1609,14 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dependencies": { - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -2288,6 +2255,166 @@ "jsdom": "22.1.0" } }, + "node_modules/blockly/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/blockly/node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "peer": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/blockly/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "peer": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/blockly/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/blockly/node_modules/jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "peer": true, + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/blockly/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/blockly/node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "peer": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/blockly/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/blockly/node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "peer": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/blockly/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", @@ -3102,6 +3229,17 @@ "node": ">=0.10.0" } }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -3127,6 +3265,41 @@ "node": ">= 14" } }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -3394,6 +3567,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "peer": true, "dependencies": { "webidl-conversions": "^7.0.0" }, @@ -4756,18 +4932,6 @@ "node": "^16.13 || >=18 || >=20" } }, - "node_modules/geckodriver/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/geckodriver/node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -4789,32 +4953,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/geckodriver/node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/geckodriver/node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/geckodriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -6260,6 +6398,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -6288,16 +6427,15 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/http-server": { @@ -6341,15 +6479,26 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/ieee754": { @@ -6886,39 +7035,37 @@ } }, "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", + "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", "dependencies": { - "abab": "^2.0.6", "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", + "data-urls": "^5.0.0", "decimal.js": "^10.4.3", - "domexception": "^4.0.0", "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", + "nwsapi": "^2.2.7", "parse5": "^7.1.2", "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.14.2", + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { - "canvas": "^2.5.0" + "canvas": "^3.0.0" }, "peerDependenciesMeta": { "canvas": { @@ -6926,51 +7073,69 @@ } } }, - "node_modules/jsdom/node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/jsdom/node_modules/data-urls": { + "node_modules/jsdom/node_modules/html-encoding-sniffer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/jsdom/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dependencies": { - "punycode": "^2.3.0" + "punycode": "^2.3.1" }, "engines": { - "node": ">=14" + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" } }, "node_modules/jsdom/node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", "dependencies": { - "tr46": "^4.1.1", + "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/json-buffer": { @@ -8102,9 +8267,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", - "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==" + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -8446,44 +8611,6 @@ "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/pac-resolver": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", @@ -8986,44 +9113,6 @@ "node": ">= 14" } }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/proxy-agent/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -9076,9 +9165,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -10064,18 +10153,6 @@ "node": ">= 14" } }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -11286,14 +11363,14 @@ } }, "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dependencies": { - "xml-name-validator": "^4.0.0" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/wait-port": { @@ -11472,6 +11549,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -11479,23 +11557,12 @@ "node": ">=12" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/whatwg-url": { @@ -11586,6 +11653,7 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, "engines": { "node": ">=10.0.0" }, @@ -11603,11 +11671,11 @@ } }, "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/xmlchars": { diff --git a/package.json b/package.json index 8f972c170..3f237a7da 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,6 @@ "yargs": "^17.2.1" }, "dependencies": { - "jsdom": "22.1.0" + "jsdom": "23.0.0" } } From b198e2f4ae5755ac53e79ed85e246976080137b6 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Tue, 28 Nov 2023 16:57:31 +0000 Subject: [PATCH 70/86] fix(generators): Improve consistency of migrated language generators (#7662) * docs(generators): @fileoverview -> @file; delete @suppress * fix(generators): Fix return type of getAdjusted And improve its documentation too. Fix the @returns doc for PythonGenerator's getAdjustedInt but (for now) don't change the type because it does actually return numbers in some circumstances. --- generators/dart.ts | 6 +++--- generators/dart/colour.ts | 2 +- generators/dart/dart_generator.ts | 4 ++-- generators/dart/lists.ts | 2 +- generators/dart/logic.ts | 2 +- generators/dart/loops.ts | 2 +- generators/dart/math.ts | 2 +- generators/dart/procedures.ts | 2 +- generators/dart/text.ts | 2 +- generators/dart/variables.ts | 2 +- generators/dart/variables_dynamic.ts | 2 +- generators/javascript.ts | 6 +++--- generators/javascript/colour.ts | 2 +- generators/javascript/javascript_generator.ts | 4 ++-- generators/javascript/lists.ts | 3 +-- generators/javascript/logic.ts | 2 +- generators/javascript/loops.ts | 2 +- generators/javascript/math.ts | 3 +-- generators/javascript/procedures.ts | 2 +- generators/javascript/text.ts | 2 +- generators/javascript/variables.ts | 2 +- generators/javascript/variables_dynamic.ts | 2 +- generators/python.ts | 6 +++--- generators/python/colour.ts | 2 +- generators/python/lists.ts | 2 +- generators/python/logic.ts | 2 +- generators/python/loops.ts | 2 +- generators/python/math.ts | 2 +- generators/python/procedures.ts | 2 +- generators/python/python_generator.ts | 2 +- generators/python/text.ts | 2 +- generators/python/variables.ts | 2 +- generators/python/variables_dynamic.ts | 2 +- 33 files changed, 41 insertions(+), 43 deletions(-) diff --git a/generators/dart.ts b/generators/dart.ts index 3bd1271ad..ee21b1fbd 100644 --- a/generators/dart.ts +++ b/generators/dart.ts @@ -5,9 +5,9 @@ */ /** - * @fileoverview Complete helper functions for generating Dart for - * blocks. This is the entrypoint for dart_compressed.js. - * @suppress {extraRequire} + * @file Instantiate a DartGenerator and populate it with the complete + * set of block generator functions for Dart. This is the entrypoint + * for dart_compressed.js. */ // Former goog.module ID: Blockly.Dart.all diff --git a/generators/dart/colour.ts b/generators/dart/colour.ts index b55fc5e6f..ac72fc04c 100644 --- a/generators/dart/colour.ts +++ b/generators/dart/colour.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for colour blocks. + * @file Generating Dart for colour blocks. */ // Former goog.module ID: Blockly.Dart.colour diff --git a/generators/dart/dart_generator.ts b/generators/dart/dart_generator.ts index b2eb80cdd..222bbd41d 100644 --- a/generators/dart/dart_generator.ts +++ b/generators/dart/dart_generator.ts @@ -269,7 +269,7 @@ export class DartGenerator extends CodeGenerator { * @param delta Value to add. * @param negate Whether to negate the value. * @param order The highest order acting on this value. - * @returns The adjusted value. + * @returns The adjusted value or code that evaluates to it. */ getAdjusted( block: Block, @@ -277,7 +277,7 @@ export class DartGenerator extends CodeGenerator { delta = 0, negate = false, order = Order.NONE, - ): string | number { + ): string { if (block.workspace.options.oneBasedIndex) { delta--; } diff --git a/generators/dart/lists.ts b/generators/dart/lists.ts index d1b65cc53..4aaf39905 100644 --- a/generators/dart/lists.ts +++ b/generators/dart/lists.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for list blocks. + * @file Generating Dart for list blocks. */ // Former goog.module ID: Blockly.Dart.lists diff --git a/generators/dart/logic.ts b/generators/dart/logic.ts index 82d9d563b..45c385b86 100644 --- a/generators/dart/logic.ts +++ b/generators/dart/logic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for logic blocks. + * @file Generating Dart for logic blocks. */ // Former goog.module ID: Blockly.Dart.logic diff --git a/generators/dart/loops.ts b/generators/dart/loops.ts index 5f54d2018..a6b6bb180 100644 --- a/generators/dart/loops.ts +++ b/generators/dart/loops.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for loop blocks. + * @file Generating Dart for loop blocks. */ // Former goog.module ID: Blockly.Dart.loops diff --git a/generators/dart/math.ts b/generators/dart/math.ts index 01830a0b1..550821e9f 100644 --- a/generators/dart/math.ts +++ b/generators/dart/math.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for math blocks. + * @file Generating Dart for math blocks. */ // Former goog.module ID: Blockly.Dart.math diff --git a/generators/dart/procedures.ts b/generators/dart/procedures.ts index 934e52318..5102432ad 100644 --- a/generators/dart/procedures.ts +++ b/generators/dart/procedures.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for procedure blocks. + * @file Generating Dart for procedure blocks. */ // Former goog.module ID: Blockly.Dart.procedures diff --git a/generators/dart/text.ts b/generators/dart/text.ts index e8c9be637..108516019 100644 --- a/generators/dart/text.ts +++ b/generators/dart/text.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for text blocks. + * @file Generating Dart for text blocks. */ // Former goog.module ID: Blockly.Dart.texts diff --git a/generators/dart/variables.ts b/generators/dart/variables.ts index 1910befc9..4863d0417 100644 --- a/generators/dart/variables.ts +++ b/generators/dart/variables.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for variable blocks. + * @file Generating Dart for variable blocks. */ // Former goog.module ID: Blockly.Dart.variables diff --git a/generators/dart/variables_dynamic.ts b/generators/dart/variables_dynamic.ts index 6a92fff91..68cdf22d6 100644 --- a/generators/dart/variables_dynamic.ts +++ b/generators/dart/variables_dynamic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Dart for dynamic variable blocks. + * @file Generating Dart for dynamic variable blocks. */ // Former goog.module ID: Blockly.Dart.variablesDynamic diff --git a/generators/javascript.ts b/generators/javascript.ts index 079c2f793..2358d187d 100644 --- a/generators/javascript.ts +++ b/generators/javascript.ts @@ -5,9 +5,9 @@ */ /** - * @fileoverview Complete helper functions for generating JavaScript for - * blocks. This is the entrypoint for javascript_compressed.js. - * @suppress {extraRequire} + * @file Instantiate a JavascriptGenerator and populate it with the + * complete set of block generator functions for JavaScript. This is + * the entrypoint for javascript_compressed.js. */ // Former goog.module ID: Blockly.JavaScript.all diff --git a/generators/javascript/colour.ts b/generators/javascript/colour.ts index 3e7089cd7..b599e76d9 100644 --- a/generators/javascript/colour.ts +++ b/generators/javascript/colour.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for colour blocks. + * @file Generating JavaScript for colour blocks. */ // Former goog.module ID: Blockly.JavaScript.colour diff --git a/generators/javascript/javascript_generator.ts b/generators/javascript/javascript_generator.ts index 547b7daf7..98c6a4a4b 100644 --- a/generators/javascript/javascript_generator.ts +++ b/generators/javascript/javascript_generator.ts @@ -295,7 +295,7 @@ export class JavascriptGenerator extends CodeGenerator { * @param delta Value to add. * @param negate Whether to negate the value. * @param order The highest order acting on this value. - * @returns The adjusted value. + * @returns The adjusted value or code that evaluates to it. */ getAdjusted( block: Block, @@ -303,7 +303,7 @@ export class JavascriptGenerator extends CodeGenerator { delta = 0, negate = false, order = Order.NONE, - ): string | number { + ): string { if (block.workspace.options.oneBasedIndex) { delta--; } diff --git a/generators/javascript/lists.ts b/generators/javascript/lists.ts index 0a1fcc87f..839d959cb 100644 --- a/generators/javascript/lists.ts +++ b/generators/javascript/lists.ts @@ -5,8 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for list blocks. - * @suppress {missingRequire} + * @file Generating JavaScript for list blocks. */ // Former goog.module ID: Blockly.JavaScript.lists diff --git a/generators/javascript/logic.ts b/generators/javascript/logic.ts index bdc51f997..60174c85a 100644 --- a/generators/javascript/logic.ts +++ b/generators/javascript/logic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for logic blocks. + * @file Generating JavaScript for logic blocks. */ // Former goog.module ID: Blockly.JavaScript.logic diff --git a/generators/javascript/loops.ts b/generators/javascript/loops.ts index a5dd86357..555e43ff1 100644 --- a/generators/javascript/loops.ts +++ b/generators/javascript/loops.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for loop blocks. + * @file Generating JavaScript for loop blocks. */ // Former goog.module ID: Blockly.JavaScript.loops diff --git a/generators/javascript/math.ts b/generators/javascript/math.ts index c05e817cf..e8ab2852f 100644 --- a/generators/javascript/math.ts +++ b/generators/javascript/math.ts @@ -5,8 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for math blocks. - * @suppress {missingRequire} + * @file Generating JavaScript for math blocks. */ // Former goog.module ID: Blockly.JavaScript.math diff --git a/generators/javascript/procedures.ts b/generators/javascript/procedures.ts index f0b5c94f0..a835271e7 100644 --- a/generators/javascript/procedures.ts +++ b/generators/javascript/procedures.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for procedure blocks. + * @file Generating JavaScript for procedure blocks. */ // Former goog.module ID: Blockly.JavaScript.procedures diff --git a/generators/javascript/text.ts b/generators/javascript/text.ts index 7e3b0e4c1..1681979ec 100644 --- a/generators/javascript/text.ts +++ b/generators/javascript/text.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for text blocks. + * @file Generating JavaScript for text blocks. */ // Former goog.module ID: Blockly.JavaScript.texts diff --git a/generators/javascript/variables.ts b/generators/javascript/variables.ts index 88320be54..33a4f7d31 100644 --- a/generators/javascript/variables.ts +++ b/generators/javascript/variables.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for variable blocks. + * @file Generating JavaScript for variable blocks. */ // Former goog.module ID: Blockly.JavaScript.variables diff --git a/generators/javascript/variables_dynamic.ts b/generators/javascript/variables_dynamic.ts index b88d03fc1..27cd214e4 100644 --- a/generators/javascript/variables_dynamic.ts +++ b/generators/javascript/variables_dynamic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating JavaScript for dynamic variable blocks. + * @file Generating JavaScript for dynamic variable blocks. */ // Former goog.module ID: Blockly.JavaScript.variablesDynamic diff --git a/generators/python.ts b/generators/python.ts index e2345a776..08ab10e81 100644 --- a/generators/python.ts +++ b/generators/python.ts @@ -5,9 +5,9 @@ */ /** - * @fileoverview Complete helper functions for generating Python for - * blocks. This is the entrypoint for python_compressed.js. - * @suppress {extraRequire} + * @file Instantiate a PythonGenerator and populate it with the + * complete set of block generator functions for Python. This is the + * entrypoint for python_compressed.js. */ // Former goog.module ID: Blockly.Python.all diff --git a/generators/python/colour.ts b/generators/python/colour.ts index 82f9dd37b..729d87cf5 100644 --- a/generators/python/colour.ts +++ b/generators/python/colour.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for colour blocks. + * @file Generating Python for colour blocks. */ // Former goog.module ID: Blockly.Python.colour diff --git a/generators/python/lists.ts b/generators/python/lists.ts index 7577cc417..6e412c23f 100644 --- a/generators/python/lists.ts +++ b/generators/python/lists.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for list blocks. + * @file Generating Python for list blocks. */ // Former goog.module ID: Blockly.Python.lists diff --git a/generators/python/logic.ts b/generators/python/logic.ts index e562c6794..40133600d 100644 --- a/generators/python/logic.ts +++ b/generators/python/logic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for logic blocks. + * @file Generating Python for logic blocks. */ // Former goog.module ID: Blockly.Python.logic diff --git a/generators/python/loops.ts b/generators/python/loops.ts index 1d2d3a86e..7ca7a5582 100644 --- a/generators/python/loops.ts +++ b/generators/python/loops.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for loop blocks. + * @file Generating Python for loop blocks. */ // Former goog.module ID: Blockly.Python.loops diff --git a/generators/python/math.ts b/generators/python/math.ts index d458b0e87..59b68c7a7 100644 --- a/generators/python/math.ts +++ b/generators/python/math.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for math blocks. + * @file Generating Python for math blocks. */ // Former goog.module ID: Blockly.Python.math diff --git a/generators/python/procedures.ts b/generators/python/procedures.ts index ad45f2dfb..0d9b2e85d 100644 --- a/generators/python/procedures.ts +++ b/generators/python/procedures.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for procedure blocks. + * @file Generating Python for procedure blocks. */ // Former goog.module ID: Blockly.Python.procedures diff --git a/generators/python/python_generator.ts b/generators/python/python_generator.ts index 5e5daf9f2..33c07fe39 100644 --- a/generators/python/python_generator.ts +++ b/generators/python/python_generator.ts @@ -318,7 +318,7 @@ export class PythonGenerator extends CodeGenerator { * @param atId The ID of the input block to get (and adjust) the value of. * @param delta Value to add. * @param negate Whether to negate the value. - * @returns The adjusted value. + * @returns The adjusted value or code that evaluates to it. */ getAdjustedInt( block: Block, diff --git a/generators/python/text.ts b/generators/python/text.ts index 7b554efda..5d93e91ed 100644 --- a/generators/python/text.ts +++ b/generators/python/text.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for text blocks. + * @file Generating Python for text blocks. */ // Former goog.module ID: Blockly.Python.texts diff --git a/generators/python/variables.ts b/generators/python/variables.ts index 5510e5e0f..a323181f1 100644 --- a/generators/python/variables.ts +++ b/generators/python/variables.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for variable blocks. + * @file Generating Python for variable blocks. */ // Former goog.module ID: Blockly.Python.variables diff --git a/generators/python/variables_dynamic.ts b/generators/python/variables_dynamic.ts index 4ca397258..884700160 100644 --- a/generators/python/variables_dynamic.ts +++ b/generators/python/variables_dynamic.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating Python for dynamic variable blocks. + * @file Generating Python for dynamic variable blocks. */ // Former goog.module ID: Blockly.Python.variablesDynamic From 7bda30924aa0d7bef69e8c32f18ea3d6775bc48e Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Tue, 28 Nov 2023 16:59:19 +0000 Subject: [PATCH 71/86] refactor(generators): Migrate PHP generators to TypeScript (#7647) * refactor(generators): Migrate dart_generator.js to TypeScript * refactor(generators): Simplify getAdjusted Slightly simplify the implementation of getAdjusted, in part to make it more readable. Also improve its JSDoc comment. * refactor(generators): Migrate generators/php/* to TypeScript First pass doing very mechanistic migration, not attempting to fix all the resulting type errors. * fix(generators): Fix type errors in generator functions This consists almost entirely of adding casts, so the code output by tsc should be as similar as possible to the pre-migration .js source files. * fix(generators): Fix more minor inconsistencies in JS and Python The migration of the JavaScript and Python generators inadvertently introduced some inconsistencies in the code, e.g. putting executable code before the initial comment line that most generator functions begin with. This fixes another instance of this (but n.b. that these inline comments should have been JSDocs and a task has been added to #7600 to convert them). Additionally, I noticed while doing the PHP migration that ORDER_OVERRIDES was not typed as specifically as it could be, in previous migrations, so this is fixed here (along with the formatting of the associated JSDoc, which can fit on one line now.) * refactor(generators): Migrate generators/php.js to TypeScript The way the generator functions are added to phpGenerator.forBlock has been modified so that incorrect generator function signatures will cause tsc to generate a type error. * chore(generator): Format One block protected with // prettier-ignore to preserve careful comment formatting. Where there are repeated concatenations prettier has made a pretty mess of things, but the correct fix is probably to use template literals instead (rather than just locally disabling prettier). This is one of the items in the to-do list in #7600. * docs(generators): @fileoverview -> @file With an update to the wording for generators/php.ts. * fix(generators): Fixes for PR #7647. - Don't declare unused wherePascalCase dictionary. - Don't allow null in OPERATOR dictionary when not needed. - Fix return type (and documentation thereof) of getAdjusted. --- generators/javascript/javascript_generator.ts | 6 +- generators/javascript/lists.ts | 2 +- generators/{php.js => php.ts} | 25 +- generators/php/{colour.js => colour.ts} | 60 ++-- generators/php/{lists.js => lists.ts} | 314 ++++++++++------- generators/php/{logic.js => logic.ts} | 114 ++++--- generators/php/{loops.js => loops.ts} | 152 ++++++--- generators/php/{math.js => math.ts} | 202 +++++++---- generators/php/php_generator.js | 307 ----------------- generators/php/php_generator.ts | 320 ++++++++++++++++++ .../php/{procedures.js => procedures.ts} | 82 +++-- generators/php/{text.js => text.ts} | 208 ++++++++---- generators/php/variables.js | 30 -- generators/php/variables.ts | 32 ++ ...iables_dynamic.js => variables_dynamic.ts} | 3 +- generators/python/python_generator.ts | 6 +- 16 files changed, 1107 insertions(+), 756 deletions(-) rename generators/{php.js => php.ts} (65%) rename generators/php/{colour.js => colour.ts} (69%) rename generators/php/{lists.js => lists.ts} (68%) rename generators/php/{logic.js => logic.ts} (51%) rename generators/php/{loops.js => loops.ts} (57%) rename generators/php/{math.js => math.ts} (70%) delete mode 100644 generators/php/php_generator.js create mode 100644 generators/php/php_generator.ts rename generators/php/{procedures.js => procedures.ts} (65%) rename generators/php/{text.js => text.ts} (63%) delete mode 100644 generators/php/variables.js create mode 100644 generators/php/variables.ts rename generators/php/{variables_dynamic.js => variables_dynamic.ts} (83%) diff --git a/generators/javascript/javascript_generator.ts b/generators/javascript/javascript_generator.ts index 98c6a4a4b..02602e71f 100644 --- a/generators/javascript/javascript_generator.ts +++ b/generators/javascript/javascript_generator.ts @@ -66,10 +66,8 @@ export enum Order { * JavaScript code generator class. */ export class JavascriptGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - */ - ORDER_OVERRIDES: number[][] = [ + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], diff --git a/generators/javascript/lists.ts b/generators/javascript/lists.ts index 839d959cb..bbed5231b 100644 --- a/generators/javascript/lists.ts +++ b/generators/javascript/lists.ts @@ -302,6 +302,7 @@ export function lists_getSublist( block: Block, generator: JavascriptGenerator, ): [string, Order] { + // Get sublist. // Dictionary of WHEREn field choices and their CamelCase equivalents. const wherePascalCase = { 'FIRST': 'First', @@ -310,7 +311,6 @@ export function lists_getSublist( 'FROM_END': 'FromEnd', }; type WhereOption = keyof typeof wherePascalCase; - // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1') as WhereOption; const where2 = block.getFieldValue('WHERE2') as WhereOption; diff --git a/generators/php.js b/generators/php.ts similarity index 65% rename from generators/php.js rename to generators/php.ts index f61daccf7..18631ad9a 100644 --- a/generators/php.js +++ b/generators/php.ts @@ -5,9 +5,9 @@ */ /** - * @fileoverview Complete helper functions for generating PHP for - * blocks. This is the entrypoint for php_compressed.js. - * @suppress {extraRequire} + * @file Instantiate a PhpGenerator and populate it with the complete + * set of block generator functions for PHP. This is the entrypoint + * for php_compressed.js. */ // Former goog.module ID: Blockly.PHP.all @@ -32,8 +32,17 @@ export * from './php/php_generator.js'; export const phpGenerator = new PhpGenerator(); // Install per-block-type generator functions: -Object.assign( - phpGenerator.forBlock, - colour, lists, logic, loops, math, procedures, - text, variables, variablesDynamic -); +const generators: typeof phpGenerator.forBlock = { + ...colour, + ...lists, + ...logic, + ...loops, + ...math, + ...procedures, + ...text, + ...variables, + ...variablesDynamic, +}; +for (const name in generators) { + phpGenerator.forBlock[name] = generators[name]; +} diff --git a/generators/php/colour.js b/generators/php/colour.ts similarity index 69% rename from generators/php/colour.js rename to generators/php/colour.ts index e15cc385c..eefb7cba7 100644 --- a/generators/php/colour.js +++ b/generators/php/colour.ts @@ -5,37 +5,52 @@ */ /** - * @fileoverview Generating PHP for colour blocks. + * @file Generating PHP for colour blocks. */ // Former goog.module ID: Blockly.PHP.colour +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function colour_picker(block, generator) { +export function colour_picker( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Colour picker. const code = generator.quote_(block.getFieldValue('COLOUR')); return [code, Order.ATOMIC]; -}; +} -export function colour_random(block, generator) { +export function colour_random( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Generate a random colour. - const functionName = generator.provideFunction_('colour_random', ` + const functionName = generator.provideFunction_( + 'colour_random', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); } -`); +`, + ); const code = functionName + '()'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_rgb(block, generator) { +export function colour_rgb( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Compose a colour from RGB components expressed as percentages. const red = generator.valueToCode(block, 'RED', Order.NONE) || 0; const green = generator.valueToCode(block, 'GREEN', Order.NONE) || 0; const blue = generator.valueToCode(block, 'BLUE', Order.NONE) || 0; - const functionName = generator.provideFunction_('colour_rgb', ` + const functionName = generator.provideFunction_( + 'colour_rgb', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { $r = round(max(min($r, 100), 0) * 2.55); $g = round(max(min($g, 100), 0) * 2.55); @@ -46,19 +61,23 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); return $hex; } -`); +`, + ); const code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function colour_blend(block, generator) { +export function colour_blend( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Blend two colours together. - const c1 = - generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; - const c2 = - generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; + const c1 = generator.valueToCode(block, 'COLOUR1', Order.NONE) || "'#000000'"; + const c2 = generator.valueToCode(block, 'COLOUR2', Order.NONE) || "'#000000'"; const ratio = generator.valueToCode(block, 'RATIO', Order.NONE) || 0.5; - const functionName = generator.provideFunction_('colour_blend', ` + const functionName = generator.provideFunction_( + 'colour_blend', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { $ratio = max(min($ratio, 1), 0); $r1 = hexdec(substr($c1, 1, 2)); @@ -76,7 +95,8 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); return $hex; } -`); +`, + ); const code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/lists.js b/generators/php/lists.ts similarity index 68% rename from generators/php/lists.js rename to generators/php/lists.ts index d2d5a0842..7ca2639b7 100644 --- a/generators/php/lists.js +++ b/generators/php/lists.ts @@ -5,7 +5,7 @@ */ /** - * @fileoverview Generating PHP for list blocks. + * @file Generating PHP for list blocks. */ /** @@ -22,27 +22,42 @@ // Former goog.module ID: Blockly.generator.lists import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {CreateWithBlock} from '../../blocks/lists.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; -export function lists_create_empty(block, generator) { +export function lists_create_empty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create an empty list. return ['array()', Order.FUNCTION_CALL]; -}; +} -export function lists_create_with(block, generator) { +export function lists_create_with( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a list with any number of elements of any type. - let code = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - code[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; + const createWithBlock = block as CreateWithBlock; + const elements = new Array(createWithBlock.itemCount_); + for (let i = 0; i < createWithBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null'; } - code = 'array(' + code.join(', ') + ')'; + const code = 'array(' + elements.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_repeat(block, generator) { +export function lists_repeat( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a list with one element repeated. - const functionName = generator.provideFunction_('lists_repeat', ` + const functionName = generator.provideFunction_( + 'lists_repeat', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { $array = array(); for ($index = 0; $index < $count; $index++) { @@ -50,16 +65,22 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value, $count) { } return $array; } -`); +`, + ); const element = generator.valueToCode(block, 'ITEM', Order.NONE) || 'null'; const repeatCount = generator.valueToCode(block, 'NUM', Order.NONE) || '0'; const code = functionName + '(' + element + ', ' + repeatCount + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_length(block, generator) { +export function lists_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { // String or array length. - const functionName = generator.provideFunction_('length', ` + const functionName = generator.provideFunction_( + 'length', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); @@ -67,24 +88,29 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { return count($value); } } -`); +`, + ); const list = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + list + ')', Order.FUNCTION_CALL]; -}; +} -export function lists_isEmpty(block, generator) { +export function lists_isEmpty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Is the string null or array empty? const argument0 = - generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || 'array()'; return ['empty(' + argument0 + ')', Order.FUNCTION_CALL]; -}; +} -export function lists_indexOf(block, generator) { +export function lists_indexOf( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Find an item in the list. const argument0 = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; - const argument1 = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; + const argument1 = generator.valueToCode(block, 'VALUE', Order.MEMBER) || '[]'; let errorIndex = ' -1'; let indexAdjustment = ''; if (block.workspace.options.oneBasedIndex) { @@ -94,17 +120,22 @@ export function lists_indexOf(block, generator) { let functionName; if (block.getFieldValue('END') === 'FIRST') { // indexOf - functionName = generator.provideFunction_('indexOf', ` + functionName = generator.provideFunction_( + 'indexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { for ($index = 0; $index < count($haystack); $index++) { if ($haystack[$index] == $needle) return $index${indexAdjustment}; } return ${errorIndex}; } -`); +`, + ); } else { // lastIndexOf - functionName = generator.provideFunction_('lastIndexOf', ` + functionName = generator.provideFunction_( + 'lastIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { $last = ${errorIndex}; for ($index = 0; $index < count($haystack); $index++) { @@ -112,14 +143,18 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($haystack, $needle) { } return $last; } -`); +`, + ); } const code = functionName + '(' + argument1 + ', ' + argument0 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_getIndex(block, generator) { +export function lists_getIndex( + block: Block, + generator: PhpGenerator, +): [string, Order] | string { // Get element at index. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; @@ -127,34 +162,34 @@ export function lists_getIndex(block, generator) { case 'FIRST': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; const code = list + '[0]'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_shift(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_shift(' + list + ');\n'; } break; case 'LAST': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'end(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_pop(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_pop(' + list + ');\n'; } break; @@ -162,17 +197,17 @@ export function lists_getIndex(block, generator) { const at = generator.getAdjusted(block, 'AT'); if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.MEMBER) || 'array()'; const code = list + '[' + at + ']'; return [code, Order.MEMBER]; } else if (mode === 'GET_REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const code = 'array_splice(' + list + ', ' + at + ', 1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; return 'array_splice(' + list + ', ' + at + ', 1);\n'; } break; @@ -180,17 +215,22 @@ export function lists_getIndex(block, generator) { case 'FROM_END': if (mode === 'GET') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; const at = generator.getAdjusted(block, 'AT', 1, true); const code = 'array_slice(' + list + ', ' + at + ', 1)[0]'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE' || mode === 'REMOVE') { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; - const at = - generator.getAdjusted(block, 'AT', 1, false, Order.SUBTRACTION); - const code = 'array_splice(' + list + ', count(' + list + ') - ' + at + - ', 1)[0]'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + const at = generator.getAdjusted( + block, + 'AT', + 1, + false, + Order.SUBTRACTION, + ); + const code = + 'array_splice(' + list + ', count(' + list + ') - ' + at + ', 1)[0]'; if (mode === 'GET_REMOVE') { return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { @@ -200,58 +240,65 @@ export function lists_getIndex(block, generator) { break; case 'RANDOM': { const list = - generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; + generator.valueToCode(block, 'VALUE', Order.NONE) || 'array()'; if (mode === 'GET') { - const functionName = - generator.provideFunction_('lists_get_random_item', ` + const functionName = generator.provideFunction_( + 'lists_get_random_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { return $list[rand(0,count($list)-1)]; } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'GET_REMOVE') { - const functionName = - generator.provideFunction_('lists_get_remove_random_item', ` + const functionName = generator.provideFunction_( + 'lists_get_remove_random_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { $x = rand(0,count($list)-1); unset($list[$x]); return array_values($list); } -`); +`, + ); const code = functionName + '(' + list + ')'; return [code, Order.FUNCTION_CALL]; } else if (mode === 'REMOVE') { - const functionName = - generator.provideFunction_('lists_remove_random_item', ` + const functionName = generator.provideFunction_( + 'lists_remove_random_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list) { unset($list[rand(0,count($list)-1)]); } -`); +`, + ); return functionName + '(' + list + ');\n'; } break; } } throw Error('Unhandled combination (lists_getIndex).'); -}; +} -export function lists_setIndex(block, generator) { +export function lists_setIndex(block: Block, generator: PhpGenerator) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const value = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; + const value = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. - let cachedList; + let cachedList: string; function cacheList() { if (cachedList.match(/^\$\w+$/)) { return ''; } - const listVar = - generator.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); + const listVar = generator.nameDB_!.getDistinctName( + 'tmp_list', + NameType.VARIABLE, + ); const code = listVar + ' = &' + cachedList + ';\n'; cachedList = listVar; return code; @@ -260,24 +307,26 @@ export function lists_setIndex(block, generator) { case 'FIRST': if (mode === 'SET') { const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[0] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; return 'array_unshift(' + list + ', ' + value + ');\n'; } break; case 'LAST': { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; if (mode === 'SET') { - const functionName = - generator.provideFunction_('lists_set_last_item', ` + const functionName = generator.provideFunction_( + 'lists_set_last_item', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { $list[count($list) - 1] = $value; } -`); +`, + ); return functionName + '(' + list + ', ' + value + ');\n'; } else if (mode === 'INSERT') { return 'array_push(' + list + ', ' + value + ');\n'; @@ -288,45 +337,51 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $value) { const at = generator.getAdjusted(block, 'AT'); if (mode === 'SET') { const list = - generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; + generator.valueToCode(block, 'LIST', Order.MEMBER) || 'array()'; return list + '[' + at + '] = ' + value + ';\n'; } else if (mode === 'INSERT') { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; return 'array_splice(' + list + ', ' + at + ', 0, ' + value + ');\n'; } break; } case 'FROM_END': { const list = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const at = generator.getAdjusted(block, 'AT', 1); if (mode === 'SET') { - const functionName = - generator.provideFunction_('lists_set_from_end', ` + const functionName = generator.provideFunction_( + 'lists_set_from_end', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { $list[count($list) - $at] = $value; } -`); +`, + ); return functionName + '(' + list + ', ' + at + ', ' + value + ');\n'; } else if (mode === 'INSERT') { - const functionName = - generator.provideFunction_('lists_insert_from_end', ` + const functionName = generator.provideFunction_( + 'lists_insert_from_end', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { return array_splice($list, count($list) - $at, 0, $value); } -`); +`, + ); return functionName + '(' + list + ', ' + at + ', ' + value + ');\n'; } break; } case 'RANDOM': cachedList = - generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.REFERENCE) || 'array()'; let code = cacheList(); const list = cachedList; - const xVar = - generator.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + const xVar = generator.nameDB_!.getDistinctName( + 'tmp_x', + NameType.VARIABLE, + ); code += xVar + ' = rand(0, count(' + list + ')-1);\n'; if (mode === 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; @@ -338,9 +393,12 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}(&$list, $at, $value) { break; } throw Error('Unhandled combination (lists_setIndex).'); -}; +} -export function lists_getSublist(block, generator) { +export function lists_getSublist( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get sublist. const list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const where1 = block.getFieldValue('WHERE1'); @@ -349,8 +407,9 @@ export function lists_getSublist(block, generator) { if (where1 === 'FIRST' && where2 === 'LAST') { code = list; } else if ( - list.match(/^\$\w+$/) || - (where1 !== 'FROM_END' && where2 === 'FROM_START')) { + list.match(/^\$\w+$/) || + (where1 !== 'FROM_END' && where2 === 'FROM_START') + ) { // If the list is a simple value or doesn't require a call for length, don't // generate a helper function. let at1; @@ -359,8 +418,7 @@ export function lists_getSublist(block, generator) { at1 = generator.getAdjusted(block, 'AT1'); break; case 'FROM_END': - at1 = - generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); + at1 = generator.getAdjusted(block, 'AT1', 1, false, Order.SUBTRACTION); at1 = 'count(' + list + ') - ' + at1; break; case 'FIRST': @@ -373,11 +431,12 @@ export function lists_getSublist(block, generator) { let length; switch (where2) { case 'FROM_START': - at2 = - generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = at2 + ' - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -385,11 +444,12 @@ export function lists_getSublist(block, generator) { length += ' + 1'; break; case 'FROM_END': - at2 = - generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); + at2 = generator.getAdjusted(block, 'AT2', 0, false, Order.SUBTRACTION); length = 'count(' + list + ') - ' + at2 + ' - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -397,8 +457,10 @@ export function lists_getSublist(block, generator) { break; case 'LAST': length = 'count(' + list + ') - '; - if (stringUtils.isNumber(String(at1)) || - String(at1).match(/^\(.+\)$/)) { + if ( + stringUtils.isNumber(String(at1)) || + String(at1).match(/^\(.+\)$/) + ) { length += at1; } else { length += '(' + at1 + ')'; @@ -411,8 +473,9 @@ export function lists_getSublist(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = - generator.provideFunction_('lists_get_sublist', ` + const functionName = generator.provideFunction_( + 'lists_get_sublist', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, $at2) { if ($where1 == 'FROM_END') { $at1 = count($list) - 1 - $at1; @@ -433,20 +496,37 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $where1, $at1, $where2, } return array_slice($list, $at1, $length); } -`); - code = functionName + '(' + list + ', \'' + where1 + '\', ' + at1 + ', \'' + - where2 + '\', ' + at2 + ')'; +`, + ); + code = + functionName + + '(' + + list + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_sort(block, generator) { +export function lists_sort( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for sorting a list. const listCode = - generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; + generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; const direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1; const type = block.getFieldValue('TYPE'); - const functionName = generator.provideFunction_('lists_sort', ` + const functionName = generator.provideFunction_( + 'lists_sort', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { $sortCmpFuncs = array( 'NUMERIC' => 'strnatcasecmp', @@ -461,17 +541,20 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list, $type, $direction) { } return $list2; } -`); +`, + ); const sortCode = - functionName + '(' + listCode + ', "' + type + '", ' + direction + ')'; + functionName + '(' + listCode + ', "' + type + '", ' + direction + ')'; return [sortCode, Order.FUNCTION_CALL]; -}; +} -export function lists_split(block, generator) { +export function lists_split( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for splitting text into a list, or joining a list into text. let value_input = generator.valueToCode(block, 'INPUT', Order.NONE); - const value_delim = - generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; + const value_delim = generator.valueToCode(block, 'DELIM', Order.NONE) || "''"; const mode = block.getFieldValue('MODE'); let functionName; if (mode === 'SPLIT') { @@ -489,11 +572,14 @@ export function lists_split(block, generator) { } const code = functionName + '(' + value_delim + ', ' + value_input + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function lists_reverse(block, generator) { +export function lists_reverse( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Block for reversing a list. const list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; const code = 'array_reverse(' + list + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/logic.js b/generators/php/logic.ts similarity index 51% rename from generators/php/logic.js rename to generators/php/logic.ts index 0968c1ea4..8aaa5c892 100644 --- a/generators/php/logic.js +++ b/generators/php/logic.ts @@ -5,35 +5,43 @@ */ /** - * @fileoverview Generating PHP for logic blocks. + * @file Generating PHP for logic blocks. */ // Former goog.module ID: Blockly.PHP.logic +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function controls_if(block, generator) { +export function controls_if(block: Block, generator: PhpGenerator) { // If/elseif/else condition. let n = 0; - let code = '', branchCode, conditionCode; + let code = '', + branchCode, + conditionCode; if (generator.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. code += generator.injectId(generator.STATEMENT_PREFIX, block); } do { conditionCode = - generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; + generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false'; branchCode = generator.statementToCode(block, 'DO' + n); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } - code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + - branchCode + '}'; + code += + (n > 0 ? ' else ' : '') + + 'if (' + + conditionCode + + ') {\n' + + branchCode + + '}'; n++; } while (block.getInput('IF' + n)); @@ -41,36 +49,48 @@ export function controls_if(block, generator) { branchCode = generator.statementToCode(block, 'ELSE'); if (generator.STATEMENT_SUFFIX) { branchCode = - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT) + - branchCode; + generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ) + branchCode; } code += ' else {\n' + branchCode + '}'; } return code + '\n'; -}; +} export const controls_ifelse = controls_if; -export function logic_compare(block, generator) { +export function logic_compare( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Comparison operator. - const OPERATORS = - {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; - const operator = OPERATORS[block.getFieldValue('OP')]; - const order = (operator === '==' || operator === '!=') ? Order.EQUALITY : - Order.RELATIONAL; + const OPERATORS = { + 'EQ': '==', + 'NEQ': '!=', + 'LT': '<', + 'LTE': '<=', + 'GT': '>', + 'GTE': '>=', + }; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('OP') as OperatorOption]; + const order = + operator === '==' || operator === '!=' ? Order.EQUALITY : Order.RELATIONAL; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_operation(block, generator) { +export function logic_operation( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Operations 'and', 'or'. - const operator = (block.getFieldValue('OP') === 'AND') ? '&&' : '||'; - const order = - (operator === '&&') ? Order.LOGICAL_AND : Order.LOGICAL_OR; + const operator = block.getFieldValue('OP') === 'AND' ? '&&' : '||'; + const order = operator === '&&' ? Order.LOGICAL_AND : Order.LOGICAL_OR; let argument0 = generator.valueToCode(block, 'A', order); let argument1 = generator.valueToCode(block, 'B', order); if (!argument0 && !argument1) { @@ -79,7 +99,7 @@ export function logic_operation(block, generator) { argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. - const defaultArgument = (operator === '&&') ? 'true' : 'false'; + const defaultArgument = operator === '&&' ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } @@ -89,35 +109,47 @@ export function logic_operation(block, generator) { } const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; -}; +} -export function logic_negate(block, generator) { +export function logic_negate( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Negation. const order = Order.LOGICAL_NOT; const argument0 = generator.valueToCode(block, 'BOOL', order) || 'true'; const code = '!' + argument0; return [code, order]; -}; +} -export function logic_boolean(block, generator) { +export function logic_boolean( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Boolean values true and false. - const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'true' : 'false'; + const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false'; return [code, Order.ATOMIC]; -}; +} -export function logic_null(block, generator) { +export function logic_null( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Null data type. return ['null', Order.ATOMIC]; -}; +} -export function logic_ternary(block, generator) { +export function logic_ternary( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Ternary operator. const value_if = - generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; + generator.valueToCode(block, 'IF', Order.CONDITIONAL) || 'false'; const value_then = - generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'THEN', Order.CONDITIONAL) || 'null'; const value_else = - generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; + generator.valueToCode(block, 'ELSE', Order.CONDITIONAL) || 'null'; const code = value_if + ' ? ' + value_then + ' : ' + value_else; return [code, Order.CONDITIONAL]; -}; +} diff --git a/generators/php/loops.js b/generators/php/loops.ts similarity index 57% rename from generators/php/loops.js rename to generators/php/loops.ts index 981a4e219..ae87dbb29 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.ts @@ -5,17 +5,19 @@ */ /** - * @fileoverview Generating PHP for loop blocks. + * @file Generating PHP for loop blocks. */ // Former goog.module ID: Blockly.PHP.loops import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import type {ControlFlowInLoopBlock} from '../../blocks/loops.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function controls_repeat_ext(block, generator) { +export function controls_repeat_ext(block: Block, generator: PhpGenerator) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -28,55 +30,80 @@ export function controls_repeat_ext(block, generator) { let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; - const loopVar = - generator.nameDB_.getDistinctName('count', NameType.VARIABLE); + const loopVar = generator.nameDB_!.getDistinctName( + 'count', + NameType.VARIABLE, + ); let endVar = repeats; if (!repeats.match(/^\w+$/) && !stringUtils.isNumber(repeats)) { - endVar = - generator.nameDB_.getDistinctName('repeat_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + 'repeat_end', + NameType.VARIABLE, + ); code += endVar + ' = ' + repeats + ';\n'; } - code += 'for (' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + - loopVar + '++) {\n' + branch + '}\n'; + code += + 'for (' + + loopVar + + ' = 0; ' + + loopVar + + ' < ' + + endVar + + '; ' + + loopVar + + '++) {\n' + + branch + + '}\n'; return code; -}; +} export const controls_repeat = controls_repeat_ext; -export function controls_whileUntil(block, generator) { +export function controls_whileUntil(block: Block, generator: PhpGenerator) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; let argument0 = - generator.valueToCode( - block, 'BOOL', until ? Order.LOGICAL_NOT : Order.NONE) || - 'false'; + generator.valueToCode( + block, + 'BOOL', + until ? Order.LOGICAL_NOT : Order.NONE, + ) || 'false'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; -}; +} -export function controls_for(block, generator) { +export function controls_for(block: Block, generator: PhpGenerator) { // For loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; - const argument1 = - generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; - const increment = - generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; + generator.valueToCode(block, 'FROM', Order.ASSIGNMENT) || '0'; + const argument1 = generator.valueToCode(block, 'TO', Order.ASSIGNMENT) || '0'; + const increment = generator.valueToCode(block, 'BY', Order.ASSIGNMENT) || '1'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code; - if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && - stringUtils.isNumber(increment)) { + if ( + stringUtils.isNumber(argument0) && + stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment) + ) { // All arguments are simple numbers. const up = Number(argument0) <= Number(argument1); - code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + - (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; + code = + 'for (' + + variable0 + + ' = ' + + argument0 + + '; ' + + variable0 + + (up ? ' <= ' : ' >= ') + + argument1 + + '; ' + + variable0; const step = Math.abs(Number(increment)); if (step === 1) { code += up ? '++' : '--'; @@ -89,55 +116,78 @@ export function controls_for(block, generator) { // Cache non-trivial values to variables to prevent repeated look-ups. let startVar = argument0; if (!argument0.match(/^\w+$/) && !stringUtils.isNumber(argument0)) { - startVar = - generator.nameDB_.getDistinctName( - variable0 + '_start', NameType.VARIABLE); + startVar = generator.nameDB_!.getDistinctName( + variable0 + '_start', + NameType.VARIABLE, + ); code += startVar + ' = ' + argument0 + ';\n'; } let endVar = argument1; if (!argument1.match(/^\w+$/) && !stringUtils.isNumber(argument1)) { - endVar = - generator.nameDB_.getDistinctName( - variable0 + '_end', NameType.VARIABLE); + endVar = generator.nameDB_!.getDistinctName( + variable0 + '_end', + NameType.VARIABLE, + ); code += endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. - const incVar = - generator.nameDB_.getDistinctName( - variable0 + '_inc', NameType.VARIABLE); + const incVar = generator.nameDB_!.getDistinctName( + variable0 + '_inc', + NameType.VARIABLE, + ); code += incVar + ' = '; if (stringUtils.isNumber(increment)) { - code += Math.abs(increment) + ';\n'; + code += Math.abs(Number(increment)) + ';\n'; } else { code += 'abs(' + increment + ');\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += generator.INDENT + incVar + ' = -' + incVar + ';\n'; code += '}\n'; - code += 'for (' + variable0 + ' = ' + startVar + '; ' + incVar + - ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + - ' >= ' + endVar + '; ' + variable0 + ' += ' + incVar + ') {\n' + - branch + '}\n'; + code += + 'for (' + + variable0 + + ' = ' + + startVar + + '; ' + + incVar + + ' >= 0 ? ' + + variable0 + + ' <= ' + + endVar + + ' : ' + + variable0 + + ' >= ' + + endVar + + '; ' + + variable0 + + ' += ' + + incVar + + ') {\n' + + branch + + '}\n'; } return code; -}; +} -export function controls_forEach(block, generator) { +export function controls_forEach(block: Block, generator: PhpGenerator) { // For each loop. - const variable0 = - generator.getVariableName(block.getFieldValue('VAR')); + const variable0 = generator.getVariableName(block.getFieldValue('VAR')); const argument0 = - generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; + generator.valueToCode(block, 'LIST', Order.ASSIGNMENT) || '[]'; let branch = generator.statementToCode(block, 'DO'); branch = generator.addLoopTrap(branch, block); let code = ''; code += - 'foreach (' + argument0 + ' as ' + variable0 + ') {\n' + branch + '}\n'; + 'foreach (' + argument0 + ' as ' + variable0 + ') {\n' + branch + '}\n'; return code; -}; +} -export function controls_flow_statements(block, generator) { +export function controls_flow_statements( + block: Block, + generator: PhpGenerator, +) { // Flow statements: continue, break. let xfix = ''; if (generator.STATEMENT_PREFIX) { @@ -150,7 +200,7 @@ export function controls_flow_statements(block, generator) { xfix += generator.injectId(generator.STATEMENT_SUFFIX, block); } if (generator.STATEMENT_PREFIX) { - const loop = block.getSurroundLoop(); + const loop = (block as ControlFlowInLoopBlock).getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. @@ -165,4 +215,4 @@ export function controls_flow_statements(block, generator) { return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); -}; +} diff --git a/generators/php/math.js b/generators/php/math.ts similarity index 70% rename from generators/php/math.js rename to generators/php/math.ts index f1985949e..6218bf4d1 100644 --- a/generators/php/math.js +++ b/generators/php/math.ts @@ -5,45 +5,55 @@ */ /** - * @fileoverview Generating PHP for math blocks. + * @file Generating PHP for math blocks. */ // Former goog.module ID: Blockly.PHP.math +import type {Block} from '../../core/block.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function math_number(block, generator) { +export function math_number( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Numeric value. - let code = Number(block.getFieldValue('NUM')); - const order = code >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION; - if (code === Infinity) { - code = 'INF'; - } else if (code === -Infinity) { - code = '-INF'; + let number = Number(block.getFieldValue('NUM')); + if (number === Infinity) { + return ['INF', Order.ATOMIC]; + } else if (number === -Infinity) { + return ['-INF', Order.UNARY_NEGATION]; } - return [code, order]; -}; + return [String(number), number >= 0 ? Order.ATOMIC : Order.UNARY_NEGATION]; +} -export function math_arithmetic(block, generator) { +export function math_arithmetic( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Basic arithmetic operators, and power. - const OPERATORS = { + const OPERATORS: Record = { 'ADD': [' + ', Order.ADDITION], 'MINUS': [' - ', Order.SUBTRACTION], 'MULTIPLY': [' * ', Order.MULTIPLICATION], 'DIVIDE': [' / ', Order.DIVISION], 'POWER': [' ** ', Order.POWER], }; - const tuple = OPERATORS[block.getFieldValue('OP')]; + type OperatorOption = keyof typeof OPERATORS; + const tuple = OPERATORS[block.getFieldValue('OP') as OperatorOption]; const operator = tuple[0]; const order = tuple[1]; const argument0 = generator.valueToCode(block, 'A', order) || '0'; const argument1 = generator.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; -}; +} -export function math_single(block, generator) { +export function math_single( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; @@ -122,11 +132,14 @@ export function math_single(block, generator) { throw Error('Unknown math operator: ' + operator); } return [code, Order.DIVISION]; -}; +} -export function math_constant(block, generator) { +export function math_constant( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. - const CONSTANTS = { + const CONSTANTS: Record = { 'PI': ['M_PI', Order.ATOMIC], 'E': ['M_E', Order.ATOMIC], 'GOLDEN_RATIO': ['(1 + sqrt(5)) / 2', Order.DIVISION], @@ -134,13 +147,20 @@ export function math_constant(block, generator) { 'SQRT1_2': ['M_SQRT1_2', Order.ATOMIC], 'INFINITY': ['INF', Order.ATOMIC], }; - return CONSTANTS[block.getFieldValue('CONSTANT')]; -}; + type ConstantOption = keyof typeof CONSTANTS; + return CONSTANTS[block.getFieldValue('CONSTANT') as ConstantOption]; +} -export function math_number_property(block, generator) { +export function math_number_property( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. - const PROPERTIES = { + const PROPERTIES: Record< + string, + [string, string, Order, Order] | [null, null, Order, Order] + > = { 'EVEN': ['', ' % 2 == 0', Order.MODULUS, Order.EQUALITY], 'ODD': ['', ' % 2 == 1', Order.MODULUS, Order.EQUALITY], 'WHOLE': ['is_int(', ')', Order.NONE, Order.FUNCTION_CALL], @@ -149,15 +169,18 @@ export function math_number_property(block, generator) { 'DIVISIBLE_BY': [null, null, Order.MODULUS, Order.EQUALITY], 'PRIME': [null, null, Order.NONE, Order.FUNCTION_CALL], }; - const dropdownProperty = block.getFieldValue('PROPERTY'); + type PropertyOption = keyof typeof PROPERTIES; + const dropdownProperty = block.getFieldValue('PROPERTY') as PropertyOption; const [prefix, suffix, inputOrder, outputOrder] = - PROPERTIES[dropdownProperty]; - const numberToCheck = generator.valueToCode(block, 'NUMBER_TO_CHECK', - inputOrder) || '0'; + PROPERTIES[dropdownProperty]; + const numberToCheck = + generator.valueToCode(block, 'NUMBER_TO_CHECK', inputOrder) || '0'; let code; if (dropdownProperty === 'PRIME') { // Prime is a special case as it is not a one-liner test. - const functionName = generator.provideFunction_('math_isPrime', ` + const functionName = generator.provideFunction_( + 'math_isPrime', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { // https://en.wikipedia.org/wiki/Primality_test#Naive_methods if ($n == 2 || $n == 3) { @@ -176,37 +199,39 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($n) { } return true; } -`); +`, + ); code = functionName + '(' + numberToCheck + ')'; } else if (dropdownProperty === 'DIVISIBLE_BY') { - const divisor = generator.valueToCode(block, 'DIVISOR', - Order.MODULUS) || '0'; + const divisor = + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; if (divisor === '0') { return ['false', Order.ATOMIC]; - } code = numberToCheck + ' % ' + divisor + ' == 0'; } else { code = prefix + numberToCheck + suffix; } return [code, outputOrder]; -}; +} -export function math_change(block, generator) { +export function math_change(block: Block, generator: PhpGenerator) { // Add to a variable in place. const argument0 = - generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); + generator.valueToCode(block, 'DELTA', Order.ADDITION) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); return varName + ' += ' + argument0 + ';\n'; -}; +} // Rounding functions have a single operand. export const math_round = math_single; // Trigonometry functions have a single operand. export const math_trig = math_single; -export function math_on_list(block, generator) { +export function math_on_list( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Math functions for lists. const func = block.getFieldValue('OP'); let list; @@ -214,40 +239,43 @@ export function math_on_list(block, generator) { switch (func) { case 'SUM': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'array_sum(' + list + ')'; break; case 'MIN': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'min(' + list + ')'; break; case 'MAX': list = - generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) - || 'array()'; + generator.valueToCode(block, 'LIST', Order.FUNCTION_CALL) || 'array()'; code = 'max(' + list + ')'; break; case 'AVERAGE': { - const functionName = generator.provideFunction_('math_mean', ` + const functionName = generator.provideFunction_( + 'math_mean', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($myList) { return array_sum($myList) / count($myList); } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || 'array()'; code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - const functionName = generator.provideFunction_('math_median', ` + const functionName = generator.provideFunction_( + 'math_median', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($arr) { sort($arr,SORT_NUMERIC); return (count($arr) % 2) ? $arr[floor(count($arr) / 2)] : ($arr[floor(count($arr) / 2)] + $arr[floor(count($arr) / 2) - 1]) / 2; } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -256,7 +284,9 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($arr) { // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. - const functionName = generator.provideFunction_('math_modes', ` + const functionName = generator.provideFunction_( + 'math_modes', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { if (empty($values)) return array(); $counts = array_count_values($values); @@ -264,14 +294,16 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($values) { $modes = array_keys($counts, current($counts), true); return $modes; } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - const functionName = - generator.provideFunction_('math_standard_deviation', ` + const functionName = generator.provideFunction_( + 'math_standard_deviation', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { $n = count($numbers); if (!$n) return null; @@ -279,18 +311,22 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($numbers) { foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2); return sqrt(array_sum($devs) / (count($devs) - 1)); } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; } case 'RANDOM': { - const functionName = generator.provideFunction_('math_random_list', ` + const functionName = generator.provideFunction_( + 'math_random_list', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { $x = rand(0, count($list)-1); return $list[$x]; } -`); +`, + ); list = generator.valueToCode(block, 'LIST', Order.NONE) || '[]'; code = functionName + '(' + list + ')'; break; @@ -299,56 +335,74 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($list) { throw Error('Unknown operator: ' + func); } return [code, Order.FUNCTION_CALL]; -}; +} -export function math_modulo(block, generator) { +export function math_modulo( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Remainder computation. const argument0 = - generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVIDEND', Order.MODULUS) || '0'; const argument1 = - generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; + generator.valueToCode(block, 'DIVISOR', Order.MODULUS) || '0'; const code = argument0 + ' % ' + argument1; return [code, Order.MODULUS]; -}; +} -export function math_constrain(block, generator) { +export function math_constrain( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Constrain a number between two limits. const argument0 = generator.valueToCode(block, 'VALUE', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'LOW', Order.NONE) || '0'; const argument2 = - generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; + generator.valueToCode(block, 'HIGH', Order.NONE) || 'Infinity'; const code = - 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; + 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_int(block, generator) { +export function math_random_int( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Random integer between [X] and [Y]. const argument0 = generator.valueToCode(block, 'FROM', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'TO', Order.NONE) || '0'; - const functionName = generator.provideFunction_('math_random_int', ` + const functionName = generator.provideFunction_( + 'math_random_int', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($a, $b) { if ($a > $b) { return rand($b, $a); } return rand($a, $b); } -`); +`, + ); const code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function math_random_float(block, generator) { +export function math_random_float( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Random fraction between 0 and 1. return ['(float)rand()/(float)getrandmax()', Order.FUNCTION_CALL]; -}; +} -export function math_atan2(block, generator) { +export function math_atan2( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Arctangent of point (X, Y) in degrees from -180 to 180. const argument0 = generator.valueToCode(block, 'X', Order.NONE) || '0'; const argument1 = generator.valueToCode(block, 'Y', Order.NONE) || '0'; return [ 'atan2(' + argument1 + ', ' + argument0 + ') / pi() * 180', - Order.DIVISION + Order.DIVISION, ]; -}; +} diff --git a/generators/php/php_generator.js b/generators/php/php_generator.js deleted file mode 100644 index dfe6f8543..000000000 --- a/generators/php/php_generator.js +++ /dev/null @@ -1,307 +0,0 @@ -/** - * @license - * Copyright 2015 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Helper functions for generating PHP for blocks. - * @suppress {checkTypes|globalThis} - */ - -// Former goog.module ID: Blockly.PHP - -import * as stringUtils from '../../core/utils/string.js'; -// import type {Block} from '../../core/block.js'; -import {CodeGenerator} from '../../core/generator.js'; -import {Names} from '../../core/names.js'; -// import type {Workspace} from '../../core/workspace.js'; -import {inputTypes} from '../../core/inputs/input_types.js'; - - -/** - * Order of operation ENUMs. - * http://php.net/manual/en/language.operators.precedence.php - * @enum {number} - */ -export const Order = { - ATOMIC: 0, // 0 "" ... - CLONE: 1, // clone - NEW: 1, // new - MEMBER: 2.1, // [] - FUNCTION_CALL: 2.2, // () - POWER: 3, // ** - INCREMENT: 4, // ++ - DECREMENT: 4, // -- - BITWISE_NOT: 4, // ~ - CAST: 4, // (int) (float) (string) (array) ... - SUPPRESS_ERROR: 4, // @ - INSTANCEOF: 5, // instanceof - LOGICAL_NOT: 6, // ! - UNARY_PLUS: 7.1, // + - UNARY_NEGATION: 7.2, // - - MULTIPLICATION: 8.1, // * - DIVISION: 8.2, // / - MODULUS: 8.3, // % - ADDITION: 9.1, // + - SUBTRACTION: 9.2, // - - STRING_CONCAT: 9.3, // . - BITWISE_SHIFT: 10, // << >> - RELATIONAL: 11, // < <= > >= - EQUALITY: 12, // == != === !== <> <=> - REFERENCE: 13, // & - BITWISE_AND: 13, // & - BITWISE_XOR: 14, // ^ - BITWISE_OR: 15, // | - LOGICAL_AND: 16, // && - LOGICAL_OR: 17, // || - IF_NULL: 18, // ?? - CONDITIONAL: 19, // ?: - ASSIGNMENT: 20, // = += -= *= /= %= <<= >>= ... - LOGICAL_AND_WEAK: 21, // and - LOGICAL_XOR: 22, // xor - LOGICAL_OR_WEAK: 23, // or - NONE: 99, // (...) -}; - -export class PhpGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - * @type {!Array>} - */ - ORDER_OVERRIDES = [ - // (foo()).bar() -> foo().bar() - // (foo())[0] -> foo()[0] - [Order.MEMBER, Order.FUNCTION_CALL], - // (foo[0])[1] -> foo[0][1] - // (foo.bar).baz -> foo.bar.baz - [Order.MEMBER, Order.MEMBER], - // !(!foo) -> !!foo - [Order.LOGICAL_NOT, Order.LOGICAL_NOT], - // a * (b * c) -> a * b * c - [Order.MULTIPLICATION, Order.MULTIPLICATION], - // a + (b + c) -> a + b + c - [Order.ADDITION, Order.ADDITION], - // a && (b && c) -> a && b && c - [Order.LOGICAL_AND, Order.LOGICAL_AND], - // a || (b || c) -> a || b || c - [Order.LOGICAL_OR, Order.LOGICAL_OR] - ]; - - constructor(name) { - super(name ?? 'PHP'); - this.isInitialized = false; - - // Copy Order values onto instance for backwards compatibility - // while ensuring they are not part of the publically-advertised - // API. - // - // TODO(#7085): deprecate these in due course. (Could initially - // replace data properties with get accessors that call - // deprecate.warn().) - for (const key in Order) { - this['ORDER_' + key] = Order[key]; - } - - // List of illegal variable names. This is not intended to be a - // security feature. Blockly is 100% client-side, so bypassing - // this list is trivial. This is intended to prevent users from - // accidentally clobbering a built-in object or function. - this.addReservedWords( - // http://php.net/manual/en/reserved.keywords.php - '__halt_compiler,abstract,and,array,as,break,callable,case,catch,class,' + - 'clone,const,continue,declare,default,die,do,echo,else,elseif,empty,' + - 'enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,' + - 'extends,final,for,foreach,function,global,goto,if,implements,include,' + - 'include_once,instanceof,insteadof,interface,isset,list,namespace,new,' + - 'or,print,private,protected,public,require,require_once,return,static,' + - 'switch,throw,trait,try,unset,use,var,while,xor,' + - // http://php.net/manual/en/reserved.constants.php - 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,' + - 'PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,' + - 'PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,' + - 'PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,' + - 'PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,' + - 'PHP_SYSCONFDIR,PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,' + - 'PHP_CONFIG_FILE_SCAN_DIR,PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,' + - 'E_NOTICE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,' + - 'E_COMPILE_WARNING,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE,' + - 'E_DEPRECATED,E_USER_DEPRECATED,E_ALL,E_STRICT,' + - '__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,__FILE__,' + - '__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__' - ); - } - - /** - * Initialise the database of variable names. - * @param {!Workspace} workspace Workspace to generate code from. - */ - init(workspace) { - super.init(workspace); - - if (!this.nameDB_) { - this.nameDB_ = new Names(this.RESERVED_WORDS_, '$'); - } else { - this.nameDB_.reset(); - } - - this.nameDB_.setVariableMap(workspace.getVariableMap()); - this.nameDB_.populateVariables(workspace); - this.nameDB_.populateProcedures(workspace); - - this.isInitialized = true; - }; - - /** - * Prepend the generated code with the variable definitions. - * @param {string} code Generated code. - * @return {string} Completed code. - */ - finish(code) { - // Convert the definitions dictionary into a list. - const definitions = Object.values(this.definitions_); - // Call Blockly.CodeGenerator's finish. - code = super.finish(code); - this.isInitialized = false; - - this.nameDB_.reset(); - return definitions.join('\n\n') + '\n\n\n' + code; - }; - - /** - * Naked values are top-level blocks with outputs that aren't plugged into - * anything. A trailing semicolon is needed to make this legal. - * @param {string} line Line of generated code. - * @return {string} Legal line of code. - */ - scrubNakedValue(line) { - return line + ';\n'; - }; - - /** - * Encode a string as a properly escaped PHP string, complete with - * quotes. - * @param {string} string Text to encode. - * @return {string} PHP string. - */ - quote_(string) { - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n') - .replace(/'/g, '\\\''); - return '\'' + string + '\''; - }; - - /** - * Encode a string as a properly escaped multiline PHP string, complete with - * quotes. - * @param {string} string Text to encode. - * @return {string} PHP string. - */ - multiline_quote_(string) { - const lines = string.split(/\n/g).map(this.quote_); - // Join with the following, plus a newline: - // . "\n" . - // Newline escaping only works in double-quoted strings. - return lines.join(' . \"\\n\" .\n'); - }; - - /** - * Common tasks for generating PHP from blocks. - * Handles comments for the specified block and any connected value blocks. - * Calls any statements following this block. - * @param {!Block} block The current block. - * @param {string} code The PHP code created for this block. - * @param {boolean=} opt_thisOnly True to generate code for only this - * statement. - * @return {string} PHP code with comments and subsequent blocks added. - * @protected - */ - scrub_(block, code, opt_thisOnly) { - let commentCode = ''; - // Only collect comments for blocks that aren't inline. - if (!block.outputConnection || !block.outputConnection.targetConnection) { - // Collect comment for this block. - let comment = block.getCommentText(); - if (comment) { - comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3); - commentCode += this.prefixLines(comment, '// ') + '\n'; - } - // Collect comments for all value arguments. - // Don't collect comments for nested statements. - for (let i = 0; i < block.inputList.length; i++) { - if (block.inputList[i].type === inputTypes.VALUE) { - const childBlock = block.inputList[i].connection.targetBlock(); - if (childBlock) { - comment = this.allNestedComments(childBlock); - if (comment) { - commentCode += this.prefixLines(comment, '// '); - } - } - } - } - } - const nextBlock = - block.nextConnection && block.nextConnection.targetBlock(); - const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock); - return commentCode + code + nextCode; - }; - - /** - * Gets a property and adjusts the value while taking into account indexing. - * @param {!Block} block The block. - * @param {string} atId The property ID of the element to get. - * @param {number=} opt_delta Value to add. - * @param {boolean=} opt_negate Whether to negate the value. - * @param {number=} opt_order The highest order acting on this value. - * @return {string|number} - */ - getAdjusted(block, atId, opt_delta, opt_negate, opt_order) { - let delta = opt_delta || 0; - let order = opt_order || this.ORDER_NONE; - if (block.workspace.options.oneBasedIndex) { - delta--; - } - let defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; - let outerOrder = order; - let innerOrder; - if (delta > 0) { - outerOrder = this.ORDER_ADDITION; - innerOrder = this.ORDER_ADDITION; - } else if (delta < 0) { - outerOrder = this.ORDER_SUBTRACTION; - innerOrder = this.ORDER_SUBTRACTION; - } else if (opt_negate) { - outerOrder = this.ORDER_UNARY_NEGATION; - innerOrder = this.ORDER_UNARY_NEGATION; - } - let at = this.valueToCode(block, atId, outerOrder) || defaultAtIndex; - - if (stringUtils.isNumber(at)) { - // If the index is a naked number, adjust it right now. - at = Number(at) + delta; - if (opt_negate) { - at = -at; - } - } else { - // If the index is dynamic, adjust it in code. - if (delta > 0) { - at = at + ' + ' + delta; - } else if (delta < 0) { - at = at + ' - ' + -delta; - } - if (opt_negate) { - if (delta) { - at = '-(' + at + ')'; - } else { - at = '-' + at; - } - } - innerOrder = Math.floor(innerOrder); - order = Math.floor(order); - if (innerOrder && order >= innerOrder) { - at = '(' + at + ')'; - } - } - return at; - }; -} diff --git a/generators/php/php_generator.ts b/generators/php/php_generator.ts new file mode 100644 index 000000000..ecdfb76fd --- /dev/null +++ b/generators/php/php_generator.ts @@ -0,0 +1,320 @@ +/** + * @license + * Copyright 2015 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file PHP code generator class, including helper methods for + * generating PHP for blocks. + */ + +// Former goog.module ID: Blockly.PHP + +import * as stringUtils from '../../core/utils/string.js'; +import type {Block} from '../../core/block.js'; +import {CodeGenerator} from '../../core/generator.js'; +import {Names} from '../../core/names.js'; +import type {Workspace} from '../../core/workspace.js'; +import {inputTypes} from '../../core/inputs/input_types.js'; + +/** + * Order of operation ENUMs. + * http://php.net/manual/en/language.operators.precedence.php + */ +// prettier-ignore +export enum Order { + ATOMIC = 0, // 0 "" ... + CLONE = 1, // clone + NEW = 1, // new + MEMBER = 2.1, // [] + FUNCTION_CALL = 2.2, // () + POWER = 3, // ** + INCREMENT = 4, // ++ + DECREMENT = 4, // -- + BITWISE_NOT = 4, // ~ + CAST = 4, // (int) (float) (string) (array) ... + SUPPRESS_ERROR = 4, // @ + INSTANCEOF = 5, // instanceof + LOGICAL_NOT = 6, // ! + UNARY_PLUS = 7.1, // + + UNARY_NEGATION = 7.2, // - + MULTIPLICATION = 8.1, // * + DIVISION = 8.2, // / + MODULUS = 8.3, // % + ADDITION = 9.1, // + + SUBTRACTION = 9.2, // - + STRING_CONCAT = 9.3, // . + BITWISE_SHIFT = 10, // << >> + RELATIONAL = 11, // < <= > >= + EQUALITY = 12, // == != === !== <> <=> + REFERENCE = 13, // & + BITWISE_AND = 13, // & + BITWISE_XOR = 14, // ^ + BITWISE_OR = 15, // | + LOGICAL_AND = 16, // && + LOGICAL_OR = 17, // || + IF_NULL = 18, // ?? + CONDITIONAL = 19, // ?: + ASSIGNMENT = 20, // = += -= *= /= %= <<= >>= ... + LOGICAL_AND_WEAK = 21, // and + LOGICAL_XOR = 22, // xor + LOGICAL_OR_WEAK = 23, // or + NONE = 99, // (...) +} + +export class PhpGenerator extends CodeGenerator { + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ + // (foo()).bar() -> foo().bar() + // (foo())[0] -> foo()[0] + [Order.MEMBER, Order.FUNCTION_CALL], + // (foo[0])[1] -> foo[0][1] + // (foo.bar).baz -> foo.bar.baz + [Order.MEMBER, Order.MEMBER], + // !(!foo) -> !!foo + [Order.LOGICAL_NOT, Order.LOGICAL_NOT], + // a * (b * c) -> a * b * c + [Order.MULTIPLICATION, Order.MULTIPLICATION], + // a + (b + c) -> a + b + c + [Order.ADDITION, Order.ADDITION], + // a && (b && c) -> a && b && c + [Order.LOGICAL_AND, Order.LOGICAL_AND], + // a || (b || c) -> a || b || c + [Order.LOGICAL_OR, Order.LOGICAL_OR], + ]; + + /** @param name Name of the language the generator is for. */ + constructor(name = 'PHP') { + super(name); + this.isInitialized = false; + + // Copy Order values onto instance for backwards compatibility + // while ensuring they are not part of the publically-advertised + // API. + // + // TODO(#7085): deprecate these in due course. (Could initially + // replace data properties with get accessors that call + // deprecate.warn().) + for (const key in Order) { + // Must assign Order[key] to a temporary to get the type guard to work; + // see https://github.com/microsoft/TypeScript/issues/10530. + const value = Order[key]; + // Skip reverse-lookup entries in the enum. Due to + // https://github.com/microsoft/TypeScript/issues/55713 this (as + // of TypeScript 5.5.2) actually narrows the type of value to + // never - but that still allows the following assignment to + // succeed. + if (typeof value === 'string') continue; + (this as unknown as Record)['ORDER_' + key] = value; + } + + // List of illegal variable names. This is not intended to be a + // security feature. Blockly is 100% client-side, so bypassing + // this list is trivial. This is intended to prevent users from + // accidentally clobbering a built-in object or function. + this.addReservedWords( + // http://php.net/manual/en/reserved.keywords.php + '__halt_compiler,abstract,and,array,as,break,callable,case,catch,class,' + + 'clone,const,continue,declare,default,die,do,echo,else,elseif,empty,' + + 'enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,' + + 'extends,final,for,foreach,function,global,goto,if,implements,include,' + + 'include_once,instanceof,insteadof,interface,isset,list,namespace,new,' + + 'or,print,private,protected,public,require,require_once,return,static,' + + 'switch,throw,trait,try,unset,use,var,while,xor,' + + // http://php.net/manual/en/reserved.constants.php + 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,' + + 'PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,' + + 'PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,' + + 'PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,' + + 'PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,' + + 'PHP_SYSCONFDIR,PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,' + + 'PHP_CONFIG_FILE_SCAN_DIR,PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,' + + 'E_NOTICE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,' + + 'E_COMPILE_WARNING,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE,' + + 'E_DEPRECATED,E_USER_DEPRECATED,E_ALL,E_STRICT,' + + '__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,__FILE__,' + + '__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__', + ); + } + + /** + * Initialise the database of variable names. + * + * @param workspace Workspace to generate code from. + */ + init(workspace: Workspace) { + super.init(workspace); + + if (!this.nameDB_) { + this.nameDB_ = new Names(this.RESERVED_WORDS_, '$'); + } else { + this.nameDB_.reset(); + } + + this.nameDB_.setVariableMap(workspace.getVariableMap()); + this.nameDB_.populateVariables(workspace); + this.nameDB_.populateProcedures(workspace); + + this.isInitialized = true; + } + + /** + * Prepend the generated code with the variable definitions. + * + * @param code Generated code. + * @returns Completed code. + */ + finish(code: string): string { + // Convert the definitions dictionary into a list. + const definitions = Object.values(this.definitions_); + // Call Blockly.CodeGenerator's finish. + code = super.finish(code); + this.isInitialized = false; + + this.nameDB_!.reset(); + return definitions.join('\n\n') + '\n\n\n' + code; + } + + /** + * Naked values are top-level blocks with outputs that aren't plugged into + * anything. + * + * @param line Line of generated code. + * @returns Legal line of code. + */ + scrubNakedValue(line: string): string { + return line + ';\n'; + } + + /** + * Encode a string as a properly escaped PHP string, complete with + * quotes. + * + * @param string Text to encode. + * @returns PHP string. + */ + quote_(string: string): string { + string = string + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\\n') + .replace(/'/g, "\\'"); + return "'" + string + "'"; + } + + /** + * Encode a string as a properly escaped multiline PHP string, complete with + * quotes. + * @param string Text to encode. + * @returns PHP string. + */ + multiline_quote_(string: string): string { + const lines = string.split(/\n/g).map(this.quote_); + // Join with the following, plus a newline: + // . "\n" . + // Newline escaping only works in double-quoted strings. + return lines.join(' . "\\n" .\n'); + } + + /** + * Common tasks for generating PHP from blocks. + * Handles comments for the specified block and any connected value blocks. + * Calls any statements following this block. + * + * @param block The current block. + * @param code The PHP code created for this block. + * @param thisOnly True to generate code for only this statement. + * @returns PHP code with comments and subsequent blocks added. + */ + scrub_(block: Block, code: string, thisOnly = false): string { + let commentCode = ''; + // Only collect comments for blocks that aren't inline. + if (!block.outputConnection || !block.outputConnection.targetConnection) { + // Collect comment for this block. + let comment = block.getCommentText(); + if (comment) { + comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3); + commentCode += this.prefixLines(comment, '// ') + '\n'; + } + // Collect comments for all value arguments. + // Don't collect comments for nested statements. + for (let i = 0; i < block.inputList.length; i++) { + if (block.inputList[i].type === inputTypes.VALUE) { + const childBlock = block.inputList[i].connection!.targetBlock(); + if (childBlock) { + comment = this.allNestedComments(childBlock); + if (comment) { + commentCode += this.prefixLines(comment, '// '); + } + } + } + } + } + const nextBlock = + block.nextConnection && block.nextConnection.targetBlock(); + const nextCode = thisOnly ? '' : this.blockToCode(nextBlock); + return commentCode + code + nextCode; + } + + /** + * Generate code representing the specified value input, adjusted to take into + * account indexing (zero- or one-based) and optionally by a specified delta + * and/or by negation. + * + * @param block The block. + * @param atId The ID of the input block to get (and adjust) the value of. + * @param delta Value to add. + * @param negate Whether to negate the value. + * @param order The highest order acting on this value. + * @returns The adjusted value or code that evaluates to it. + */ + getAdjusted( + block: Block, + atId: string, + delta = 0, + negate = false, + order = Order.NONE, + ): string { + if (block.workspace.options.oneBasedIndex) { + delta--; + } + let defaultAtIndex = block.workspace.options.oneBasedIndex ? '1' : '0'; + + let orderForInput = order; + if (delta > 0) { + orderForInput = Order.ADDITION; + } else if (delta < 0) { + orderForInput = Order.SUBTRACTION; + } else if (negate) { + orderForInput = Order.UNARY_NEGATION; + } + + let at = this.valueToCode(block, atId, orderForInput) || defaultAtIndex; + + // Easy case: no adjustments. + if (delta === 0 && !negate) { + return at; + } + // If the index is a naked number, adjust it right now. + if (stringUtils.isNumber(at)) { + at = String(Number(at) + delta); + if (negate) { + at = String(-Number(at)); + } + return at; + } + // If the index is dynamic, adjust it in code. + if (delta > 0) { + at = `${at} + ${delta}`; + } else if (delta < 0) { + at = `${at} - ${-delta}`; + } + if (negate) { + at = delta ? `-(${at})` : `-${at}`; + } + if (Math.floor(order) >= Math.floor(orderForInput)) { + at = `(${at})`; + } + return at; + } +} diff --git a/generators/php/procedures.js b/generators/php/procedures.ts similarity index 65% rename from generators/php/procedures.js rename to generators/php/procedures.ts index f261ec919..5d44eb21b 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.ts @@ -5,17 +5,19 @@ */ /** - * @fileoverview Generating PHP for procedure blocks. + * @file Generating PHP for procedure blocks. */ // Former goog.module ID: Blockly.PHP.procedures import * as Variables from '../../core/variables.js'; +import type {Block} from '../../core/block.js'; +import type {IfReturnBlock} from '../../blocks/procedures.js'; import {NameType} from '../../core/names.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function procedures_defreturn(block, generator) { +export function procedures_defreturn(block: Block, generator: PhpGenerator) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. @@ -33,15 +35,14 @@ export function procedures_defreturn(block, generator) { const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { globals.push( - generator.nameDB_.getName( - devVarList[i], NameType.DEVELOPER_VARIABLE)); + generator.nameDB_!.getName(devVarList[i], NameType.DEVELOPER_VARIABLE), + ); } - const globalStr = - globals.length ? - generator.INDENT + 'global ' + globals.join(', ') + ';\n' : ''; + const globalStr = globals.length + ? generator.INDENT + 'global ' + globals.join(', ') + ';\n' + : ''; - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); let xfix1 = ''; if (generator.STATEMENT_PREFIX) { xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block); @@ -55,8 +56,9 @@ export function procedures_defreturn(block, generator) { let loopTrap = ''; if (generator.INFINITE_LOOP_TRAP) { loopTrap = generator.prefixLines( - generator.injectId(generator.INFINITE_LOOP_TRAP, block), - generator.INDENT); + generator.injectId(generator.INFINITE_LOOP_TRAP, block), + generator.INDENT, + ); } const branch = generator.statementToCode(block, 'STACK'); let returnValue = generator.valueToCode(block, 'RETURN', Order.NONE) || ''; @@ -73,22 +75,37 @@ export function procedures_defreturn(block, generator) { for (let i = 0; i < variables.length; i++) { args[i] = generator.getVariableName(variables[i]); } - let code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + - globalStr + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; + let code = + 'function ' + + funcName + + '(' + + args.join(', ') + + ') {\n' + + globalStr + + xfix1 + + loopTrap + + branch + + xfix2 + + returnValue + + '}'; code = generator.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - generator.definitions_['%' + funcName] = code; + // TODO(#7600): find better approach than casting to any to override + // CodeGenerator declaring .definitions protected. + (generator as AnyDuringMigration).definitions_['%' + funcName] = code; return null; -}; +} // Defining a procedure without a return value uses the same generator as // a procedure with a return value. export const procedures_defnoreturn = procedures_defreturn; -export function procedures_callreturn(block, generator) { +export function procedures_callreturn( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Call a procedure with a return value. - const funcName = - generator.getProcedureName(block.getFieldValue('NAME')); + const funcName = generator.getProcedureName(block.getFieldValue('NAME')); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { @@ -96,30 +113,33 @@ export function procedures_callreturn(block, generator) { } const code = funcName + '(' + args.join(', ') + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function procedures_callnoreturn(block, generator) { +export function procedures_callnoreturn(block: Block, generator: PhpGenerator) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = generator.forBlock['procedures_callreturn'](block, generator); + const tuple = generator.forBlock['procedures_callreturn']( + block, + generator, + ) as [string, Order]; return tuple[0] + ';\n'; -}; +} -export function procedures_ifreturn(block, generator) { +export function procedures_ifreturn(block: Block, generator: PhpGenerator) { // Conditionally return value from a procedure. const condition = - generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; + generator.valueToCode(block, 'CONDITION', Order.NONE) || 'false'; let code = 'if (' + condition + ') {\n'; if (generator.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += - generator.prefixLines( - generator.injectId(generator.STATEMENT_SUFFIX, block), - generator.INDENT); + code += generator.prefixLines( + generator.injectId(generator.STATEMENT_SUFFIX, block), + generator.INDENT, + ); } - if (block.hasReturnValue_) { + if ((block as IfReturnBlock).hasReturnValue_) { const value = generator.valueToCode(block, 'VALUE', Order.NONE) || 'null'; code += generator.INDENT + 'return ' + value + ';\n'; } else { @@ -127,4 +147,4 @@ export function procedures_ifreturn(block, generator) { } code += '}\n'; return code; -}; +} diff --git a/generators/php/text.js b/generators/php/text.ts similarity index 63% rename from generators/php/text.js rename to generators/php/text.ts index b5941315b..f2fa69fae 100644 --- a/generators/php/text.js +++ b/generators/php/text.ts @@ -5,87 +5,104 @@ */ /** - * @fileoverview Generating PHP for text blocks. + * @file Generating PHP for text blocks. */ // Former goog.module ID: Blockly.PHP.texts +import type {Block} from '../../core/block.js'; +import type {JoinMutatorBlock} from '../../blocks/text.js'; import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; - -export function text(block, generator) { +export function text(block: Block, generator: PhpGenerator): [string, Order] { // Text value. const code = generator.quote_(block.getFieldValue('TEXT')); return [code, Order.ATOMIC]; -}; +} -export function text_multiline(block, generator) { +export function text_multiline( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Text value. const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('.') !== -1 ? Order.STRING_CONCAT : Order.ATOMIC; + const order = code.indexOf('.') !== -1 ? Order.STRING_CONCAT : Order.ATOMIC; return [code, order]; -}; +} -export function text_join(block, generator) { +export function text_join( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Create a string made up of any number of elements of any type. - if (block.itemCount_ === 0) { + const joinBlock = block as JoinMutatorBlock; + if (joinBlock.itemCount_ === 0) { return ["''", Order.ATOMIC]; - } else if (block.itemCount_ === 1) { + } else if (joinBlock.itemCount_ === 1) { const element = generator.valueToCode(block, 'ADD0', Order.NONE) || "''"; const code = element; return [code, Order.NONE]; - } else if (block.itemCount_ === 2) { + } else if (joinBlock.itemCount_ === 2) { const element0 = - generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; + generator.valueToCode(block, 'ADD0', Order.STRING_CONCAT) || "''"; const element1 = - generator.valueToCode(block, 'ADD1', Order.STRING_CONCAT) || "''"; + generator.valueToCode(block, 'ADD1', Order.STRING_CONCAT) || "''"; const code = element0 + ' . ' + element1; return [code, Order.STRING_CONCAT]; } else { - const elements = new Array(block.itemCount_); - for (let i = 0; i < block.itemCount_; i++) { - elements[i] = - generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; + const elements = new Array(joinBlock.itemCount_); + for (let i = 0; i < joinBlock.itemCount_; i++) { + elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || "''"; } - const code = 'implode(\'\', array(' + elements.join(',') + '))'; + const code = "implode('', array(" + elements.join(',') + '))'; return [code, Order.FUNCTION_CALL]; } -}; +} -export function text_append(block, generator) { +export function text_append(block: Block, generator: PhpGenerator) { // Append to a variable in place. - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - const value = - generator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + const value = generator.valueToCode(block, 'TEXT', Order.ASSIGNMENT) || "''"; return varName + ' .= ' + value + ';\n'; -}; +} -export function text_length(block, generator) { +export function text_length( + block: Block, + generator: PhpGenerator, +): [string, Order] { // String or array length. - const functionName = generator.provideFunction_('length', ` + const functionName = generator.provideFunction_( + 'length', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($value) { if (is_string($value)) { return strlen($value); } return count($value); } -`); +`, + ); const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return [functionName + '(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_isEmpty(block, generator) { +export function text_isEmpty( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Is the string null or array empty? const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; return ['empty(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_indexOf(block, generator) { +export function text_indexOf( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Search the text for a substring. const operator = - block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; + block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos'; const substring = generator.valueToCode(block, 'FIND', Order.NONE) || "''"; const text = generator.valueToCode(block, 'VALUE', Order.NONE) || "''"; let errorIndex = ' -1'; @@ -95,22 +112,27 @@ export function text_indexOf(block, generator) { indexAdjustment = ' + 1'; } const functionName = generator.provideFunction_( - block.getFieldValue('END') === 'FIRST' ? 'text_indexOf' : - 'text_lastIndexOf', - ` + block.getFieldValue('END') === 'FIRST' + ? 'text_indexOf' + : 'text_lastIndexOf', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $search) { $pos = ${operator}($text, $search); return $pos === false ? ${errorIndex} : $pos${indexAdjustment}; } -`); +`, + ); const code = functionName + '(' + text + ', ' + substring + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_charAt(block, generator) { +export function text_charAt( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get letter at index. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = (where === 'RANDOM') ? Order.NONE : Order.NONE; + const textOrder = where === 'RANDOM' ? Order.NONE : Order.NONE; const text = generator.valueToCode(block, 'VALUE', textOrder) || "''"; switch (where) { case 'FIRST': { @@ -132,19 +154,25 @@ export function text_charAt(block, generator) { return [code, Order.FUNCTION_CALL]; } case 'RANDOM': { - const functionName = generator.provideFunction_('text_random_letter', ` + const functionName = generator.provideFunction_( + 'text_random_letter', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text) { return $text[rand(0, strlen($text) - 1)]; } -`); +`, + ); const code = functionName + '(' + text + ')'; return [code, Order.FUNCTION_CALL]; } } throw Error('Unhandled option (text_charAt).'); -}; +} -export function text_getSubstring(block, generator) { +export function text_getSubstring( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); @@ -155,7 +183,9 @@ export function text_getSubstring(block, generator) { } else { const at1 = generator.getAdjusted(block, 'AT1'); const at2 = generator.getAdjusted(block, 'AT2'); - const functionName = generator.provideFunction_('text_get_substring', ` + const functionName = generator.provideFunction_( + 'text_get_substring', + ` function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, $at2) { if ($where1 == 'FROM_END') { $at1 = strlen($text) - 1 - $at1; @@ -176,14 +206,29 @@ function ${generator.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, } return substr($text, $at1, $length); } -`); - const code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 + - ', \'' + where2 + '\', ' + at2 + ')'; +`, + ); + const code = + functionName + + '(' + + text + + ", '" + + where1 + + "', " + + at1 + + ", '" + + where2 + + "', " + + at2 + + ')'; return [code, Order.FUNCTION_CALL]; } -}; +} -export function text_changeCase(block, generator) { +export function text_changeCase( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Change capitalization. const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; let code; @@ -194,24 +239,31 @@ export function text_changeCase(block, generator) { } else if (block.getFieldValue('CASE') === 'TITLECASE') { code = 'ucwords(strtolower(' + text + '))'; } - return [code, Order.FUNCTION_CALL]; -}; + return [code as string, Order.FUNCTION_CALL]; +} -export function text_trim(block, generator) { +export function text_trim( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Trim spaces. const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'}; - const operator = OPERATORS[block.getFieldValue('MODE')]; + type OperatorOption = keyof typeof OPERATORS; + const operator = OPERATORS[block.getFieldValue('MODE') as OperatorOption]; const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return [operator + '(' + text + ')', Order.FUNCTION_CALL]; -}; +} -export function text_print(block, generator) { +export function text_print(block: Block, generator: PhpGenerator) { // Print statement. const msg = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; return 'print(' + msg + ');\n'; -}; +} -export function text_prompt_ext(block, generator) { +export function text_prompt_ext( + block: Block, + generator: PhpGenerator, +): [string, Order] { // Prompt function. let msg; if (block.getField('TEXT')) { @@ -227,29 +279,47 @@ export function text_prompt_ext(block, generator) { code = 'floatval(' + code + ')'; } return [code, Order.FUNCTION_CALL]; -}; +} export const text_prompt = text_prompt_ext; -export function text_count(block, generator) { +export function text_count( + block: Block, + generator: PhpGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const sub = generator.valueToCode(block, 'SUB', Order.NONE) || "''"; - const code = 'strlen(' + sub + ') === 0' + - ' ? strlen(' + text + ') + 1' + - ' : substr_count(' + text + ', ' + sub + ')'; + const code = + 'strlen(' + + sub + + ') === 0' + + ' ? strlen(' + + text + + ') + 1' + + ' : substr_count(' + + text + + ', ' + + sub + + ')'; return [code, Order.CONDITIONAL]; -}; +} -export function text_replace(block, generator) { +export function text_replace( + block: Block, + generator: PhpGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const from = generator.valueToCode(block, 'FROM', Order.NONE) || "''"; const to = generator.valueToCode(block, 'TO', Order.NONE) || "''"; const code = 'str_replace(' + from + ', ' + to + ', ' + text + ')'; return [code, Order.FUNCTION_CALL]; -}; +} -export function text_reverse(block, generator) { +export function text_reverse( + block: Block, + generator: PhpGenerator, +): [string, Order] { const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''"; const code = 'strrev(' + text + ')'; return [code, Order.FUNCTION_CALL]; -}; +} diff --git a/generators/php/variables.js b/generators/php/variables.js deleted file mode 100644 index 50429fa9b..000000000 --- a/generators/php/variables.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright 2015 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Generating PHP for variable blocks. - */ - -// Former goog.module ID: Blockly.PHP.variables - -import {Order} from './php_generator.js'; - - -export function variables_get(block, generator) { - // Variable getter. - const code = - generator.getVariableName(block.getFieldValue('VAR')); - return [code, Order.ATOMIC]; -}; - -export function variables_set(block, generator) { - // Variable setter. - const argument0 = - generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; - const varName = - generator.getVariableName(block.getFieldValue('VAR')); - return varName + ' = ' + argument0 + ';\n'; -}; diff --git a/generators/php/variables.ts b/generators/php/variables.ts new file mode 100644 index 000000000..4aacc293b --- /dev/null +++ b/generators/php/variables.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2015 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file Generating PHP for variable blocks. + */ + +// Former goog.module ID: Blockly.PHP.variables + +import type {Block} from '../../core/block.js'; +import {Order} from './php_generator.js'; +import type {PhpGenerator} from './php_generator.js'; + +export function variables_get( + block: Block, + generator: PhpGenerator, +): [string, Order] { + // Variable getter. + const code = generator.getVariableName(block.getFieldValue('VAR')); + return [code, Order.ATOMIC]; +} + +export function variables_set(block: Block, generator: PhpGenerator) { + // Variable setter. + const argument0 = + generator.valueToCode(block, 'VALUE', Order.ASSIGNMENT) || '0'; + const varName = generator.getVariableName(block.getFieldValue('VAR')); + return varName + ' = ' + argument0 + ';\n'; +} diff --git a/generators/php/variables_dynamic.js b/generators/php/variables_dynamic.ts similarity index 83% rename from generators/php/variables_dynamic.js rename to generators/php/variables_dynamic.ts index 1f4a3c100..5ab5ec6ca 100644 --- a/generators/php/variables_dynamic.js +++ b/generators/php/variables_dynamic.ts @@ -5,12 +5,11 @@ */ /** - * @fileoverview Generating PHP for dynamic variable blocks. + * @file Generating PHP for dynamic variable blocks. */ // Former goog.module ID: Blockly.PHP.variablesDynamic - // generator is dynamically typed. export { variables_get as variables_get_dynamic, diff --git a/generators/python/python_generator.ts b/generators/python/python_generator.ts index 33c07fe39..229c2022c 100644 --- a/generators/python/python_generator.ts +++ b/generators/python/python_generator.ts @@ -52,10 +52,8 @@ export enum Order { * PythonScript code generator class. */ export class PythonGenerator extends CodeGenerator { - /** - * List of outer-inner pairings that do NOT require parentheses. - */ - ORDER_OVERRIDES: number[][] = [ + /** List of outer-inner pairings that do NOT require parentheses. */ + ORDER_OVERRIDES: [Order, Order][] = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] [Order.FUNCTION_CALL, Order.MEMBER], From 3d3cd3fbb0c86b7c855baa592663d2989f921c2e Mon Sep 17 00:00:00 2001 From: Zoey Li <31378877+alicialics@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:18:44 -0800 Subject: [PATCH 72/86] chore: Renable macos-latest build (#7640) * chore: Renable macos-latest build * chore: Update browser_test.yml --- .github/workflows/browser_test.yml | 4 +--- .github/workflows/build.yml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/browser_test.yml b/.github/workflows/browser_test.yml index 3675af7b0..7e09fd52b 100644 --- a/.github/workflows/browser_test.yml +++ b/.github/workflows/browser_test.yml @@ -16,9 +16,7 @@ jobs: strategy: matrix: - # TODO (#2114): re-enable osx build. - # os: [ubuntu-latest, macos-latest] - os: [macos-latest] + os: [ubuntu-latest, macos-latest] node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad62722e1..05b5139ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,9 +15,7 @@ jobs: strategy: matrix: - # TODO (#2114): re-enable osx build. - # os: [ubuntu-latest, macos-latest] - os: [ubuntu-latest] + os: [ubuntu-latest, macos-latest] node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ From f363252d355020539b49b3df85c59b639c4c486a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 1 Dec 2023 19:39:41 +0000 Subject: [PATCH 73/86] chore: modify readme about how we want people to acquire Blockly (#7661) * chore: modify readme about how we want people to acquire Blockly * chore: PR comments --- scripts/package/README.md | 88 +++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/scripts/package/README.md b/scripts/package/README.md index 378eb3373..9e8ab6e35 100644 --- a/scripts/package/README.md +++ b/scripts/package/README.md @@ -5,26 +5,10 @@ blocks together to build programs. All code is free and open source. The source for this module is in the [Blockly repo](http://github.com/google/blockly). -## Installation - -You can install this package either via `npm` or `unpkg`. - -### npm - -```bash -npm install blockly -``` - -### unpkg - -```html - -``` - ## Example Usage ```js -import Blockly from 'blockly'; +import * as Blockly from 'blockly/core'; Blockly.inject('blocklyDiv', { ... }) @@ -34,46 +18,76 @@ Blockly.inject('blocklyDiv', { For samples on how to integrate Blockly into your project, view the list of samples at [blockly-samples](https://github.com/google/blockly-samples). -### Importing Blockly +## Installation -When you import Blockly with `import * as Blockly from 'blockly';` you'll get the default modules: -Blockly core, Blockly built-in blocks, the JavaScript generator and the English lang files. +You can install this package either via `npm` or `unpkg`. -If you need more flexibility, you'll want to define your imports more carefully: +### unpkg -#### Blockly Core +```html + +``` + +When importing from unpkg, you can access imports from the global namespace. ```js +// Access Blockly. +Blockly.thing; +// Access the default blocks. +Blockly.Blocks['block_type']; +// Access the javascript generator. +javascript.javascriptGenerator; +``` + +### npm + +```bash +npm install blockly +``` + +## Imports + +Note: Using import of our package targets requires you to use a bundler (like webpack), since Blockly is packaged as a UMD, rather than an ESM. + +```js +// Import Blockly core. import * as Blockly from 'blockly/core'; -``` - -#### Blockly built in blocks - -```js +// Import the default blocks. import * as libraryBlocks from 'blockly/blocks'; +// Import a generator. +import {javascriptGenerator} from 'blockly/javascript'; +// Import a message file. +import * as En from 'blockly/msg/en'; ``` -#### Blockly Generators - -If your application needs to generate code from the Blockly blocks, you'll want to include a generator. +## Requires ```js -import {pythonGenerator} from 'blockly/python'; +// Require Blockly core. +const Blockly = require('blockly/core'); +// Require the default blocks. +const libraryBlocks = require('blockly/blocks'); +// Require a generator. +const {javascriptGenerator} = require('blockly/javascript'); +// Require a message file. +const En = require('blockly/msg/en'); ``` -to include the Python generator. You can also import `{javascriptGenerator} from 'blockly/javascript'`, `{phpGenerator} from 'blockly/php'`, `{dartGenerator} from 'blockly/dart'` and `{luaGenerator} from 'blockly/lua'`. +## Applying messages -#### Blockly Languages +Once you have the message files, you also need to apply them. ```js -import * as Fr from 'blockly/msg/fr'; -Blockly.setLocale(Fr); +Blockly.setLocal(En); ``` -To import the French lang files. Once you've imported the specific lang module, you'll also want to set the locale in Blockly. - For a full list of supported Blockly locales, see: [https://github.com/google/blockly/tree/master/msg/js](https://github.com/google/blockly/tree/master/msg/js) +## Docs + +For more information about how to use Blockly, check out our +[devsite](https://developers.google.com/blockly/guides/overview). + ## License Apache 2.0 From 71ded9dd89fe09a16ec7fced91626ffb9c97e023 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 4 Dec 2023 19:14:19 +0000 Subject: [PATCH 74/86] fix: trashcan flyout opening on drag (#7691) --- core/trashcan.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/trashcan.ts b/core/trashcan.ts index ee7c98eeb..42c32ea1f 100644 --- a/core/trashcan.ts +++ b/core/trashcan.ts @@ -545,7 +545,7 @@ export class Trashcan /** Inspect the contents of the trash. */ click() { - if (!this.hasContents()) { + if (!this.hasContents() || this.workspace.isDragging()) { return; } this.openFlyout(); From 1733e26e3608c050e1e2ecb05ce3378288ec514b Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Mon, 4 Dec 2023 11:21:21 -0800 Subject: [PATCH 75/86] Revert "chore: Renable macos-latest build (#7640)" (#7692) This reverts commit 3d3cd3fbb0c86b7c855baa592663d2989f921c2e. --- .github/workflows/browser_test.yml | 4 +++- .github/workflows/build.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/browser_test.yml b/.github/workflows/browser_test.yml index 7e09fd52b..3675af7b0 100644 --- a/.github/workflows/browser_test.yml +++ b/.github/workflows/browser_test.yml @@ -16,7 +16,9 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest] + # TODO (#2114): re-enable osx build. + # os: [ubuntu-latest, macos-latest] + os: [macos-latest] node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05b5139ef..ad62722e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,9 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest] + # TODO (#2114): re-enable osx build. + # os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest] node-version: [18.x, 20.x] # See supported Node.js release schedule at # https://nodejs.org/en/about/releases/ From 38d121f9b108e2737669fe23d9422ec5e93faca7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:00:00 -0800 Subject: [PATCH 76/86] chore(deps): Bump @hyperjump/json-schema from 1.6.5 to 1.6.6 (#7687) Bumps [@hyperjump/json-schema](https://github.com/hyperjump-io/json-schema) from 1.6.5 to 1.6.6. - [Commits](https://github.com/hyperjump-io/json-schema/compare/v1.6.5...v1.6.6) --- updated-dependencies: - dependency-name: "@hyperjump/json-schema" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0585e583..b0be9e36f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -394,9 +394,9 @@ } }, "node_modules/@hyperjump/json-schema": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.6.5.tgz", - "integrity": "sha512-m9Ozq32JH9yy55JH4d/coXd2KGXKIWunzJZWr6J+rTRHvpchy7bZ7SBBLxLvslGJ5yoVSRQ4bEPh1mgJCzNhqg==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-1.6.6.tgz", + "integrity": "sha512-LuZ+erTRmAzppvBT3cx7orfK5AF7wVxdHd850KM06i3RZbcDX+EWD65+YIojQ7uNbHeiqCdcQmIxhNNUN9riNQ==", "dev": true, "dependencies": { "@hyperjump/json-pointer": "^1.0.0", From 0a27e1c47299b5d38b66cd13c88a85774c2665a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:00:40 -0800 Subject: [PATCH 77/86] chore(deps): Bump webdriverio from 8.24.2 to 8.24.6 (#7683) Bumps [webdriverio](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/webdriverio) from 8.24.2 to 8.24.6. - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.24.6/packages/webdriverio) --- updated-dependencies: - dependency-name: webdriverio dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0be9e36f..88925cff8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1374,14 +1374,14 @@ "dev": true }, "node_modules/@wdio/config": { - "version": "8.24.2", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.24.2.tgz", - "integrity": "sha512-qMTU40PBtEZEdj+vTkK2mRxaT07gcEGundlj+u08brYNT2LHPtEw5Vp0jReCz29Wlq4zsrv9qHpgluiSnRTHQw==", + "version": "8.24.6", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.24.6.tgz", + "integrity": "sha512-ZFmd6rB1kgL4k/SjLXbtFTCxvxSf1qzdt/losiTqkqFBYznkTRUBGSoGaVTlkMtHAReiVSK92sICc15JWaCdEA==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", "@wdio/types": "8.24.2", - "@wdio/utils": "8.24.2", + "@wdio/utils": "8.24.6", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1488,9 +1488,9 @@ } }, "node_modules/@wdio/utils": { - "version": "8.24.2", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.24.2.tgz", - "integrity": "sha512-YsQunFrAqZO7Retkzfhqa7N/zY21FdnI4iFYCAeIeL3spRIGRFsXjrbE8vEXu9/Tr+h5Xxgn5Lj3Dc/7HD8EPg==", + "version": "8.24.6", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.24.6.tgz", + "integrity": "sha512-qwcshLH9iKnhK0jXoXjPw3G02UhyShT0I+ljC0hMybJEBsra92TYFa47Cp6n1fdvM3+/BTuhsgtzRz0anObicQ==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", @@ -11400,18 +11400,18 @@ } }, "node_modules/webdriver": { - "version": "8.24.2", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.24.2.tgz", - "integrity": "sha512-UZzXIRXd+Ja7F2gfgwgaFiRxnHhX7q+WS7DRP2x/HJPZGWuoRwuqhPdTJ3SgsCKgDgwRUWwmh7yKCcfiGR1/lg==", + "version": "8.24.6", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.24.6.tgz", + "integrity": "sha512-k5XI2/SHd/14h4ElPQH8EzSUXujZIGbBEi+3dTS2H457KFR5Q8QYfIazDs/YnEdooOp8b6Oe9N7qI99LP8K6bQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.24.2", + "@wdio/config": "8.24.6", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.23.0", "@wdio/types": "8.24.2", - "@wdio/utils": "8.24.2", + "@wdio/utils": "8.24.6", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -11459,18 +11459,18 @@ } }, "node_modules/webdriverio": { - "version": "8.24.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.24.2.tgz", - "integrity": "sha512-zHQNI27Ltd3HpNHYil0U7VKqa+ESN264RSsOLfY9vlnmFAwPXLM7MFaFSx/u6OPG/mcQ2j8W49px2n+yeDHvuw==", + "version": "8.24.6", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.24.6.tgz", + "integrity": "sha512-gJMAJiErbXe/oFJbV+H9lXp9GPxnUgHrbtxkG6SCKQlk1zPFho9FZ3fQWl/ty84w5n9ZMhAdnQIfZM9aytxIBQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.24.2", + "@wdio/config": "8.24.6", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.23.0", "@wdio/repl": "8.23.1", "@wdio/types": "8.24.2", - "@wdio/utils": "8.24.2", + "@wdio/utils": "8.24.6", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -11487,7 +11487,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.24.2" + "webdriver": "8.24.6" }, "engines": { "node": "^16.13 || >=18" From 96a354b46b44c77dfffb1314e45a6ffa742bb53c Mon Sep 17 00:00:00 2001 From: truongductri01 <58579187+truongductri01@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:10:09 -0500 Subject: [PATCH 78/86] feat: added intermediate event change (#7671) * feat: added intermediate event change * fix: update prettier format for the code * fix: update comment style * fix: update test statements --- .../events_block_field_intermediate_change.ts | 30 ++++++++++++++++ ...nt_block_field_intermediate_change_test.js | 34 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/core/events/events_block_field_intermediate_change.ts b/core/events/events_block_field_intermediate_change.ts index 1e19a04a6..264f910a8 100644 --- a/core/events/events_block_field_intermediate_change.ts +++ b/core/events/events_block_field_intermediate_change.ts @@ -122,6 +122,36 @@ export class BlockFieldIntermediateChange extends BlockBase { override isNull(): boolean { return this.oldValue === this.newValue; } + + /** + * Run a change event. + * + * @param forward True if run forward, false if run backward (undo). + */ + override run(forward: boolean) { + const workspace = this.getEventWorkspace_(); + if (!this.blockId) { + throw new Error( + 'The block ID is undefined. Either pass a block to ' + + 'the constructor, or call fromJson', + ); + } + const block = workspace.getBlockById(this.blockId); + if (!block) { + throw new Error( + 'The associated block is undefined. Either pass a ' + + 'block to the constructor, or call fromJson', + ); + } + + const value = forward ? this.newValue : this.oldValue; + const field = block.getField(this.name!); + if (field) { + field.setValue(value); + } else { + console.warn("Can't set non-existent field: " + this.name); + } + } } export interface BlockFieldIntermediateChangeJson extends BlockBaseJson { diff --git a/tests/mocha/event_block_field_intermediate_change_test.js b/tests/mocha/event_block_field_intermediate_change_test.js index e8a71effb..4d441e5d6 100644 --- a/tests/mocha/event_block_field_intermediate_change_test.js +++ b/tests/mocha/event_block_field_intermediate_change_test.js @@ -35,4 +35,38 @@ suite('Field Intermediate Change Event', function () { chai.assert.deepEqual(newEvent, origEvent); }); }); + + suite('Change Value', function () { + test("running forward changes the block's value to new value", function () { + const block = this.workspace.newBlock('text', 'block_id'); + const origEvent = new Blockly.Events.BlockFieldIntermediateChange( + block, + 'TEXT', + 'old value', + 'new value', + ); + origEvent.run(true); + + chai.assert.deepEqual( + block.getField(origEvent.name).getValue(), + 'new value', + ); + }); + + test("running backward changes the block's value to old value", function () { + const block = this.workspace.newBlock('text', 'block_id'); + const origEvent = new Blockly.Events.BlockFieldIntermediateChange( + block, + 'TEXT', + 'old value', + 'new value', + ); + origEvent.run(false); + + chai.assert.deepEqual( + block.getField(origEvent.name).getValue(), + 'old value', + ); + }); + }); }); From 2b00cd85aad3e4e93be420c6929f9f35db7ef381 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:20:26 -0800 Subject: [PATCH 79/86] chore(deps): Bump eslint from 8.54.0 to 8.55.0 (#7686) Bumps [eslint](https://github.com/eslint/eslint) from 8.54.0 to 8.55.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.54.0...v8.55.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88925cff8..34ad18c58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -210,9 +210,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -233,9 +233,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3885,15 +3885,15 @@ } }, "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", From 0836a1db10e1587bd60e849e446eb2a8bced0e21 Mon Sep 17 00:00:00 2001 From: Ananta Bastola <12180395+ananta@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:42:35 -0500 Subject: [PATCH 80/86] fix: release dummy wheel listener on workspace dispose (#7693) fix #7674 --- core/workspace_svg.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 1cfdbbc37..fe1386587 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -247,6 +247,12 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { | ((menuOptions: ContextMenuOption[], e: Event) => void) | null = null; + /** + * A dummy wheel event listener used as a workaround for a Safari scrolling issue. + * Set in createDom and used for removal in dispose to ensure proper cleanup. + */ + private dummyWheelListener: (() => void) | null = null; + /** * In a flyout, the target workspace where blocks should be placed after a * drag. Otherwise null. @@ -787,7 +793,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { // This no-op works around https://bugs.webkit.org/show_bug.cgi?id=226683, // which otherwise prevents zoom/scroll events from being observed in // Safari. Once that bug is fixed it should be removed. - document.body.addEventListener('wheel', function () {}); + this.dummyWheelListener = () => {}; + document.body.addEventListener('wheel', this.dummyWheelListener); browserEvents.conditionalBind( this.svgGroup_, 'wheel', @@ -896,6 +903,12 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { browserEvents.unbind(this.resizeHandlerWrapper); this.resizeHandlerWrapper = null; } + + // Remove the dummy wheel listener + if (this.dummyWheelListener) { + document.body.removeEventListener('wheel', this.dummyWheelListener); + this.dummyWheelListener = null; + } } /** From 45cc1e8feaebdc90792e56faf6f0d8364df024e6 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 5 Dec 2023 18:51:21 +0000 Subject: [PATCH 81/86] fix: mutator coordinates not respecting flyout (#7690) * fix: mutator coordinates not respecting flyout * chore: fixup conditionals --- core/flyout_horizontal.ts | 15 +++++++++++++++ core/flyout_vertical.ts | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index 02ac7377a..9c9490b22 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -382,6 +382,21 @@ export class HorizontalFlyout extends Flyout { } } + // TODO(#7689): Remove this. + // Workspace with no scrollbars where this is permanently open on the top. + // If scrollbars exist they properly update the metrics. + if ( + !this.targetWorkspace.scrollbar && + !this.autoClose && + this.targetWorkspace.getFlyout() === this && + this.toolboxPosition_ === toolbox.Position.TOP + ) { + this.targetWorkspace.translate( + this.targetWorkspace.scrollX, + this.targetWorkspace.scrollY + flyoutHeight, + ); + } + this.height_ = flyoutHeight; this.position(); this.targetWorkspace.resizeContents(); diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index 72c53efbf..c9ce4f659 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -375,6 +375,22 @@ export class VerticalFlyout extends Flyout { } } + // TODO(#7689): Remove this. + // Workspace with no scrollbars where this is permanently + // open on the left. + // If scrollbars exist they properly update the metrics. + if ( + !this.targetWorkspace.scrollbar && + !this.autoClose && + this.targetWorkspace.getFlyout() === this && + this.toolboxPosition_ === toolbox.Position.LEFT + ) { + this.targetWorkspace.translate( + this.targetWorkspace.scrollX + flyoutWidth, + this.targetWorkspace.scrollY, + ); + } + this.width_ = flyoutWidth; this.position(); this.targetWorkspace.resizeContents(); From a2a041f212fb73b55da60cf636797c85c18674d5 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 5 Dec 2023 22:24:38 +0000 Subject: [PATCH 82/86] fix: reenable showing empty flyouts (#7695) --- core/flyout_base.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 219d69e3e..76d2e8f8c 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -647,7 +647,6 @@ export abstract class Flyout // Parse the Array, Node or NodeList into a a list of flyout items. const parsedContent = toolbox.convertFlyoutDefToJsonArray(flyoutDef); - if (!parsedContent.length) return; // No need to show an empty flyout. const flyoutInfo = this.createFlyoutInfo(parsedContent); renderManagement.triggerQueuedRenders(); From f0c3f33a960f31f51f36568e773b3fbadc350921 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 5 Dec 2023 22:29:00 +0000 Subject: [PATCH 83/86] Revert "chore(deps): Bump jsdom from 22.1.0 to 23.0.0 (#7667)" (#7694) This reverts commit ac362fd57a2edefa739aa3ff49d3c566c1f94483. --- package-lock.json | 592 ++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 263 insertions(+), 331 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34ad18c58..a4b8c198e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "jsdom": "23.0.0" + "jsdom": "22.1.0" }, "devDependencies": { "@blockly/block-test": "^5.0.0", @@ -897,8 +897,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "peer": true, "engines": { "node": ">= 10" } @@ -1533,6 +1531,18 @@ "node": ">=16.3.0" } }, + "node_modules/@wdio/utils/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/utils/node_modules/decamelize": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", @@ -1545,6 +1555,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/utils/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/utils/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/utils/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -1582,10 +1618,7 @@ "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true, - "peer": true + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, "node_modules/acorn": { "version": "8.11.2", @@ -1609,14 +1642,14 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dependencies": { - "debug": "^4.3.4" + "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6.0.0" } }, "node_modules/ajv": { @@ -2255,166 +2288,6 @@ "jsdom": "22.1.0" } }, - "node_modules/blockly/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/blockly/node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "peer": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/blockly/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/blockly/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/blockly/node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dev": true, - "peer": true, - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/blockly/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "peer": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/blockly/node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "peer": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/blockly/node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/blockly/node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dev": true, - "peer": true, - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/blockly/node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", @@ -3229,17 +3102,6 @@ "node": ">=0.10.0" } }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -3265,41 +3127,6 @@ "node": ">= 14" } }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -3567,9 +3394,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "peer": true, "dependencies": { "webidl-conversions": "^7.0.0" }, @@ -4932,6 +4756,18 @@ "node": "^16.13 || >=18 || >=20" } }, + "node_modules/geckodriver/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/geckodriver/node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -4953,6 +4789,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/geckodriver/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/geckodriver/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/geckodriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -6398,7 +6260,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -6427,15 +6288,16 @@ } }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, "node_modules/http-server": { @@ -6479,26 +6341,15 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, "node_modules/ieee754": { @@ -7035,37 +6886,39 @@ } }, "node_modules/jsdom": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", - "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", "dependencies": { + "abab": "^2.0.6", "cssstyle": "^3.0.0", - "data-urls": "^5.0.0", + "data-urls": "^4.0.0", "decimal.js": "^10.4.3", + "domexception": "^4.0.0", "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.7", + "nwsapi": "^2.2.4", "parse5": "^7.1.2", "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", - "w3c-xmlserializer": "^5.0.0", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.14.2", - "xml-name-validator": "^5.0.0" + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=16" }, "peerDependencies": { - "canvas": "^3.0.0" + "canvas": "^2.5.0" }, "peerDependenciesMeta": { "canvas": { @@ -7073,69 +6926,51 @@ } } }, - "node_modules/jsdom/node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "node_modules/jsdom/node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", "dependencies": { - "whatwg-encoding": "^3.1.1" + "rrweb-cssom": "^0.6.0" }, "engines": { - "node": ">=18" + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" } }, "node_modules/jsdom/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", "dependencies": { - "punycode": "^2.3.1" + "punycode": "^2.3.0" }, "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" + "node": ">=14" } }, "node_modules/jsdom/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", "dependencies": { - "tr46": "^5.0.0", + "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": ">=14" } }, "node_modules/json-buffer": { @@ -8267,9 +8102,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -8611,6 +8446,44 @@ "node": ">= 14" } }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pac-resolver": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", @@ -9113,6 +8986,44 @@ "node": ">= 14" } }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/proxy-agent/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -9165,9 +9076,9 @@ } }, "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "engines": { "node": ">=6" } @@ -10153,6 +10064,18 @@ "node": ">= 14" } }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -11363,14 +11286,14 @@ } }, "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dependencies": { - "xml-name-validator": "^5.0.0" + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=14" } }, "node_modules/wait-port": { @@ -11549,7 +11472,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -11557,12 +11479,23 @@ "node": ">=12" } }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "engines": { + "node": ">=12" } }, "node_modules/whatwg-url": { @@ -11653,7 +11586,6 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -11671,11 +11603,11 @@ } }, "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/xmlchars": { diff --git a/package.json b/package.json index 3f237a7da..8f972c170 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,6 @@ "yargs": "^17.2.1" }, "dependencies": { - "jsdom": "23.0.0" + "jsdom": "22.1.0" } } From 76a1ab2413e537933470fad0934dfcb340a56ec1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:53:31 -0800 Subject: [PATCH 84/86] chore(deps): Bump @microsoft/api-extractor from 7.38.0 to 7.38.3 (#7685) Bumps [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) from 7.38.0 to 7.38.3. - [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md) - [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.38.3/apps/api-extractor) --- updated-dependencies: - dependency-name: "@microsoft/api-extractor" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4b8c198e..7340e04fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -553,18 +553,6 @@ "api-documenter": "bin/api-documenter" } }, - "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", - "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", - "dev": true, - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, "node_modules/@microsoft/api-documenter/node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -588,9 +576,9 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.38.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.38.0.tgz", - "integrity": "sha512-e1LhZYnfw+JEebuY2bzhw0imDCl1nwjSThTrQqBXl40hrVo6xm3j/1EpUr89QyzgjqmAwek2ZkIVZbrhaR+cqg==", + "version": "7.38.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.38.3.tgz", + "integrity": "sha512-xt9iYyC5f39281j77JTA9C3ISJpW1XWkCcnw+2vM78CPnro6KhPfwQdPDfwS5JCPNuq0grm8cMdPUOPvrchDWw==", "dev": true, "dependencies": { "@microsoft/api-extractor-model": "7.28.2", @@ -598,7 +586,7 @@ "@microsoft/tsdoc-config": "~0.16.1", "@rushstack/node-core-library": "3.61.0", "@rushstack/rig-package": "0.5.1", - "@rushstack/ts-command-line": "4.16.1", + "@rushstack/ts-command-line": "4.17.1", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.22.1", @@ -814,9 +802,9 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.1.tgz", - "integrity": "sha512-+OCsD553GYVLEmz12yiFjMOzuPeCiZ3f8wTiFHL30ZVXexTyPmgjwXEhg2K2P0a2lVf+8YBy7WtPoflB2Fp8/A==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", + "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", "dev": true, "dependencies": { "@types/argparse": "1.0.38", From a3053955d3e0889df159e139d82b6eea2b9c9c3a Mon Sep 17 00:00:00 2001 From: Maribeth Bottorff Date: Wed, 6 Dec 2023 11:02:45 -0800 Subject: [PATCH 85/86] feat: make fields and icons optionally clickable in flyouts (#7672) * feat: add ability to click fields in flyouts * feat: control if icons are clickable in flyouts * fix: make default icons not clickable in flyout * fix: use booleans like a real programmer --- core/field.ts | 14 ++++++++++++++ core/gesture.ts | 20 ++++++++++++-------- core/icons/comment_icon.ts | 4 ++++ core/icons/icon.ts | 13 +++++++++++++ core/icons/mutator_icon.ts | 4 ++++ core/icons/warning_icon.ts | 4 ++++ core/interfaces/i_icon.ts | 9 +++++++++ 7 files changed, 60 insertions(+), 8 deletions(-) diff --git a/core/field.ts b/core/field.ts index a3afb7062..7522cde93 100644 --- a/core/field.ts +++ b/core/field.ts @@ -581,6 +581,20 @@ export abstract class Field ); } + /** + * Check whether the field should be clickable while the block is in a flyout. + * The default is that fields are clickable in always-open flyouts such as the + * simple toolbox, but not in autoclosing flyouts such as the category toolbox. + * Subclasses may override this function to change this behavior. Note that + * `isClickable` must also return true for this to have any effect. + * + * @param autoClosingFlyout true if the containing flyout is an auto-closing one. + * @returns Whether the field should be clickable while the block is in a flyout. + */ + isClickableInFlyout(autoClosingFlyout: boolean): boolean { + return !autoClosingFlyout; + } + /** * Check whether this field is currently editable. Some fields are never * EDITABLE (e.g. text labels). Other fields may be EDITABLE but may exist on diff --git a/core/gesture.ts b/core/gesture.ts index 4549efcba..4b85c4f6f 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -1157,25 +1157,29 @@ export class Gesture { } /** - * Whether this gesture is a click on a field. This should only be called + * Whether this gesture is a click on a field that should be handled. This should only be called * when ending a gesture (pointerup). * * @returns Whether this gesture was a click on a field. */ private isFieldClick(): boolean { - const fieldClickable = this.startField - ? this.startField.isClickable() - : false; + if (!this.startField) return false; return ( - fieldClickable && + this.startField.isClickable() && !this.hasExceededDragRadius && - (!this.flyout || !this.flyout.autoClose) + (!this.flyout || + this.startField.isClickableInFlyout(this.flyout.autoClose)) ); } - /** @returns Whether this gesture is a click on an icon. */ + /** @returns Whether this gesture is a click on an icon that should be handled. */ private isIconClick(): boolean { - return !!this.startIcon && !this.hasExceededDragRadius; + if (!this.startIcon) return false; + const handleInFlyout = + !this.flyout || + !this.startIcon.isClickableInFlyout || + this.startIcon.isClickableInFlyout(this.flyout.autoClose); + return !this.hasExceededDragRadius && handleInFlyout; } /** diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index 364ef67d1..7756088b6 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -223,6 +223,10 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { this.setBubbleVisible(!this.bubbleIsVisible()); } + override isClickableInFlyout(): boolean { + return false; + } + /** * Updates the text of this comment in response to changes in the text of * the input bubble. diff --git a/core/icons/icon.ts b/core/icons/icon.ts index c5979445c..b1104b157 100644 --- a/core/icons/icon.ts +++ b/core/icons/icon.ts @@ -133,6 +133,19 @@ export abstract class Icon implements IIcon { onClick(): void {} + /** + * Check whether the icon should be clickable while the block is in a flyout. + * The default is that icons are clickable in all flyouts (auto-closing or not). + * Subclasses may override this function to change this behavior. + * + * @param autoClosingFlyout true if the containing flyout is an auto-closing one. + * @returns Whether the icon should be clickable while the block is in a flyout. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isClickableInFlyout(autoClosingFlyout: boolean): boolean { + return true; + } + /** * Sets the visibility of the icon's bubble if one exists. * diff --git a/core/icons/mutator_icon.ts b/core/icons/mutator_icon.ts index c53d58f8a..56365ed1f 100644 --- a/core/icons/mutator_icon.ts +++ b/core/icons/mutator_icon.ts @@ -157,6 +157,10 @@ export class MutatorIcon extends Icon implements IHasBubble { } } + override isClickableInFlyout(): boolean { + return false; + } + bubbleIsVisible(): boolean { return !!this.miniWorkspaceBubble; } diff --git a/core/icons/warning_icon.ts b/core/icons/warning_icon.ts index 7c44d0d34..f0862c3e9 100644 --- a/core/icons/warning_icon.ts +++ b/core/icons/warning_icon.ts @@ -160,6 +160,10 @@ export class WarningIcon extends Icon implements IHasBubble { this.setBubbleVisible(!this.bubbleIsVisible()); } + override isClickableInFlyout(): boolean { + return false; + } + bubbleIsVisible(): boolean { return !!this.textBubble; } diff --git a/core/interfaces/i_icon.ts b/core/interfaces/i_icon.ts index 8c1477997..a6159985f 100644 --- a/core/interfaces/i_icon.ts +++ b/core/interfaces/i_icon.ts @@ -83,6 +83,15 @@ export interface IIcon { * Notifies the icon that it has been clicked. */ onClick(): void; + + /** + * Check whether the icon should be clickable while the block is in a flyout. + * If this function is not defined, the icon will be clickable in all flyouts. + * + * @param autoClosingFlyout true if the containing flyout is an auto-closing one. + * @returns Whether the icon should be clickable while the block is in a flyout. + */ + isClickableInFlyout?(autoClosingFlyout: boolean): boolean; } /** Type guard that checks whether the given object is an IIcon. */ From 3f0da523dcd71910170ec7b429618d685606765b Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 7 Dec 2023 21:18:53 +0000 Subject: [PATCH 86/86] chore: Update metadata for 2023 Q4 release (#7700) --- tests/scripts/check_metadata.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/scripts/check_metadata.sh b/tests/scripts/check_metadata.sh index 15e3cdb85..1accb7148 100755 --- a/tests/scripts/check_metadata.sh +++ b/tests/scripts/check_metadata.sh @@ -36,7 +36,8 @@ readonly RELEASE_DIR='dist' # Q1 2023 9.2.1 909181 # Q2 2023 9.3.3 887618 # Q3 2023 10.1.3 898859 -readonly BLOCKLY_SIZE_EXPECTED=898859 +# Q4 2023 10.2.2 903535 +readonly BLOCKLY_SIZE_EXPECTED=903535 # Size of blocks_compressed.js # Q2 2019 2.20190722.0 75618 @@ -58,7 +59,8 @@ readonly BLOCKLY_SIZE_EXPECTED=898859 # Q1 2023 9.2.1 101114 # Q2 2023 9.3.3 91848 # Q3 2023 10.1.3 90150 -readonly BLOCKS_SIZE_EXPECTED=90150 +# Q4 2023 10.2.2 90269 +readonly BLOCKS_SIZE_EXPECTED=90269 # Size of blockly_compressed.js.gz # Q2 2019 2.20190722.0 180925 @@ -81,7 +83,8 @@ readonly BLOCKS_SIZE_EXPECTED=90150 # Q1 2023 9.2.1 179814 # Q2 2023 9.3.3 175206 # Q3 2023 10.1.3 180553 -readonly BLOCKLY_GZ_SIZE_EXPECTED=180553 +# Q4 2023 10.2.2 181474 +readonly BLOCKLY_GZ_SIZE_EXPECTED=181474 # Size of blocks_compressed.js.gz # Q2 2019 2.20190722.0 14552 @@ -103,7 +106,8 @@ readonly BLOCKLY_GZ_SIZE_EXPECTED=180553 # Q1 2023 9.2.1 17262 # Q2 2023 9.3.3 16736 # Q3 2023 10.1.3 16508 -readonly BLOCKS_GZ_SIZE_EXPECTED=16508 +# Q4 2023 10.2.2 16442 +readonly BLOCKS_GZ_SIZE_EXPECTED=16442 # ANSI colors readonly BOLD_GREEN='\033[1;32m'