diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..1bd12ca8b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,222 @@ +const rules = { + 'curly': ['error'], + 'eol-last': ['error'], + 'keyword-spacing': ['error'], + 'linebreak-style': ['error', 'unix'], + 'max-len': [ + 'error', + { + 'code': 100, + 'tabWidth': 4, + 'ignoreStrings': true, + 'ignoreRegExpLiterals': true, + 'ignoreUrls': true, + }, + ], + 'no-trailing-spaces': ['error', {'skipBlankLines': true}], + 'no-unused-vars': [ + 'warn', + { + 'args': 'after-used', + // Ignore vars starting with an underscore. + 'varsIgnorePattern': '^_', + // Ignore arguments starting with an underscore. + 'argsIgnorePattern': '^_', + }, + ], + // Blockly uses for exporting symbols. no-self-assign added in eslint 5. + 'no-self-assign': ['off'], + // Blockly uses single quotes except for JSON blobs, which must use double + // quotes. + 'quotes': ['off'], + 'semi': ['error', 'always'], + // Blockly doesn't have space before function paren when defining functions. + 'space-before-function-paren': ['error', 'never'], + // Blockly doesn't have space before function paren when calling functions. + 'func-call-spacing': ['error', 'never'], + 'space-infix-ops': ['error'], + // Blockly uses 'use strict' in files. + 'strict': ['off'], + // Closure style allows redeclarations. + 'no-redeclare': ['off'], + 'valid-jsdoc': ['error'], + 'no-console': ['off'], + 'no-multi-spaces': ['error', {'ignoreEOLComments': true}], + 'operator-linebreak': ['error', 'after'], + 'spaced-comment': [ + 'error', + 'always', + { + 'block': { + 'balanced': true, + }, + 'exceptions': ['*'], + }, + ], + // Blockly uses prefixes for optional arguments and test-only functions. + 'camelcase': [ + 'error', + { + 'properties': 'never', + 'allow': ['^opt_', '^_opt_', '^testOnly_'], + }, + ], + // Use clang-format for indentation by running `npm run format`. + 'indent': ['off'], + // Blockly uses capital letters for some non-constructor namespaces. + // Keep them for legacy reasons. + 'new-cap': ['off'], + // Mostly use default rules for brace style, but allow single-line blocks. + 'brace-style': ['error', '1tbs', {'allowSingleLine': true}], + // Blockly uses objects as maps, but uses Object.create(null) to + // instantiate them. + 'guard-for-in': ['off'], + 'prefer-spread': ['off'], + 'comma-dangle': [ + 'error', + { + 'arrays': 'always-multiline', + 'objects': 'always-multiline', + 'imports': 'always-multiline', + 'exports': 'always-multiline', + 'functions': 'ignore', + }, + ], +}; + +/** + * Build shared settings for TS linting and add in the config differences. + * @return {Object} The override TS linting for given files and a given + * tsconfig. + */ +function buildTSOverride({files, tsconfig}) { + return { + 'files': files, + 'plugins': [ + '@typescript-eslint/eslint-plugin', + 'jsdoc', + ], + 'settings': { + 'jsdoc': { + 'mode': 'typescript', + }, + }, + 'parser': '@typescript-eslint/parser', + 'parserOptions': { + 'project': tsconfig, + 'tsconfigRootDir': '.', + 'ecmaVersion': 2020, + 'sourceType': 'module', + }, + 'extends': [ + 'plugin:@typescript-eslint/recommended', + 'plugin:jsdoc/recommended', + ], + 'rules': { + // TS rules + // Blockly uses namespaces to do declaration merging in some cases. + '@typescript-eslint/no-namespace': ['off'], + // Use the updated TypeScript-specific rule. + 'no-invalid-this': ['off'], + '@typescript-eslint/no-invalid-this': ['error'], + // Needs decision. 601 problems. + '@typescript-eslint/no-non-null-assertion': ['off'], + // Use TS-specific rule. + 'no-unused-vars': ['off'], + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + 'argsIgnorePattern': '^_', + 'varsIgnorePattern': '^_', + }, + ], + 'func-call-spacing': ['off'], + '@typescript-eslint/func-call-spacing': ['warn'], + // Temporarily disable. 23 problems. + '@typescript-eslint/no-explicit-any': ['off'], + // Temporarily disable. 128 problems. + 'require-jsdoc': ['off'], + // Temporarily disable. 55 problems. + '@typescript-eslint/ban-types': ['off'], + // Temporarily disable. 33 problems. + '@typescript-eslint/no-empty-function': ['off'], + // Temporarily disable. 3 problems. + '@typescript-eslint/no-empty-interface': ['off'], + + // TsDoc rules (using JsDoc plugin) + // Disable built-in jsdoc verifier. + 'valid-jsdoc': ['off'], + // Don't require types in params and returns docs. + 'jsdoc/require-param-type': ['off'], + 'jsdoc/require-returns-type': ['off'], + // params and returns docs are optional. + 'jsdoc/require-param-description': ['off'], + 'jsdoc/require-returns': ['off'], + // Disable for now (breaks on `this` which is not really a param). + 'jsdoc/require-param': ['off'], + // Don't auto-add missing jsdoc. Only required on exported items. + 'jsdoc/require-jsdoc': [ + 'warn', + { + 'enableFixer': false, + 'publicOnly': true, + }, + ], + // Disable because of false alarms with Closure-supported tags. + // Re-enable after Closure is removed. + 'jsdoc/check-tag-names': ['off'], + // Re-enable after Closure is removed. There shouldn't even be + // types in the TsDoc. + // These are "types" because of Closure's @suppress {warningName} + 'jsdoc/no-undefined-types': ['off'], + 'jsdoc/valid-types': ['off'], + // Disabled due to not handling `this`. If re-enabled, + // checkDestructured option + // should be left as false. + 'jsdoc/check-param-names': ['off', {'checkDestructured': false}], + // Allow any text in the license tag. Other checks are not relevant. + 'jsdoc/check-values': ['off'], + 'jsdoc/newline-after-description': ['error'], + }, + }; +} + +// NOTE: When this output is put directly in `module.exports`, the formatter +// does not align with the linter. +const eslintJSON = { + 'rules': rules, + 'env': { + 'es2020': true, + 'browser': true, + }, + 'globals': { + 'goog': true, + 'exports': true, + }, + 'extends': [ + 'eslint:recommended', + 'google', + ], + // TypeScript-specific config. Uses above rules plus these. + 'overrides': [ + buildTSOverride({ + files: ['./core/**/*.ts', './core/**/*.tsx'], + tsconfig: './tsconfig.json', + }), + buildTSOverride({ + files: [ + './tests/typescript/**/*.ts', + './tests/typescript/**/*.tsx', + ], + tsconfig: './tests/typescript/tsconfig.json', + }), + { + 'files': ['./.eslintrc.js'], + 'env': { + 'node': true, + }, + }, + ], +}; + +module.exports = eslintJSON; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index eb5b9f339..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "rules": { - "curly": ["error"], - "eol-last": ["error"], - "keyword-spacing": ["error"], - "linebreak-style": ["error", "unix"], - "max-len": [ - "error", - { - "code": 100, - "tabWidth": 4, - "ignoreStrings": true, - "ignoreRegExpLiterals": true, - "ignoreUrls": true - } - ], - "no-trailing-spaces": ["error", { "skipBlankLines": true }], - "no-unused-vars": [ - "warn", - { - "args": "after-used", - // Ignore vars starting with an underscore. - "varsIgnorePattern": "^_", - // Ignore arguments starting with an underscore. - "argsIgnorePattern": "^_" - } - ], - // Blockly uses for exporting symbols. no-self-assign added in eslint 5. - "no-self-assign": ["off"], - // Blockly uses single quotes except for JSON blobs, which must use double quotes. - "quotes": ["off"], - "semi": ["error", "always"], - // Blockly doesn't have space before function paren when defining functions. - "space-before-function-paren": ["error", "never"], - // Blockly doesn't have space before function paren when calling functions. - "func-call-spacing": ["error", "never"], - "space-infix-ops": ["error"], - // Blockly uses 'use strict' in files. - "strict": ["off"], - // Closure style allows redeclarations. - "no-redeclare": ["off"], - "valid-jsdoc": ["error"], - "no-console": ["off"], - "no-multi-spaces": ["error", { "ignoreEOLComments": true }], - "operator-linebreak": ["error", "after"], - "spaced-comment": ["error", "always", { - "block": { - "balanced": true - }, - "exceptions": ["*"] - }], - // Blockly uses prefixes for optional arguments and test-only functions. - "camelcase": ["error", { - "properties": "never", - "allow": ["^opt_", "^_opt_", "^testOnly_"] - }], - // Use clang-format for indentation by running `npm run format`. - "indent": ["off"], - // Blockly uses capital letters for some non-constructor namespaces. - // Keep them for legacy reasons. - "new-cap": ["off"], - // Mostly use default rules for brace style, but allow single-line blocks. - "brace-style": ["error", "1tbs", { "allowSingleLine": true }], - // Blockly uses objects as maps, but uses Object.create(null) to - // instantiate them. - "guard-for-in": ["off"], - "prefer-spread": ["off"], - "comma-dangle": ["error", { - "arrays": "always-multiline", - "objects": "always-multiline", - "imports": "always-multiline", - "exports": "always-multiline", - "functions": "ignore" - }] - }, - "env": { - "es2020": true, - "browser": true - }, - "globals": { - "goog": true, - "exports": true - }, - "extends": [ - "eslint:recommended", "google" - ], - // TypeScript-specific config. Uses above rules plus these. - "overrides": [{ - "files": ["**/*.ts", "**/*.tsx"], - "plugins": [ - "@typescript-eslint/eslint-plugin", - "jsdoc" - ], - "settings": { - "jsdoc": { - "mode": "typescript" - } - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "./tsconfig.json", - "tsconfigRootDir": ".", - "ecmaVersion": 2020, - "sourceType": "module" - }, - "extends": [ - "plugin:@typescript-eslint/recommended", - "plugin:jsdoc/recommended" - ], - "rules": { - // TS rules - // Blockly uses namespaces to do declaration merging in some cases. - "@typescript-eslint/no-namespace": ["off"], - // Use the updated TypeScript-specific rule. - "no-invalid-this": ["off"], - "@typescript-eslint/no-invalid-this": ["error"], - // Needs decision. 601 problems. - "@typescript-eslint/no-non-null-assertion": ["off"], - // Use TS-specific rule. - "no-unused-vars": ["off"], - "@typescript-eslint/no-unused-vars": ["warn", { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_" - }], - "func-call-spacing": ["off"], - "@typescript-eslint/func-call-spacing": ["warn"], - // Temporarily disable. 23 problems. - "@typescript-eslint/no-explicit-any": ["off"], - // Temporarily disable. 128 problems. - "require-jsdoc": ["off"], - // Temporarily disable. 55 problems. - "@typescript-eslint/ban-types": ["off"], - // Temporarily disable. 33 problems. - "@typescript-eslint/no-empty-function": ["off"], - // Temporarily disable. 3 problems. - "@typescript-eslint/no-empty-interface": ["off"], - - // TsDoc rules (using JsDoc plugin) - // Disable built-in jsdoc verifier. - "valid-jsdoc": ["off"], - // Don't require types in params and returns docs. - "jsdoc/require-param-type": ["off"], - "jsdoc/require-returns-type": ["off"], - // params and returns docs are optional. - "jsdoc/require-param-description": ["off"], - "jsdoc/require-returns": ["off"], - // Disable for now (breaks on `this` which is not really a param). - "jsdoc/require-param": ["off"], - // Don't auto-add missing jsdoc. Only required on exported items. - "jsdoc/require-jsdoc": ["warn", {"enableFixer": false, "publicOnly": true}], - // Disable because of false alarms with Closure-supported tags. - // Re-enable after Closure is removed. - "jsdoc/check-tag-names": ["off"], - // Re-enable after Closure is removed. There shouldn't even be types in the TsDoc. - // These are "types" because of Closure's @suppress {warningName} - "jsdoc/no-undefined-types": ["off"], - "jsdoc/valid-types": ["off"], - // Disabled due to not handling `this`. If re-enabled, checkDestructured option - // should be left as false. - "jsdoc/check-param-names": ["off", {"checkDestructured": false}], - // Allow any text in the license tag. Other checks are not relevant. - "jsdoc/check-values": ["off"] - } - }] -} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6f2e01b3f..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: Bug Report -about: Create a report to help us improve -labels: 'type: bug, issue: triage' -assignees: '' - ---- - - - -**Describe the bug** - - - -**To Reproduce** - - -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** - - - -**Screenshots** - - - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Stack Traces** - - - -``` -Replace with error stack trace. -``` - -**Additional context** - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 000000000..c0097d770 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,58 @@ +name: Bug Report +description: Create a report to help us improve +labels: 'issue: bug, issue: triage' +body: + - type: markdown + attributes: + value: > + Thank you for taking the time to fill out a bug report! + If you have a question about how to use Blockly in your application, + please ask on the [forum](https://groups.google.com/forum/#!forum/blockly) instead of filing an issue. + - type: checkboxes + id: duplicates + attributes: + label: Check for duplicates + options: + - label: I have searched for similar issues before opening a new one. + - type: textarea + id: description + attributes: + label: Description + description: Please provide a clear and concise description of the bug. + placeholder: What happened? What did you expect to happen? + validations: + required: true + - type: textarea + id: repro + attributes: + label: Reproduction steps + description: What steps should we take to reproduce the issue? + value: | + 1. + 2. + 3. + - type: textarea + id: stack-trace + attributes: + label: Stack trace + description: If you saw an error message or stack trace, please include it here. + placeholder: The text in this section will be formatted automatically; no need to include backticks. + render: shell + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: Screenshots can help us see the behavior you're describing. Please add a screenshot or gif, especially if you are describing a rendering or visual bug. + placeholder: Paste or drag-and-drop an image to upload it. + - type: dropdown + id: browsers + attributes: + label: Browsers + description: Please select all browsers you've observed this behavior on. If the bug isn't browser-specific, you can leave this blank. + multiple: true + options: + - Chrome desktop + - Safari desktop + - Firefox desktop + - Android mobile + - iOS mobile diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index 343defc12..000000000 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Documentation -about: Report an issue with our documentation -labels: 'type: documentation, issue: triage' -assignees: '' - ---- - - - -**Where** - - - -**What** - - - -- [ ] Text -- [ ] Image or Gif -- [ ] Other - -**Old content** - - - -**Suggested content** - - - -**Additional context** - - diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml new file mode 100644 index 000000000..93d7f5011 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yaml @@ -0,0 +1,39 @@ + +name: Documentation +description: Report an issue with our documentation +labels: 'issue: docs, issue: triage' +body: + - type: markdown + attributes: + value: > + Thanks for helping us improve our developer site documentation! + Use this template to describe issues with the content on our + [developer site](https://developers.google.com/blockly/guides). + - type: input + id: link + attributes: + label: Location + description: > + A link to the page with the documentation you want us to be updated. + If no page exists, describe what the page should be, and where. + - type: checkboxes + id: type + attributes: + label: Type + description: What kind of content is it? + options: + - label: Text + - label: Image or Gif + - label: Other + - type: textarea + id: content + attributes: + label: Suggested content + description: Your suggestion for improved documentation. If it's helpful, also include the old content for comparison. + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context about the problem. If this is related to a specific pull request, link to it. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 668e1adb1..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -labels: 'type: feature request, issue: triage' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** - - - -**Describe the solution you'd like** - - - -**Describe alternatives you've considered** - - - -**Additional context** - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 000000000..f64640789 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,40 @@ + +name: Feature request +description: Suggest an idea for this project +labels: 'issue: feature request, issue: triage' +body: + - type: markdown + attributes: + value: > + Thank you for taking the time to fill out a feature request! + If you have a question about how to use Blockly in your application, + please ask on the [forum](https://groups.google.com/forum/#!forum/blockly) instead of filing an issue. + - type: checkboxes + id: duplicates + attributes: + label: Check for duplicates + options: + - label: I have searched for similar issues before opening a new one. + - type: textarea + id: problem + attributes: + label: Problem + description: Is your feature request related to a problem? Please describe. + placeholder: I'm always frustrated when... + - type: textarea + id: request + attributes: + label: Request + description: Describe your feature request and how it solves your problem. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Describe any alternative solutions or features you've considered. + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/appengine_deploy.yml b/.github/workflows/appengine_deploy.yml index a72ddecd3..fc27a2c46 100644 --- a/.github/workflows/appengine_deploy.yml +++ b/.github/workflows/appengine_deploy.yml @@ -42,7 +42,7 @@ jobs: path: _deploy/ - name: Deploy to App Engine - uses: google-github-actions/deploy-appengine@v1.0.0 + uses: google-github-actions/deploy-appengine@v1.2.2 # For parameters see: # https://github.com/google-github-actions/deploy-appengine#inputs with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 754aa4c11..8dd45b064 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,7 @@ permissions: jobs: build: + timeout-minutes: 10 runs-on: ${{ matrix.os }} strategy: @@ -17,8 +18,9 @@ jobs: # TODO (#2114): re-enable osx build. # os: [ubuntu-latest, macos-latest] os: [ubuntu-latest] - node-version: [14.x, 16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + node-version: [14.x, 16.x, 18.x] + # See supported Node.js release schedule at + # https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v3 @@ -53,6 +55,7 @@ jobs: CI: true lint: + timeout-minutes: 5 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -67,3 +70,18 @@ jobs: - name: Lint run: npm run lint + + clang-formatter: + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: DoozyX/clang-format-lint-action@v0.15 + with: + source: 'core' + extensions: 'js,ts' + # This should be as close as possible to the version that the npm + # package supports. This can be found by running: + # npx clang-format --version. + clangFormatVersion: 15 diff --git a/.github/workflows/check_clang_format.yml b/.github/workflows/check_clang_format.yml deleted file mode 100644 index 94dc3461f..000000000 --- a/.github/workflows/check_clang_format.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Check clang format - -# N.B.: Runs with a read-only repo token. Safe(ish) to check out the -# submitted branch. -on: [pull_request] - -permissions: - contents: read - -jobs: - clang-formatter: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - uses: DoozyX/clang-format-lint-action@v0.15 - with: - source: 'core' - extensions: 'js,ts' - # This should be as close as possible to the version that the npm - # package supports. This can be found by running: - # npx clang-format --version. - clangFormatVersion: 15 - - # The Report clang format workflow (report_clang_format.yml) will - # run (if required) after this one to post a comment to the PR. - # (Note that the version of that workflow run will be the one on - # the master (default) branch, not the PR target branch.) diff --git a/.github/workflows/update_metadata.yml b/.github/workflows/update_metadata.yml index b6cfdaf0c..33e58a285 100644 --- a/.github/workflows/update_metadata.yml +++ b/.github/workflows/update_metadata.yml @@ -36,7 +36,7 @@ jobs: run: source ./tests/scripts/update_metadata.sh - name: Create Pull Request - uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04 + uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 with: commit-message: Update build artifact sizes in check_metadata.sh delete-branch: true diff --git a/README.md b/README.md index eacfc8966..a0ab5a8bf 100644 --- a/README.md +++ b/README.md @@ -83,4 +83,4 @@ We typically triage all bugs within 2 working days, which includes adding any ap ## Good to Know * Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https://saucelabs.com) -* We support IE11 and test it using [BrowserStack](https://browserstack.com) +* We test browsers using [BrowserStack](https://browserstack.com) diff --git a/appengine/storage.js b/appengine/storage.js index 10db4f20b..a9eb74cc9 100644 --- a/appengine/storage.js +++ b/appengine/storage.js @@ -44,7 +44,7 @@ BlocklyStorage.restoreBlocks = function(opt_workspace) { var url = window.location.href.split('#')[0]; if ('localStorage' in window && window.localStorage[url]) { var workspace = opt_workspace || Blockly.getMainWorkspace(); - var xml = Blockly.Xml.textToDom(window.localStorage[url]); + var xml = Blockly.utils.xml.textToDom(window.localStorage[url]); Blockly.Xml.domToWorkspace(xml, workspace); } }; @@ -168,7 +168,7 @@ BlocklyStorage.monitorChanges_ = function(workspace) { */ BlocklyStorage.loadXml_ = function(xml, workspace) { try { - xml = Blockly.Xml.textToDom(xml); + xml = Blockly.utils.xml.textToDom(xml); } catch (e) { BlocklyStorage.alert(BlocklyStorage.XML_ERROR + '\nXML: ' + xml); return; diff --git a/blocks/colour.js b/blocks/colour.ts similarity index 82% rename from blocks/colour.js rename to blocks/colour.ts index 236b97c5c..b01c047b7 100644 --- a/blocks/colour.js +++ b/blocks/colour.ts @@ -7,24 +7,19 @@ /** * @fileoverview Colour blocks for Blockly. */ -'use strict'; -goog.module('Blockly.libraryBlocks.colour'); +import * as goog from '../closure/goog/goog.js'; +goog.declareModuleId('Blockly.libraryBlocks.colour'); -// const {BlockDefinition} = goog.requireType('Blockly.blocks'); -// TODO (6248): Properly import the BlockDefinition type. -/* eslint-disable-next-line no-unused-vars */ -const BlockDefinition = Object; -const {createBlockDefinitionsFromJsonArray, defineBlocks} = goog.require('Blockly.common'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldColour'); +import type {BlockDefinition} from '../core/blocks.js'; +import {createBlockDefinitionsFromJsonArray, defineBlocks} from '../core/common.js'; +import '../core/field_colour.js'; /** * A dictionary of the block definitions provided by this module. - * @type {!Object} */ -const blocks = createBlockDefinitionsFromJsonArray([ +export const blocks = createBlockDefinitionsFromJsonArray([ // Block for colour picker. { 'type': 'colour_picker', @@ -115,7 +110,6 @@ const blocks = createBlockDefinitionsFromJsonArray([ 'tooltip': '%{BKY_COLOUR_BLEND_TOOLTIP}', }, ]); -exports.blocks = blocks; // Register provided blocks. defineBlocks(blocks); diff --git a/blocks/lists.js b/blocks/lists.js index c83352aa0..526329300 100644 --- a/blocks/lists.js +++ b/blocks/lists.js @@ -12,8 +12,8 @@ goog.module('Blockly.libraryBlocks.lists'); +const fieldRegistry = goog.require('Blockly.fieldRegistry'); const xmlUtils = goog.require('Blockly.utils.xml'); -const Xml = goog.require('Blockly.Xml'); const {Align} = goog.require('Blockly.Input'); /* eslint-disable-next-line no-unused-vars */ const {Block} = goog.requireType('Blockly.Block'); @@ -22,7 +22,6 @@ const {Block} = goog.requireType('Blockly.Block'); /* eslint-disable-next-line no-unused-vars */ const BlockDefinition = Object; const {ConnectionType} = goog.require('Blockly.ConnectionType'); -const {FieldDropdown} = goog.require('Blockly.FieldDropdown'); const {Msg} = goog.require('Blockly.Msg'); const {Mutator} = goog.require('Blockly.Mutator'); /* eslint-disable-next-line no-unused-vars */ @@ -315,8 +314,11 @@ blocks['lists_indexOf'] = { this.setOutput(true, 'Number'); this.appendValueInput('VALUE').setCheck('Array').appendField( Msg['LISTS_INDEX_OF_INPUT_IN_LIST']); - this.appendValueInput('FIND').appendField( - new FieldDropdown(OPERATORS), 'END'); + const operatorsDropdown = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: OPERATORS, + }); + this.appendValueInput('FIND').appendField(operatorsDropdown, 'END'); this.setInputsInline(true); // Assign 'this' to a variable for use in the tooltip closure below. const thisBlock = this; @@ -347,8 +349,11 @@ blocks['lists_getIndex'] = { ]; this.setHelpUrl(Msg['LISTS_GET_INDEX_HELPURL']); this.setStyle('list_blocks'); - const modeMenu = new FieldDropdown( - MODE, + const modeMenu = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: MODE, + }); + modeMenu.setValidator( /** * @param {*} value The input value. * @this {FieldDropdown} @@ -480,7 +485,7 @@ blocks['lists_getIndex'] = { this.updateStatement_(true); } else if (typeof state === 'string') { // backward compatible for json serialised mutations - this.domToMutation(Xml.textToDom(state)); + this.domToMutation(xmlUtils.textToDom(state)); } }, @@ -526,8 +531,11 @@ blocks['lists_getIndex'] = { } else { this.appendDummyInput('AT'); } - const menu = new FieldDropdown( - this.WHERE_OPTIONS, + const menu = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: this.WHERE_OPTIONS, + }); + menu.setValidator( /** * @param {*} value The input value. * @this {FieldDropdown} @@ -576,8 +584,12 @@ blocks['lists_setIndex'] = { this.setStyle('list_blocks'); this.appendValueInput('LIST').setCheck('Array').appendField( Msg['LISTS_SET_INDEX_INPUT_IN_LIST']); + const operationDropdown = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: MODE, + }); this.appendDummyInput() - .appendField(new FieldDropdown(MODE), 'MODE') + .appendField(operationDropdown, 'MODE') .appendField('', 'SPACE'); this.appendDummyInput('AT'); this.appendValueInput('TO').appendField(Msg['LISTS_SET_INDEX_INPUT_TO']); @@ -689,8 +701,11 @@ blocks['lists_setIndex'] = { } else { this.appendDummyInput('AT'); } - const menu = new FieldDropdown( - this.WHERE_OPTIONS, + const menu = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: this.WHERE_OPTIONS, + }); + menu.setValidator( /** * @param {*} value The input value. * @this {FieldDropdown} @@ -817,8 +832,11 @@ blocks['lists_getSublist'] = { } else { this.appendDummyInput('AT' + n); } - const menu = new FieldDropdown( - this['WHERE_OPTIONS_' + n], + const menu = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: this['WHERE_OPTIONS_' + n], + }); + menu.setValidator( /** * @param {*} value The input value. * @this {FieldDropdown} @@ -899,14 +917,16 @@ blocks['lists_split'] = { init: function() { // Assign 'this' to a variable for use in the closures below. const thisBlock = this; - const dropdown = new FieldDropdown( - [ - [Msg['LISTS_SPLIT_LIST_FROM_TEXT'], 'SPLIT'], - [Msg['LISTS_SPLIT_TEXT_FROM_LIST'], 'JOIN'], - ], - function(newMode) { - thisBlock.updateType_(newMode); - }); + const dropdown = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: [ + [Msg['LISTS_SPLIT_LIST_FROM_TEXT'], 'SPLIT'], + [Msg['LISTS_SPLIT_TEXT_FROM_LIST'], 'JOIN'], + ], + }); + dropdown.setValidator(function(newMode) { + thisBlock.updateType_(newMode); + }); this.setHelpUrl(Msg['LISTS_SPLIT_HELPURL']); this.setStyle('list_blocks'); this.appendValueInput('INPUT').setCheck('String').appendField( diff --git a/blocks/math.js b/blocks/math.ts similarity index 82% rename from blocks/math.js rename to blocks/math.ts index b6ade7f89..1fdaf3807 100644 --- a/blocks/math.js +++ b/blocks/math.ts @@ -6,37 +6,28 @@ /** * @fileoverview Math blocks for Blockly. - * @suppress {checkTypes} */ -'use strict'; -goog.module('Blockly.libraryBlocks.math'); +import * as goog from '../closure/goog/goog.js'; +goog.declareModuleId('Blockly.libraryBlocks.math'); -const Extensions = goog.require('Blockly.Extensions'); -// N.B.: Blockly.FieldDropdown needed for type AND side-effects. -/* eslint-disable-next-line no-unused-vars */ -const FieldDropdown = goog.require('Blockly.FieldDropdown'); -const xmlUtils = goog.require('Blockly.utils.xml'); -/* eslint-disable-next-line no-unused-vars */ -const {Block} = goog.requireType('Blockly.Block'); -// const {BlockDefinition} = goog.requireType('Blockly.blocks'); -// TODO (6248): Properly import the BlockDefinition type. -/* eslint-disable-next-line no-unused-vars */ -const BlockDefinition = Object; -const {createBlockDefinitionsFromJsonArray, defineBlocks} = goog.require('Blockly.common'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldLabel'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldNumber'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldVariable'); +import * as Extensions from '../core/extensions.js'; +import type {Field} from '../core/field.js'; +import type {FieldDropdown} from '../core/field_dropdown.js'; +import * as xmlUtils from '../core/utils/xml.js'; +import type {Block} from '../core/block.js'; +import type {BlockDefinition} from '../core/blocks.js'; +import {createBlockDefinitionsFromJsonArray, defineBlocks} from '../core/common.js'; +import '../core/field_dropdown.js'; +import '../core/field_label.js'; +import '../core/field_number.js'; +import '../core/field_variable.js'; /** * A dictionary of the block definitions provided by this module. - * @type {!Object} */ -const blocks = createBlockDefinitionsFromJsonArray([ +export const blocks = createBlockDefinitionsFromJsonArray([ // Block for numeric value. { 'type': 'math_number', @@ -391,11 +382,11 @@ const blocks = createBlockDefinitionsFromJsonArray([ 'helpUrl': '%{BKY_MATH_ATAN2_HELPURL}', }, ]); -exports.blocks = blocks; /** * Mapping of math block OP value to tooltip message for blocks * math_arithmetic, math_simple, math_trig, and math_on_lists. + * * @see {Extensions#buildTooltipForDropdown} * @package * @readonly @@ -440,10 +431,15 @@ Extensions.register( 'math_op_tooltip', Extensions.buildTooltipForDropdown('OP', TOOLTIPS_BY_OP)); +/** Type of a block that has IS_DIVISBLEBY_MUTATOR_MIXIN */ +type DivisiblebyBlock = Block&DivisiblebyMixin; +interface DivisiblebyMixin extends DivisiblebyMixinType {}; +type DivisiblebyMixinType = typeof IS_DIVISIBLEBY_MUTATOR_MIXIN; /** * Mixin for mutator functions in the 'math_is_divisibleby_mutator' * extension. + * * @mixin * @augments Block * @package @@ -452,22 +448,22 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { /** * Create XML to represent whether the 'divisorInput' should be present. * Backwards compatible serialization implementation. - * @return {!Element} XML storage element. - * @this {Block} + * + * @returns XML storage element. */ - mutationToDom: function() { + mutationToDom: function(this: DivisiblebyBlock): Element { const container = xmlUtils.createElement('mutation'); const divisorInput = (this.getFieldValue('PROPERTY') === 'DIVISIBLE_BY'); - container.setAttribute('divisor_input', divisorInput); + container.setAttribute('divisor_input', String(divisorInput)); return container; }, /** * Parse XML to restore the 'divisorInput'. * Backwards compatible serialization implementation. - * @param {!Element} xmlElement XML storage element. - * @this {Block} + * + * @param xmlElement XML storage element. */ - domToMutation: function(xmlElement) { + domToMutation: function(this: DivisiblebyBlock, xmlElement: Element) { const divisorInput = (xmlElement.getAttribute('divisor_input') === 'true'); this.updateShape_(divisorInput); }, @@ -479,11 +475,10 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { /** * Modify this block to have (or not have) an input for 'is divisible by'. - * @param {boolean} divisorInput True if this block has a divisor input. - * @private - * @this {Block} + * + * @param divisorInput True if this block has a divisor input. */ - updateShape_: function(divisorInput) { + updateShape_: function(this: DivisiblebyBlock, divisorInput: boolean) { // Add or remove a Value Input. const inputExists = this.getInput('DIVISOR'); if (divisorInput) { @@ -500,20 +495,15 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { * 'math_is_divisibleby_mutator' extension to the 'math_property' block that * can update the block shape (add/remove divisor input) based on whether * property is "divisible by". - * @this {Block} - * @package */ -const IS_DIVISIBLE_MUTATOR_EXTENSION = function() { - this.getField('PROPERTY') - .setValidator( - /** - * @this {FieldDropdown} - * @param {*} option The selected dropdown option. - */ - function(option) { - const divisorInput = (option === 'DIVISIBLE_BY'); - this.getSourceBlock().updateShape_(divisorInput); - }); +const IS_DIVISIBLE_MUTATOR_EXTENSION = function(this: DivisiblebyBlock) { + this.getField('PROPERTY')!.setValidator( + /** @param option The selected dropdown option. */ + function(this: FieldDropdown, option: string) { + const divisorInput = (option === 'DIVISIBLE_BY'); + (this.getSourceBlock() as DivisiblebyBlock).updateShape_(divisorInput); + return undefined; // FieldValidators can't be void. Use option as-is. + }); }; Extensions.registerMutator( @@ -525,35 +515,35 @@ Extensions.register( 'math_change_tooltip', Extensions.buildTooltipWithFieldText('%{BKY_MATH_CHANGE_TOOLTIP}', 'VAR')); +/** Type of a block that has LIST_MODES_MUTATOR_MIXIN */ +type ListModesBlock = Block&ListModesMixin; +interface ListModesMixin extends ListModesMixinType {}; +type ListModesMixinType = typeof LIST_MODES_MUTATOR_MIXIN; + /** * Mixin with mutator methods to support alternate output based if the * 'math_on_list' block uses the 'MODE' operation. - * @mixin - * @augments Block - * @package - * @readonly */ const LIST_MODES_MUTATOR_MIXIN = { /** * Modify this block to have the correct output type. - * @param {string} newOp Either 'MODE' or some op than returns a number. - * @private - * @this {Block} + * + * @param newOp Either 'MODE' or some op than returns a number. */ - updateType_: function(newOp) { + updateType_: function(this: ListModesBlock, newOp: string) { if (newOp === 'MODE') { - this.outputConnection.setCheck('Array'); + this.outputConnection!.setCheck('Array'); } else { - this.outputConnection.setCheck('Number'); + this.outputConnection!.setCheck('Number'); } }, /** * Create XML to represent the output type. * Backwards compatible serialization implementation. - * @return {!Element} XML storage element. - * @this {Block} + * + * @returns XML storage element. */ - mutationToDom: function() { + mutationToDom: function(this: ListModesBlock): Element { const container = xmlUtils.createElement('mutation'); container.setAttribute('op', this.getFieldValue('OP')); return container; @@ -561,11 +551,13 @@ const LIST_MODES_MUTATOR_MIXIN = { /** * Parse XML to restore the output type. * Backwards compatible serialization implementation. - * @param {!Element} xmlElement XML storage element. - * @this {Block} + * + * @param xmlElement XML storage element. */ - domToMutation: function(xmlElement) { - this.updateType_(xmlElement.getAttribute('op')); + domToMutation: function(this: ListModesBlock, xmlElement: Element) { + const op = xmlElement.getAttribute('op'); + if (op === null) throw new TypeError('xmlElement had no op attribute'); + this.updateType_(op); }, // This block does not need JSO serialization hooks (saveExtraState and @@ -577,13 +569,13 @@ const LIST_MODES_MUTATOR_MIXIN = { /** * Extension to 'math_on_list' blocks that allows support of * modes operation (outputs a list of numbers). - * @this {Block} - * @package */ -const LIST_MODES_MUTATOR_EXTENSION = function() { - this.getField('OP').setValidator(function(newOp) { - this.updateType_(newOp); - }.bind(this)); +const LIST_MODES_MUTATOR_EXTENSION = function(this: ListModesBlock) { + this.getField('OP')!.setValidator( + function(this: ListModesBlock, newOp: string) { + this.updateType_(newOp); + return undefined; + }.bind(this)); }; Extensions.registerMutator( diff --git a/blocks/procedures.js b/blocks/procedures.js index c7a5d7fc3..130b4cf16 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -19,6 +19,7 @@ const Events = goog.require('Blockly.Events'); const Procedures = goog.require('Blockly.Procedures'); const Variables = goog.require('Blockly.Variables'); const Xml = goog.require('Blockly.Xml'); +const fieldRegistry = goog.require('Blockly.fieldRegistry'); const xmlUtils = goog.require('Blockly.utils.xml'); const {Align} = goog.require('Blockly.Input'); /* eslint-disable-next-line no-unused-vars */ @@ -28,10 +29,6 @@ const {Block} = goog.requireType('Blockly.Block'); /* eslint-disable-next-line no-unused-vars */ const BlockDefinition = Object; const {config} = goog.require('Blockly.config'); -/* eslint-disable-next-line no-unused-vars */ -const {FieldCheckbox} = goog.require('Blockly.FieldCheckbox'); -const {FieldLabel} = goog.require('Blockly.FieldLabel'); -const {FieldTextInput} = goog.require('Blockly.FieldTextInput'); const {Msg} = goog.require('Blockly.Msg'); const {Mutator} = goog.require('Blockly.Mutator'); const {Names} = goog.require('Blockly.Names'); @@ -454,7 +451,11 @@ blocks['procedures_defnoreturn'] = { */ init: function() { const initName = Procedures.findLegalName('', this); - const nameField = new FieldTextInput(initName, Procedures.rename); + const nameField = fieldRegistry.fromJson({ + type: 'field_input', + text: initName, + }); + nameField.setValidator(Procedures.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Msg['PROCEDURES_DEFNORETURN_TITLE']) @@ -497,7 +498,11 @@ blocks['procedures_defreturn'] = { */ init: function() { const initName = Procedures.findLegalName('', this); - const nameField = new FieldTextInput(initName, Procedures.rename); + const nameField = fieldRegistry.fromJson({ + type: 'field_input', + text: initName, + }); + nameField.setValidator(Procedures.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Msg['PROCEDURES_DEFRETURN_TITLE']) @@ -546,7 +551,12 @@ blocks['procedures_mutatorcontainer'] = { this.appendStatementInput('STACK'); this.appendDummyInput('STATEMENT_INPUT') .appendField(Msg['PROCEDURES_ALLOW_STATEMENTS']) - .appendField(new FieldCheckbox('TRUE'), 'STATEMENTS'); + .appendField( + fieldRegistry.fromJson({ + type: 'field_checkbox', + checked: true, + }), + 'STATEMENTS'); this.setStyle('procedure_blocks'); this.setTooltip(Msg['PROCEDURES_MUTATORCONTAINER_TOOLTIP']); this.contextMenu = false; @@ -559,7 +569,11 @@ blocks['procedures_mutatorarg'] = { * @this {Block} */ init: function() { - const field = new FieldTextInput(Procedures.DEFAULT_ARG, this.validator_); + const field = fieldRegistry.fromJson({ + type: 'field_input', + text: Procedures.DEFAULT_ARG, + }); + field.setValidator(this.validator_); // Hack: override showEditor to do just a little bit more work. // We don't have a good place to hook into the start of a text edit. field.oldShowEditorFn_ = field.showEditor_; @@ -810,7 +824,10 @@ const PROCEDURE_CALL_COMMON = { } } else { // Add new input. - const newField = new FieldLabel(this.arguments_[i]); + const newField = fieldRegistry.fromJson({ + type: 'field_label', + text: this.arguments_[i], + }); const input = this.appendValueInput('ARG' + i) .setAlign(Align.RIGHT) .appendField(newField, 'ARGNAME' + i); diff --git a/blocks/text.js b/blocks/text.js index 88a5b8012..66bd06752 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -14,6 +14,7 @@ goog.module('Blockly.libraryBlocks.texts'); const Extensions = goog.require('Blockly.Extensions'); const {Msg} = goog.require('Blockly.Msg'); +const fieldRegistry = goog.require('Blockly.fieldRegistry'); /* eslint-disable-next-line no-unused-vars */ const xmlUtils = goog.require('Blockly.utils.xml'); const {Align} = goog.require('Blockly.Input'); @@ -24,9 +25,6 @@ const {Block} = goog.requireType('Blockly.Block'); /* eslint-disable-next-line no-unused-vars */ const BlockDefinition = Object; const {ConnectionType} = goog.require('Blockly.ConnectionType'); -const {FieldDropdown} = goog.require('Blockly.FieldDropdown'); -const {FieldImage} = goog.require('Blockly.FieldImage'); -const {FieldTextInput} = goog.require('Blockly.FieldTextInput'); const {Mutator} = goog.require('Blockly.Mutator'); /* eslint-disable-next-line no-unused-vars */ const {Workspace} = goog.requireType('Blockly.Workspace'); @@ -338,8 +336,11 @@ blocks['text_getSubstring'] = { this.removeInput('TAIL', true); this.appendDummyInput('TAIL').appendField(Msg['TEXT_GET_SUBSTRING_TAIL']); } - const menu = new FieldDropdown( - this['WHERE_OPTIONS_' + n], + const menu = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: this['WHERE_OPTIONS_' + n], + }); + menu.setValidator( /** * @param {*} value The input value. * @this {FieldDropdown} @@ -385,7 +386,11 @@ blocks['text_changeCase'] = { this.setHelpUrl(Msg['TEXT_CHANGECASE_HELPURL']); this.setStyle('text_blocks'); this.appendValueInput('TEXT').setCheck('String').appendField( - new FieldDropdown(OPERATORS), 'CASE'); + fieldRegistry.fromJson({ + type: 'field_dropdown', + options: OPERATORS, + }), + 'CASE'); this.setOutput(true, 'String'); this.setTooltip(Msg['TEXT_CHANGECASE_TOOLTIP']); }, @@ -405,7 +410,11 @@ blocks['text_trim'] = { this.setHelpUrl(Msg['TEXT_TRIM_HELPURL']); this.setStyle('text_blocks'); this.appendValueInput('TEXT').setCheck('String').appendField( - new FieldDropdown(OPERATORS), 'MODE'); + fieldRegistry.fromJson({ + type: 'field_dropdown', + options: OPERATORS, + }), + 'MODE'); this.setOutput(true, 'String'); this.setTooltip(Msg['TEXT_TRIM_TOOLTIP']); }, @@ -486,7 +495,11 @@ blocks['text_prompt_ext'] = { this.setStyle('text_blocks'); // Assign 'this' to a variable for use in the closures below. const thisBlock = this; - const dropdown = new FieldDropdown(TYPES, function(newOp) { + const dropdown = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: TYPES, + }); + dropdown.setValidator(function(newOp) { thisBlock.updateType_(newOp); }); this.appendValueInput('TEXT').appendField(dropdown, 'TYPE'); @@ -522,13 +535,22 @@ blocks['text_prompt'] = { const thisBlock = this; this.setHelpUrl(Msg['TEXT_PROMPT_HELPURL']); this.setStyle('text_blocks'); - const dropdown = new FieldDropdown(TYPES, function(newOp) { + const dropdown = fieldRegistry.fromJson({ + type: 'field_dropdown', + options: TYPES, + }); + dropdown.setValidator(function(newOp) { thisBlock.updateType_(newOp); }); this.appendDummyInput() .appendField(dropdown, 'TYPE') .appendField(this.newQuote_(true)) - .appendField(new FieldTextInput(''), 'TEXT') + .appendField( + fieldRegistry.fromJson({ + type: 'field_input', + text: '', + }), + 'TEXT') .appendField(this.newQuote_(false)); this.setOutput(true, 'String'); this.setTooltip(function() { @@ -696,9 +718,13 @@ const QUOTE_IMAGE_MIXIN = { const isLeft = this.RTL ? !open : open; const dataUri = isLeft ? this.QUOTE_IMAGE_LEFT_DATAURI : this.QUOTE_IMAGE_RIGHT_DATAURI; - return new FieldImage( - dataUri, this.QUOTE_IMAGE_WIDTH, this.QUOTE_IMAGE_HEIGHT, - isLeft ? '\u201C' : '\u201D'); + return fieldRegistry.fromJson({ + type: 'field_image', + src: dataUri, + width: this.QUOTE_IMAGE_WIDTH, + height: this.QUOTE_IMAGE_HEIGHT, + alt: isLeft ? '\u201C' : '\u201D', + }); }, }; diff --git a/closure/bin/calcdeps.py b/closure/bin/calcdeps.py deleted file mode 100644 index 67e5e8d15..000000000 --- a/closure/bin/calcdeps.py +++ /dev/null @@ -1,325 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006 The Closure Library Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS-IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -"""Calculates JavaScript dependencies without requiring Google's build system. - -It iterates over a number of search paths and builds a dependency tree. With -the inputs provided, it walks the dependency tree and outputs all the files -required for compilation. -""" - - -import logging -import os -import re -import sys - - -_BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)' -req_regex = re.compile(_BASE_REGEX_STRING % 'require') -prov_regex = re.compile(_BASE_REGEX_STRING % 'provide') -ns_regex = re.compile('^ns:((\w+\.)*(\w+))$') - - -def IsValidFile(ref): - """Returns true if the provided reference is a file and exists.""" - return os.path.isfile(ref) - - -def IsJsFile(ref): - """Returns true if the provided reference is a JavaScript file.""" - return ref.endswith('.js') - - -def IsNamespace(ref): - """Returns true if the provided reference is a namespace.""" - return re.match(ns_regex, ref) is not None - - -def IsDirectory(ref): - """Returns true if the provided reference is a directory.""" - return os.path.isdir(ref) - - -def ExpandDirectories(refs): - """Expands any directory references into inputs. - - Description: - Looks for any directories in the provided references. Found directories - are recursively searched for .js files, which are then added to the result - list. - - Args: - refs: a list of references such as files, directories, and namespaces - - Returns: - A list of references with directories removed and replaced by any - .js files that are found in them. Also, the paths will be normalized. - """ - result = [] - for ref in refs: - if IsDirectory(ref): - # Disable 'Unused variable' for subdirs - # pylint: disable=unused-variable - for (directory, subdirs, filenames) in os.walk(ref): - for filename in filenames: - if IsJsFile(filename): - result.append(os.path.join(directory, filename)) - else: - result.append(ref) - return map(os.path.normpath, result) - - -class DependencyInfo(object): - """Represents a dependency that is used to build and walk a tree.""" - - def __init__(self, filename): - self.filename = filename - self.provides = [] - self.requires = [] - - def __str__(self): - return '%s Provides: %s Requires: %s' % (self.filename, - repr(self.provides), - repr(self.requires)) - - -def BuildDependenciesFromFiles(files): - """Build a list of dependencies from a list of files. - - Description: - Takes a list of files, extracts their provides and requires, and builds - out a list of dependency objects. - - Args: - files: a list of files to be parsed for goog.provides and goog.requires. - - Returns: - A list of dependency objects, one for each file in the files argument. - """ - result = [] - filenames = set() - for filename in files: - if filename in filenames: - continue - - # Python 3 requires the file encoding to be specified - if (sys.version_info[0] < 3): - file_handle = open(filename, 'r') - else: - file_handle = open(filename, 'r', encoding='utf8') - - try: - dep = CreateDependencyInfo(filename, file_handle) - result.append(dep) - finally: - file_handle.close() - - filenames.add(filename) - - return result - - -def CreateDependencyInfo(filename, source): - """Create dependency info. - - Args: - filename: Filename for source. - source: File-like object containing source. - - Returns: - A DependencyInfo object with provides and requires filled. - """ - dep = DependencyInfo(filename) - for line in source: - if re.match(req_regex, line): - dep.requires.append(re.search(req_regex, line).group(1)) - if re.match(prov_regex, line): - dep.provides.append(re.search(prov_regex, line).group(1)) - return dep - - -def BuildDependencyHashFromDependencies(deps): - """Builds a hash for searching dependencies by the namespaces they provide. - - Description: - Dependency objects can provide multiple namespaces. This method enumerates - the provides of each dependency and adds them to a hash that can be used - to easily resolve a given dependency by a namespace it provides. - - Args: - deps: a list of dependency objects used to build the hash. - - Raises: - Exception: If a multiple files try to provide the same namepace. - - Returns: - A hash table { namespace: dependency } that can be used to resolve a - dependency by a namespace it provides. - """ - dep_hash = {} - for dep in deps: - for provide in dep.provides: - if provide in dep_hash: - raise Exception('Duplicate provide (%s) in (%s, %s)' % ( - provide, - dep_hash[provide].filename, - dep.filename)) - dep_hash[provide] = dep - return dep_hash - - -def CalculateDependencies(paths, inputs): - """Calculates the dependencies for given inputs. - - Description: - This method takes a list of paths (files, directories) and builds a - searchable data structure based on the namespaces that each .js file - provides. It then parses through each input, resolving dependencies - against this data structure. The final output is a list of files, - including the inputs, that represent all of the code that is needed to - compile the given inputs. - - Args: - paths: the references (files, directories) that are used to build the - dependency hash. - inputs: the inputs (files, directories, namespaces) that have dependencies - that need to be calculated. - - Raises: - Exception: if a provided input is invalid. - - Returns: - A list of all files, including inputs, that are needed to compile the given - inputs. - """ - deps = BuildDependenciesFromFiles(paths + inputs) - search_hash = BuildDependencyHashFromDependencies(deps) - result_list = [] - seen_list = [] - for input_file in inputs: - if IsNamespace(input_file): - namespace = re.search(ns_regex, input_file).group(1) - if namespace not in search_hash: - raise Exception('Invalid namespace (%s)' % namespace) - input_file = search_hash[namespace].filename - if not IsValidFile(input_file) or not IsJsFile(input_file): - raise Exception('Invalid file (%s)' % input_file) - seen_list.append(input_file) - file_handle = open(input_file, 'r') - try: - for line in file_handle: - if re.match(req_regex, line): - require = re.search(req_regex, line).group(1) - ResolveDependencies(require, search_hash, result_list, seen_list) - finally: - file_handle.close() - result_list.append(input_file) - - return result_list - - -def FindClosureBasePath(paths): - """Given a list of file paths, return Closure base.js path, if any. - - Args: - paths: A list of paths. - - Returns: - The path to Closure's base.js file including filename, if found. - """ - - for path in paths: - pathname, filename = os.path.split(path) - - if filename == 'base.js': - f = open(path) - - is_base = False - - # Sanity check that this is the Closure base file. Check that this - # is where goog is defined. This is determined by the @provideGoog - # flag. - for line in f: - if '@provideGoog' in line: - is_base = True - break - - f.close() - - if is_base: - return path - -def ResolveDependencies(require, search_hash, result_list, seen_list): - """Takes a given requirement and resolves all of the dependencies for it. - - Description: - A given requirement may require other dependencies. This method - recursively resolves all dependencies for the given requirement. - - Raises: - Exception: when require does not exist in the search_hash. - - Args: - require: the namespace to resolve dependencies for. - search_hash: the data structure used for resolving dependencies. - result_list: a list of filenames that have been calculated as dependencies. - This variable is the output for this function. - seen_list: a list of filenames that have been 'seen'. This is required - for the dependency->dependent ordering. - """ - if require not in search_hash: - raise Exception('Missing provider for (%s)' % require) - - dep = search_hash[require] - if not dep.filename in seen_list: - seen_list.append(dep.filename) - for sub_require in dep.requires: - ResolveDependencies(sub_require, search_hash, result_list, seen_list) - result_list.append(dep.filename) - - -def GetDepsLine(dep, base_path): - """Returns a JS string for a dependency statement in the deps.js file. - - Args: - dep: The dependency that we're printing. - base_path: The path to Closure's base.js including filename. - """ - return 'goog.addDependency("%s", %s, %s);' % ( - GetRelpath(dep.filename, base_path), dep.provides, dep.requires) - - -def GetRelpath(path, start): - """Return a relative path to |path| from |start|.""" - # NOTE: Python 2.6 provides os.path.relpath, which has almost the same - # functionality as this function. Since we want to support 2.4, we have - # to implement it manually. :( - path_list = os.path.abspath(os.path.normpath(path)).split(os.sep) - start_list = os.path.abspath( - os.path.normpath(os.path.dirname(start))).split(os.sep) - - common_prefix_count = 0 - for i in range(0, min(len(path_list), len(start_list))): - if path_list[i] != start_list[i]: - break - common_prefix_count += 1 - - # Always use forward slashes, because this will get expanded to a url, - # not a file path. - return '/'.join(['..'] * (len(start_list) - common_prefix_count) + - path_list[common_prefix_count:]) diff --git a/closure/goog/base.js b/closure/goog/base.js index 392e0735f..9f5f18a6f 100644 --- a/closure/goog/base.js +++ b/closure/goog/base.js @@ -617,8 +617,10 @@ goog.declareModuleId = function(namespace) { 'within an ES6 module'); } if (goog.moduleLoaderState_ && goog.moduleLoaderState_.moduleName) { - // throw new Error( - // 'goog.declareModuleId may only be called once per module.'); + throw new Error( + 'goog.declareModuleId may only be called once per module.' + + 'This error can also be caused by circular imports, which ' + + 'are not supported by debug module loader.'); } if (namespace in goog.loadedModules_) { throw new Error( @@ -725,7 +727,7 @@ if (!COMPILED) { // NOTE: We add goog.module as an implicit namespace as goog.module is defined // here and because the existing module package has not been moved yet out of - // the goog.module namespace. This satisifies both the debug loader and + // the goog.module namespace. This satisfies both the debug loader and // ahead-of-time dependency management. } diff --git a/core/any_aliases.ts b/core/any_aliases.ts index 6b3c413cb..b04621726 100644 --- a/core/any_aliases.ts +++ b/core/any_aliases.ts @@ -1,2 +1,8 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + // eslint-disable-next-line type AnyDuringMigration = any; diff --git a/core/block.ts b/core/block.ts index de8f16680..33dc56af3 100644 --- a/core/block.ts +++ b/core/block.ts @@ -35,7 +35,6 @@ import {Align, Input} from './input.js'; import {inputTypes} from './input_types.js'; import type {IASTNodeLocation} from './interfaces/i_ast_node_location.js'; import type {IDeletable} from './interfaces/i_deletable.js'; -import {ASTNode} from './keyboard_nav/ast_node.js'; import type {Mutator} from './mutator.js'; import * as Tooltip from './tooltip.js'; import * as arrayUtils from './utils/array.js'; @@ -50,8 +49,6 @@ import type {Workspace} from './workspace.js'; /** * Class for one block. * Not normally called directly, workspace.newBlock() is preferred. - * - * @alias Blockly.Block */ export class Block implements IASTNodeLocation, IDeletable { /** @@ -59,7 +56,7 @@ export class Block implements IASTNodeLocation, IDeletable { * changes. This is usually only called from the constructor, the block type * initializer function, or an extension initializer function. */ - onchange?: ((p1: Abstract) => AnyDuringMigration)|null; + onchange?: ((p1: Abstract) => void)|null; /** The language-neutral ID given to the collapsed input. */ static readonly COLLAPSED_INPUT_NAME: string = constants.COLLAPSED_INPUT_NAME; @@ -93,39 +90,38 @@ export class Block implements IASTNodeLocation, IDeletable { protected styleName_ = ''; /** An optional method called during initialization. */ - init?: (() => AnyDuringMigration)|null = undefined; + init?: (() => void); /** An optional method called during disposal. */ - destroy?: (() => void) = undefined; + destroy?: (() => void); /** * An optional serialization method for defining how to serialize the * mutation state to XML. This must be coupled with defining * `domToMutation`. */ - mutationToDom?: ((...p1: AnyDuringMigration[]) => Element)|null = undefined; + mutationToDom?: (...p1: AnyDuringMigration[]) => Element; /** * An optional deserialization method for defining how to deserialize the * mutation state from XML. This must be coupled with defining * `mutationToDom`. */ - domToMutation?: ((p1: Element) => AnyDuringMigration)|null = undefined; + domToMutation?: (p1: Element) => void; /** * An optional serialization method for defining how to serialize the * block's extra state (eg mutation state) to something JSON compatible. * This must be coupled with defining `loadExtraState`. */ - saveExtraState?: (() => AnyDuringMigration)|null = undefined; + saveExtraState?: () => AnyDuringMigration; /** * An optional serialization method for defining how to deserialize the * block's extra state (eg mutation state) from something JSON compatible. * This must be coupled with defining `saveExtraState`. */ - loadExtraState?: - ((p1: AnyDuringMigration) => AnyDuringMigration)|null = undefined; + loadExtraState?: (p1: AnyDuringMigration) => void; /** * An optional property for suppressing adding STATEMENT_PREFIX and @@ -139,31 +135,25 @@ export class Block implements IASTNodeLocation, IDeletable { * shown to the user, but are declared as global variables in the generated * code. */ - getDeveloperVariables?: (() => string[]) = undefined; + getDeveloperVariables?: () => string[]; /** * An optional function that reconfigures the block based on the contents of * the mutator dialog. */ - compose?: ((p1: Block) => void) = undefined; + compose?: (p1: Block) => void; /** * An optional function that populates the mutator's dialog with * this block's components. */ - decompose?: ((p1: Workspace) => Block) = undefined; + decompose?: (p1: Workspace) => Block; id: string; - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - outputConnection: Connection = null as AnyDuringMigration; - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - nextConnection: Connection = null as AnyDuringMigration; - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - previousConnection: Connection = null as AnyDuringMigration; + outputConnection: Connection|null = null; + nextConnection: Connection|null = null; + previousConnection: Connection|null = null; inputList: Input[] = []; - inputsInline?: boolean = undefined; + inputsInline?: boolean; private disabled = false; tooltip: Tooltip.TipInfo = ''; contextMenu = true; @@ -205,19 +195,17 @@ export class Block implements IASTNodeLocation, IDeletable { protected isInsertionMarker_ = false; /** Name of the type of hat. */ - hat?: string = undefined; + hat?: string; rendered: boolean|null = null; /** * String for block help, or function that returns a URL. Null for no help. */ - // AnyDuringMigration because: Type 'null' is not assignable to type 'string - // | Function'. - helpUrl: string|Function = null as AnyDuringMigration; + helpUrl: string|Function|null = null; /** A bound callback function to use when the parent workspace changes. */ - private onchangeWrapper_: ((p1: Abstract) => AnyDuringMigration)|null = null; + private onchangeWrapper_: ((p1: Abstract) => void)|null = null; /** * A count of statement inputs on the block. @@ -301,9 +289,7 @@ export class Block implements IASTNodeLocation, IDeletable { eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CREATE))(this)); } } finally { - if (!existingGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); // In case init threw, recordUndo flag should still be reset. eventUtils.setRecordUndo(initialUndoFlag); } @@ -324,44 +310,45 @@ export class Block implements IASTNodeLocation, IDeletable { * @suppress {checkTypes} */ dispose(healStack: boolean) { - if (this.isDeadOrDying()) { - return; - } - // Terminate onchange event calls. + if (this.isDeadOrDying()) return; + + // Dispose of this change listener before unplugging. + // Technically not necessary due to the event firing delay. + // But future-proofing. if (this.onchangeWrapper_) { this.workspace.removeChangeListener(this.onchangeWrapper_); } this.unplug(healStack); if (eventUtils.isEnabled()) { + // Constructing the delete event is costly. Only perform if necessary. eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_DELETE))(this)); } - eventUtils.disable(); + this.workspace.removeTopBlock(this); + this.disposeInternal(); + } + /** + * Disposes of this block without doing things required by the top block. + * E.g. does not fire events, unplug the block, etc. + */ + protected disposeInternal() { + if (this.isDeadOrDying()) return; + + if (this.onchangeWrapper_) { + this.workspace.removeChangeListener(this.onchangeWrapper_); + } + + eventUtils.disable(); try { - // This block is now at the top of the workspace. - // Remove this block from the workspace's list of top-most blocks. - this.workspace.removeTopBlock(this); this.workspace.removeTypedBlock(this); - // Remove from block database. this.workspace.removeBlockById(this.id); this.disposing = true; - // First, dispose of all my children. - for (let i = this.childBlocks_.length - 1; i >= 0; i--) { - this.childBlocks_[i].dispose(false); - } - // Then dispose of myself. - // Dispose of all inputs and their fields. - for (let i = 0, input; input = this.inputList[i]; i++) { - input.dispose(); - } + this.childBlocks_.forEach((c) => c.disposeInternal()); + this.inputList.forEach((i) => i.dispose()); this.inputList.length = 0; - // Dispose of any remaining connections (next/previous/output). - const connections = this.getConnections_(true); - for (let i = 0, connection; connection = connections[i]; i++) { - connection.dispose(); - } + this.getConnections_(true).forEach((c) => c.dispose()); } finally { eventUtils.enable(); if (typeof this.destroy === 'function') { @@ -424,7 +411,7 @@ export class Block implements IASTNodeLocation, IDeletable { */ private unplugFromRow_(opt_healStack?: boolean) { let parentConnection = null; - if (this.outputConnection.isConnected()) { + if (this.outputConnection?.isConnected()) { parentConnection = this.outputConnection.targetConnection; // Disconnect from any superior block. this.outputConnection.disconnect(); @@ -489,7 +476,7 @@ export class Block implements IASTNodeLocation, IDeletable { */ private unplugFromStack_(opt_healStack?: boolean) { let previousTarget = null; - if (this.previousConnection.isConnected()) { + if (this.previousConnection?.isConnected()) { // Remember the connection that any next statements need to connect to. previousTarget = this.previousConnection.targetConnection; // Detach this block from the parent's tree. @@ -498,7 +485,7 @@ export class Block implements IASTNodeLocation, IDeletable { const nextBlock = this.getNextBlock(); if (opt_healStack && nextBlock && !nextBlock.isShadow()) { // Disconnect the next statement. - const nextTarget = this.nextConnection.targetConnection; + const nextTarget = this.nextConnection?.targetConnection ?? null; nextTarget?.disconnect(); if (previousTarget && this.workspace.connectionChecker.canConnect( @@ -797,6 +784,15 @@ export class Block implements IASTNodeLocation, IDeletable { !this.workspace.options.readOnly; } + /** + * Return whether this block's own deletable property is true or false. + * + * @returns True if the block's deletable property is true, false otherwise. + */ + isOwnDeletable(): boolean { + return this.deletable_; + } + /** * Set whether this block is deletable or not. * @@ -810,12 +806,23 @@ export class Block implements IASTNodeLocation, IDeletable { * Get whether this block is movable or not. * * @returns True if movable. + * @internal */ isMovable(): boolean { return this.movable_ && !this.isShadow_ && !this.isDeadOrDying() && !this.workspace.options.readOnly; } + /** + * Return whether this block's own movable property is true or false. + * + * @returns True if the block's movable property is true, false otherwise. + * @internal + */ + isOwnMovable(): boolean { + return this.movable_; + } + /** * Set whether this block is movable or not. * @@ -884,12 +891,22 @@ export class Block implements IASTNodeLocation, IDeletable { * Get whether this block is editable or not. * * @returns True if editable. + * @internal */ isEditable(): boolean { return this.editable_ && !this.isDeadOrDying() && !this.workspace.options.readOnly; } + /** + * Return whether this block's own editable property is true or false. + * + * @returns True if the block's editable property is true, false otherwise. + */ + isOwnEditable(): boolean { + return this.editable_; + } + /** * Set whether this block is editable or not. * @@ -1024,7 +1041,7 @@ export class Block implements IASTNodeLocation, IDeletable { * @param onchangeFn The callback to call when the block's workspace changes. * @throws {Error} if onchangeFn is not falsey and not a function. */ - setOnChange(onchangeFn: (p1: Abstract) => AnyDuringMigration) { + setOnChange(onchangeFn: (p1: Abstract) => void) { if (onchangeFn && typeof onchangeFn !== 'function') { throw Error('onchange must be a function.'); } @@ -1066,11 +1083,12 @@ export class Block implements IASTNodeLocation, IDeletable { * @returns List of variable ids. */ getVars(): string[] { - const vars = []; + const vars: string[] = []; for (let i = 0, input; input = this.inputList[i]; i++) { for (let j = 0, field; field = input.fieldRow[j]; j++) { if (field.referencesVariables()) { - vars.push(field.getValue()); + // NOTE: This only applies to `FieldVariable`, a `Field` + vars.push(field.getValue() as string); } } } @@ -1190,9 +1208,7 @@ export class Block implements IASTNodeLocation, IDeletable { 'connection.'); } this.previousConnection.dispose(); - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - this.previousConnection = null as AnyDuringMigration; + this.previousConnection = null; } } } @@ -1222,9 +1238,7 @@ export class Block implements IASTNodeLocation, IDeletable { 'connection.'); } this.nextConnection.dispose(); - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - this.nextConnection = null as AnyDuringMigration; + this.nextConnection = null; } } } @@ -1253,9 +1267,7 @@ export class Block implements IASTNodeLocation, IDeletable { 'Must disconnect output value before removing connection.'); } this.outputConnection.dispose(); - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Connection'. - this.outputConnection = null as AnyDuringMigration; + this.outputConnection = null; } } } @@ -1386,21 +1398,52 @@ export class Block implements IASTNodeLocation, IDeletable { * Create a human-readable text representation of this block and any children. * * @param opt_maxLength Truncate the string to this length. - * @param opt_emptyToken The placeholder string used to denote an empty field. + * @param opt_emptyToken The placeholder string used to denote an empty input. * If not specified, '?' is used. * @returns Text of block. */ toString(opt_maxLength?: number, opt_emptyToken?: string): string { + const tokens = this.toTokens(opt_emptyToken); + + // Run through our tokens array and simplify expression to remove + // parentheses around single field blocks. + // E.g. ['repeat', '(', '10', ')', 'times', 'do', '?'] + for (let i = 2; i < tokens.length; i++) { + if (tokens[i - 2] === '(' && tokens[i] === ')') { + tokens[i - 2] = tokens[i - 1]; + tokens.splice(i - 1, 2); + } + } + + // Join the text array, removing the spaces around added parentheses. + let prev = ''; + let text: string = tokens.reduce((acc, curr) => { + const val = acc + ((prev === '(' || curr === ')') ? '' : ' ') + curr; + prev = curr[curr.length - 1]; + return val; + }, ''); + + text = text.trim() || '???'; + if (opt_maxLength) { + // TODO: Improve truncation so that text from this block is given + // priority. E.g. "1+2+3+4+5+6+7+8+9=0" should be "...6+7+8+9=0", not + // "1+2+3+4+5...". E.g. "1+2+3+4+5=6+7+8+9+0" should be "...4+5=6+7...". + if (text.length > opt_maxLength) { + text = text.substring(0, opt_maxLength - 3) + '...'; + } + } + return text; + } + + /** + * Converts this block into string tokens. + * + * @param emptyToken The token to use in place of an empty input. + * Defaults to '?'. + * @returns The array of string tokens representing this block. + */ + private toTokens(emptyToken = '?'): string[] { const tokens = []; - const emptyFieldPlaceholder = opt_emptyToken || '?'; - - // Temporarily set flag to navigate to all fields. - const prevNavigateFields = ASTNode.NAVIGATE_ALL_FIELDS; - ASTNode.NAVIGATE_ALL_FIELDS = true; - - let node = ASTNode.createBlockNode(this); - const rootNode = node; - /** * Whether or not to add parentheses around an input. * @@ -1416,84 +1459,26 @@ export class Block implements IASTNodeLocation, IDeletable { (checks.indexOf('Boolean') !== -1 || checks.indexOf('Number') !== -1); } - /** Check that we haven't circled back to the original root node. */ - function checkRoot() { - if (node && node.getType() === rootNode?.getType() && - node.getLocation() === rootNode?.getLocation()) { - node = null; + for (const input of this.inputList) { + if (input.name == constants.COLLAPSED_INPUT_NAME) { + continue; } - } - - // Traverse the AST building up our text string. - while (node) { - switch (node.getType()) { - case ASTNode.types.INPUT: { - const connection = node.getLocation() as Connection; - if (!node.in()) { - tokens.push(emptyFieldPlaceholder); - } else if (shouldAddParentheses(connection)) { - tokens.push('('); - } - break; - } - case ASTNode.types.FIELD: { - const field = node.getLocation() as Field; - if (field.name !== constants.COLLAPSED_FIELD_NAME) { - tokens.push(field.getText()); - } - break; - } + for (const field of input.fieldRow) { + tokens.push(field.getText()); } - - const current = node; - node = current.in() || current.next(); - if (!node) { - // Can't go in or next, keep going out until we can go next. - node = current.out(); - checkRoot(); - while (node && !node.next()) { - node = node.out(); - checkRoot(); - // If we hit an input on the way up, possibly close out parentheses. - if (node && node.getType() === ASTNode.types.INPUT && - shouldAddParentheses(node.getLocation() as Connection)) { - tokens.push(')'); - } - } - if (node) { - node = node.next(); + if (input.connection) { + const child = input.connection.targetBlock(); + if (child) { + const shouldAddParens = shouldAddParentheses(input.connection); + if (shouldAddParens) tokens.push('('); + tokens.push(...child.toTokens(emptyToken)); + if (shouldAddParens) tokens.push(')'); + } else { + tokens.push(emptyToken); } } } - - // Restore state of NAVIGATE_ALL_FIELDS. - ASTNode.NAVIGATE_ALL_FIELDS = prevNavigateFields; - - // Run through our text array and simplify expression to remove parentheses - // around single field blocks. - // E.g. ['repeat', '(', '10', ')', 'times', 'do', '?'] - for (let i = 2; i < tokens.length; i++) { - if (tokens[i - 2] === '(' && tokens[i] === ')') { - tokens[i - 2] = tokens[i - 1]; - tokens.splice(i - 1, 2); - } - } - - // Join the text array, removing spaces around added parentheses. - let text: string = tokens.reduce(function(acc, value) { - return acc + (acc.substr(-1) === '(' || value === ')' ? '' : ' ') + value; - }, ''); - - text = text.trim() || '???'; - if (opt_maxLength) { - // TODO: Improve truncation so that text from this block is given - // priority. E.g. "1+2+3+4+5+6+7+8+9=0" should be "...6+7+8+9=0", not - // "1+2+3+4+5...". E.g. "1+2+3+4+5=6+7+8+9+0" should be "...4+5=6+7...". - if (text.length > opt_maxLength) { - text = text.substring(0, opt_maxLength - 3) + '...'; - } - } - return text; + return tokens; } /** @@ -1933,10 +1918,7 @@ export class Block implements IASTNodeLocation, IDeletable { if (type === inputTypes.STATEMENT) { this.statementInputCount++; } - // AnyDuringMigration because: Argument of type 'Connection | null' is not - // assignable to parameter of type 'Connection'. - const input = - new Input(type, name, this, (connection as AnyDuringMigration)); + const input = new Input(type, name, this, connection); // Append input to list. this.inputList.push(input); return input; @@ -2080,9 +2062,7 @@ export class Block implements IASTNodeLocation, IDeletable { eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))( this, 'comment', null, this.commentModel.text, text)); this.commentModel.text = text; - // AnyDuringMigration because: Type 'string | null' is not assignable to - // type 'string | Comment'. - this.comment = text as AnyDuringMigration; // For backwards compatibility. + this.comment = text; // For backwards compatibility. } /** diff --git a/core/block_animations.ts b/core/block_animations.ts index 47ee63581..8f72bfa65 100644 --- a/core/block_animations.ts +++ b/core/block_animations.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods animating a block on connection and disconnection. - * - * @namespace Blockly.blockAnimations - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockAnimations'); @@ -28,18 +23,20 @@ interface CloneRect { /** PID of disconnect UI animation. There can only be one at a time. */ let disconnectPid: ReturnType|null = null; -/** SVG group of wobbling block. There can only be one at a time. */ -let disconnectGroup: SVGElement|null = null; +/** The wobbling block. There can only be one at a time. */ +let wobblingBlock: BlockSvg|null = null; /** * Play some UI effects (sound, animation) when disposing of a block. * * @param block The block being disposed of. - * @alias Blockly.blockAnimations.disposeUiEffect * @internal */ export function disposeUiEffect(block: BlockSvg) { + // Disposing is going to take so long the animation won't play anyway. + if (block.getDescendants(false).length > 100) return; + const workspace = block.workspace; const svgGroup = block.getSvgRoot(); workspace.getAudioManager().play('delete'); @@ -88,7 +85,6 @@ function disposeUiStep( * Play some UI effects (sound, ripple) after a connection has been established. * * @param block The block being connected. - * @alias Blockly.blockAnimations.connectionUiEffect * @internal */ export function connectionUiEffect(block: BlockSvg) { @@ -135,8 +131,8 @@ function connectionUiStep(ripple: SVGElement, start: Date, scale: number) { if (percent > 1) { dom.removeNode(ripple); } else { - ripple.setAttribute('r', (percent * 25 * scale).toString()); - ripple.style.opacity = (1 - percent).toString(); + ripple.setAttribute('r', String(percent * 25 * scale)); + ripple.style.opacity = String(1 - percent); disconnectPid = setTimeout(connectionUiStep, 10, ripple, start, scale); } } @@ -145,7 +141,6 @@ function connectionUiStep(ripple: SVGElement, start: Date, scale: number) { * Play some UI effects (sound, animation) when disconnecting a block. * * @param block The block being disconnected. - * @alias Blockly.blockAnimations.disconnectUiEffect * @internal */ export function disconnectUiEffect(block: BlockSvg) { @@ -163,18 +158,18 @@ export function disconnectUiEffect(block: BlockSvg) { magnitude *= -1; } // Start the animation. - disconnectGroup = block.getSvgRoot(); - disconnectUiStep(disconnectGroup, magnitude, new Date()); + wobblingBlock = block; + disconnectUiStep(block, magnitude, new Date()); } /** * Animate a brief wiggle of a disconnected block. * - * @param group SVG element to animate. + * @param block Block to animate. * @param magnitude Maximum degrees skew (reversed for RTL). * @param start Date of animation's start. */ -function disconnectUiStep(group: SVGElement, magnitude: number, start: Date) { +function disconnectUiStep(block: BlockSvg, magnitude: number, start: Date) { const DURATION = 200; // Milliseconds. const WIGGLES = 3; // Half oscillations. @@ -186,29 +181,25 @@ function disconnectUiStep(group: SVGElement, magnitude: number, start: Date) { const val = Math.round( Math.sin(percent * Math.PI * WIGGLES) * (1 - percent) * magnitude); skew = `skewX(${val})`; - disconnectPid = setTimeout(disconnectUiStep, 10, group, magnitude, start); + disconnectPid = setTimeout(disconnectUiStep, 10, block, magnitude, start); } - (group as AnyDuringMigration).skew_ = skew; - group.setAttribute( - 'transform', - (group as AnyDuringMigration).translate_ + - (group as AnyDuringMigration).skew_); + + block.getSvgRoot().setAttribute( + 'transform', `${block.getTranslation()} ${skew}`); } /** * Stop the disconnect UI animation immediately. * - * @alias Blockly.blockAnimations.disconnectUiStop * @internal */ export function disconnectUiStop() { - if (disconnectGroup) { - if (disconnectPid) { - clearTimeout(disconnectPid); - } - const group = disconnectGroup; - (group as AnyDuringMigration).skew_ = ''; - group.setAttribute('transform', (group as AnyDuringMigration).translate_); - disconnectGroup = null; + if (!wobblingBlock) return; + if (disconnectPid) { + clearTimeout(disconnectPid); + disconnectPid = null; } + wobblingBlock.getSvgRoot().setAttribute( + 'transform', wobblingBlock.getTranslation()); + wobblingBlock = null; } diff --git a/core/block_dragger.ts b/core/block_dragger.ts index c977f5c53..5809f7484 100644 --- a/core/block_dragger.ts +++ b/core/block_dragger.ts @@ -34,8 +34,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a block dragger. It moves blocks around the workspace when they * are being dragged by a mouse or touch. - * - * @alias Blockly.BlockDragger */ export class BlockDragger implements IBlockDragger { /** The top block in the stack that is being dragged. */ @@ -241,7 +239,7 @@ export class BlockDragger implements IBlockDragger { // These are expensive and don't need to be done if we're deleting. this.draggingBlock_.setDragging(false); if (delta) { // !preventMove - this.updateBlockAfterMove_(delta); + this.updateBlockAfterMove_(); } else { // Blocks dragged directly from a flyout may need to be bumped into // bounds. @@ -294,18 +292,14 @@ export class BlockDragger implements IBlockDragger { /** * Updates the necessary information to place a block at a certain location. - * - * @param delta The change in location from where the block started the drag - * to where it ended the drag. */ - protected updateBlockAfterMove_(delta: Coordinate) { - this.draggingBlock_.moveConnections(delta.x, delta.y); + protected updateBlockAfterMove_() { this.fireMoveEvent_(); if (this.draggedConnectionManager_.wouldConnectBlock()) { // Applying connections also rerenders the relevant blocks. this.draggedConnectionManager_.applyConnections(); } else { - this.draggingBlock_.render(); + this.draggingBlock_.queueRender(); } this.draggingBlock_.scheduleSnapAndBump(); } diff --git a/core/block_svg.ts b/core/block_svg.ts index 02e2f0d0a..b463c64c6 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -56,13 +56,12 @@ import * as svgMath from './utils/svg_math.js'; import {Warning} from './warning.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; +import {queueRender} from './render_management.js'; /** * Class for a block's SVG representation. * Not normally called directly, workspace.newBlock() is preferred. - * - * @alias Blockly.BlockSvg */ export class BlockSvg extends Block implements IASTNodeLocationSvg, IBoundedElement, ICopyable, @@ -79,12 +78,11 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * the block. */ static readonly COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_'; - override decompose?: ((p1: Workspace) => BlockSvg); + override decompose?: (p1: Workspace) => BlockSvg; // override compose?: ((p1: BlockSvg) => void)|null; - saveConnections?: ((p1: BlockSvg) => AnyDuringMigration); + saveConnections?: (p1: BlockSvg) => void; customContextMenu?: - ((p1: Array) => - AnyDuringMigration)|null; + (p1: Array) => void; /** * An property used internally to reference the block's rendering debugger. @@ -125,6 +123,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, /** @internal */ pathObject: IPathObject; override rendered = false; + private visuallyDisabled = false; /** * Is this block currently rendering? Used to stop recursive render calls @@ -144,6 +143,24 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, override previousConnection!: RenderedConnection; private readonly useDragSurface_: boolean; + private translation = ''; + + /** + * The ID of the setTimeout callback for bumping neighbours, or 0 if no bump + * is currently scheduled. + */ + private bumpNeighboursPid = 0; + + /** + * 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 + * parent. + * + * @internal + */ + relativeCoords = new Coordinate(0, 0); + + /** * @param workspace The block's workspace. * @param prototypeName Name of the language object containing type-specific @@ -154,36 +171,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, constructor(workspace: WorkspaceSvg, prototypeName: string, opt_id?: string) { super(workspace, prototypeName, opt_id); this.workspace = workspace; - - /** - * An optional method called when a mutator dialog is first opened. - * This function must create and initialize a top-level block for the - * mutator dialog, and return it. This function should also populate this - * top-level block with any sub-blocks which are appropriate. This method - * must also be coupled with defining a `compose` method for the default - * mutation dialog button and UI to appear. - */ - this.decompose = this.decompose; - - /** - * An optional method called when a mutator dialog saves its content. - * This function is called to modify the original block according to new - * settings. This method must also be coupled with defining a `decompose` - * method for the default mutation dialog button and UI to appear. - */ - this.compose = this.compose; - - /** - * An optional method called by the default mutator UI which gives the block - * a chance to save information about what child blocks are connected to - * what mutated connections. - */ - this.saveConnections = this.saveConnections; - - /** An optional method for defining custom block context menu items. */ - this.customContextMenu = this.customContextMenu; this.svgGroup_ = dom.createSvgElement(Svg.G, {}); - (this.svgGroup_ as AnyDuringMigration).translate_ = ''; /** A block style object. */ this.style = workspace.getRenderer().getConstants().getBlockStyle(null); @@ -199,7 +187,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this.useDragSurface_ = !!workspace.getBlockDragSurface(); const svgPath = this.pathObject.svgPath; - (svgPath as AnyDuringMigration).tooltip = this; + (svgPath as any).tooltip = this; Tooltip.bindMouseEvents(svgPath); // Expose this block's ID on its top-level SVG group. @@ -348,9 +336,6 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, const oldXY = this.getRelativeToSurfaceXY(); if (newParent) { (newParent as BlockSvg).getSvgRoot().appendChild(svgRoot); - const newXY = this.getRelativeToSurfaceXY(); - // Move the connections to match the child's new position. - this.moveConnections(newXY.x - oldXY.x, newXY.y - oldXY.y); } else if (oldParent) { // If we are losing a parent, we want to move our DOM element to the // root of the workspace. @@ -435,8 +420,18 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @param y The y coordinate of the translation in workspace units. */ translate(x: number, y: number) { - this.getSvgRoot().setAttribute( - 'transform', 'translate(' + x + ',' + y + ')'); + this.translation = `translate(${x}, ${y})`; + this.relativeCoords = new Coordinate(x, y); + this.getSvgRoot().setAttribute('transform', this.getTranslation()); + } + + /** + * Returns the SVG translation of this block. + * + * @internal + */ + getTranslation(): string { + return this.translation; } /** @@ -506,13 +501,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this.workspace.getBlockDragSurface()!.translateSurface( newLoc.x, newLoc.y); } else { - (this.svgGroup_ as AnyDuringMigration).translate_ = - 'translate(' + newLoc.x + ',' + newLoc.y + ')'; - (this.svgGroup_ as AnyDuringMigration) - .setAttribute( - 'transform', - (this.svgGroup_ as AnyDuringMigration).translate_ + - (this.svgGroup_ as AnyDuringMigration).skew_); + this.translate(newLoc.x, newLoc.y); + this.getSvgRoot().setAttribute('transform', this.getTranslation()); } } @@ -598,13 +588,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, return; } super.setCollapsed(collapsed); - if (!collapsed) { - this.updateCollapsed_(); - } else if (this.rendered) { - this.render(); - // Don't bump neighbours. Users like to store collapsed functions together - // and bumping makes them go out of alignment. - } + this.updateCollapsed_(); } /** @@ -708,11 +692,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, if (this.workspace.options.readOnly || !this.contextMenu) { return null; } - // AnyDuringMigration because: Argument of type '{ block: this; }' is not - // assignable to parameter of type 'Scope'. const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( - ContextMenuRegistry.ScopeType.BLOCK, - {block: this} as AnyDuringMigration); + ContextMenuRegistry.ScopeType.BLOCK, {block: this}); // Allow the block to add or modify menuOptions. if (this.customContextMenu) { @@ -775,9 +756,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, */ setDragging(adding: boolean) { if (adding) { - const group = this.getSvgRoot(); - (group as AnyDuringMigration).translate_ = ''; - (group as AnyDuringMigration).skew_ = ''; + this.translation = ''; common.draggingConnections.push(...this.getConnections_(true)); dom.addClass(this.svgGroup_, 'blocklyDragging'); } else { @@ -862,59 +841,39 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @suppress {checkTypes} */ override dispose(healStack?: boolean, animate?: boolean) { - if (this.isDeadOrDying()) { - return; - } + if (this.isDeadOrDying()) return; + Tooltip.dispose(); - Tooltip.unbindMouseEvents(this.pathObject.svgPath); - dom.startTextWidthCache(); - // Save the block's workspace temporarily so we can resize the - // contents once the block is disposed. - const blockWorkspace = this.workspace; - // If this block is being dragged, unlink the mouse events. - if (common.getSelected() === this) { - this.unselect(); - this.workspace.cancelCurrentGesture(); - } - // If this block has a context menu open, close it. - if (ContextMenu.getCurrentBlock() === this) { - ContextMenu.hide(); - } + ContextMenu.hide(); if (animate && this.rendered) { this.unplug(healStack); blockAnimations.disposeUiEffect(this); } - // Stop rerendering. - this.rendered = false; - - // Clear pending warnings. - for (const n of this.warningTextDb.values()) { - clearTimeout(n); - } - this.warningTextDb.clear(); - - const icons = this.getIcons(); - for (let i = 0; i < icons.length; i++) { - icons[i].dispose(); - } - - // Just deleting this block from the DOM would result in a memory leak as - // well as corruption of the connection database. Therefore we must - // methodically step through the blocks and carefully disassemble them. - if (common.getSelected() === this) { - common.setSelected(null); - } super.dispose(!!healStack); - dom.removeNode(this.svgGroup_); - blockWorkspace.resizeContents(); - // Sever JavaScript to DOM connections. - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'SVGGElement'. - this.svgGroup_ = null as AnyDuringMigration; - dom.stopTextWidthCache(); + } + + /** + * Disposes of this block without doing things required by the top block. + * E.g. does trigger UI effects, remove nodes, etc. + */ + override disposeInternal() { + if (this.isDeadOrDying()) return; + super.disposeInternal(); + + this.rendered = false; + + if (common.getSelected() === this) { + this.unselect(); + this.workspace.cancelCurrentGesture(); + } + + [...this.warningTextDb.values()].forEach((n) => clearTimeout(n)); + this.warningTextDb.clear(); + + this.getIcons().forEach((i) => i.dispose()); } /** @@ -987,15 +946,12 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @internal */ updateDisabled() { - const children = (this.getChildren(false)); + const disabled = !this.isEnabled() || this.getInheritedDisabled(); + if (this.visuallyDisabled === disabled) return; this.applyColour(); - if (this.isCollapsed()) { - return; - } - for (let i = 0, child; child = children[i]; i++) { - if (child.rendered) { - child.updateDisabled(); - } + this.visuallyDisabled = disabled; + for (const child of this.getChildren(false)) { + child.updateDisabled(); } } @@ -1015,8 +971,6 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @param text The text, or null to delete. */ override setCommentText(text: string|null) { - // AnyDuringMigration because: Property 'get' does not exist on type - // '(name: string) => void'. if (this.commentModel.text === text) { return; } @@ -1291,7 +1245,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, super.setPreviousStatement(newBoolean, opt_check); if (this.rendered) { - this.render(); + this.queueRender(); this.bumpNeighbours(); } } @@ -1308,7 +1262,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, super.setNextStatement(newBoolean, opt_check); if (this.rendered) { - this.render(); + this.queueRender(); this.bumpNeighbours(); } } @@ -1324,7 +1278,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, super.setOutput(newBoolean, opt_check); if (this.rendered) { - this.render(); + this.queueRender(); this.bumpNeighbours(); } } @@ -1338,7 +1292,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, super.setInputsInline(newBoolean); if (this.rendered) { - this.render(); + this.queueRender(); this.bumpNeighbours(); } } @@ -1356,7 +1310,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, const removed = super.removeInput(name, opt_quiet); if (this.rendered) { - this.render(); + this.queueRender(); // Removing an input will cause the block to change shape. this.bumpNeighbours(); } @@ -1374,7 +1328,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, super.moveNumberedInputBefore(inputIndex, refIndex); if (this.rendered) { - this.render(); + this.queueRender(); // Moving an input will cause the block to change shape. this.bumpNeighbours(); } @@ -1392,7 +1346,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, const input = super.appendInput_(type, name); if (this.rendered) { - this.render(); + this.queueRender(); // Adding an input will cause the block to change shape. this.bumpNeighbours(); } @@ -1450,7 +1404,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * * @param all If true, return all connections even hidden ones. * Otherwise, for a non-rendered block return an empty list, and for a - * collapsed block don't return inputs connections. + * collapsed block don't return inputs connections. * @returns Array of connections. * @internal */ @@ -1542,7 +1496,16 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * up on screen, because that creates confusion for end-users. */ override bumpNeighbours() { - this.getRootBlock().bumpNeighboursInternal(); + if (this.bumpNeighboursPid) return; + const group = eventUtils.getGroup(); + + this.bumpNeighboursPid = setTimeout(() => { + const oldGroup = eventUtils.getGroup(); + eventUtils.setGroup(group); + this.getRootBlock().bumpNeighboursInternal(); + eventUtils.setGroup(oldGroup); + this.bumpNeighboursPid = 0; + }, config.bumpDelay); } /** @@ -1597,11 +1560,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, eventUtils.setGroup(false); }, config.bumpDelay / 2); - setTimeout(() => { - eventUtils.setGroup(group); - this.bumpNeighbours(); - eventUtils.setGroup(false); - }, config.bumpDelay); + this.bumpNeighbours(); } /** @@ -1650,7 +1609,17 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, } /** - * Lays out and reflows a block based on its contents and settings. + * Triggers a rerender after a delay to allow for batching. + * + * @internal + */ + queueRender() { + queueRender(this); + } + + /** + * Immediately lays out and reflows a block based on its contents and + * settings. * * @param opt_bubble If false, just render this block. * If true, also render block's parent, grandparent, etc. Defaults to true. @@ -1668,7 +1637,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this.updateCollapsed_(); } this.workspace.getRenderer().render(this); - this.updateConnectionLocations_(); + this.updateConnectionLocations(); if (opt_bubble !== false) { const parentBlock = this.getParent(); @@ -1687,6 +1656,43 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, } } + /** + * Renders this block in a way that's compatible with the more efficient + * render management system. + * + * @internal + */ + renderEfficiently() { + this.rendered = true; + dom.startTextWidthCache(); + + if (this.isCollapsed()) { + this.updateCollapsed_(); + } + this.workspace.getRenderer().render(this); + this.tightenChildrenEfficiently(); + + dom.stopTextWidthCache(); + this.updateMarkers_(); + } + + /** + * Tightens all children of this block so they are snuggly rendered against + * their parent connections. + * + * Does not update connection locations, so that they can be updated more + * efficiently by the render management system. + * + * @internal + */ + tightenChildrenEfficiently() { + for (const input of this.inputList) { + const conn = input.connection as RenderedConnection; + if (conn) conn.tightenEfficiently(); + } + if (this.nextConnection) this.nextConnection.tightenEfficiently(); + } + /** Redraw any attached marker or cursor svgs if needed. */ protected updateMarkers_() { if (this.workspace.keyboardAccessibilityMode && this.pathObject.cursorSvg) { @@ -1696,14 +1702,21 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, // TODO(#4592): Update all markers on the block. this.workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw(); } + for (const input of this.inputList) { + for (const field of input.fieldRow) { + field.updateMarkers_(); + } + } } /** * 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 updateConnectionLocations_() { + updateConnectionLocations() { const blockTL = this.getRelativeToSurfaceXY(); // Don't tighten previous or output connections because they are inferior // connections. diff --git a/core/blockly.ts b/core/blockly.ts index 0537827a9..b833924f6 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The top level namespace used to access the Blockly library. - * - * @namespace Blockly - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly'); @@ -53,19 +48,19 @@ import {DragTarget} from './drag_target.js'; import * as dropDownDiv from './dropdowndiv.js'; import * as Events from './events/events.js'; import * as Extensions from './extensions.js'; -import {Field, FieldValidator} from './field.js'; -import {FieldAngle, FieldAngleValidator} from './field_angle.js'; -import {FieldCheckbox, FieldCheckboxValidator} from './field_checkbox.js'; -import {FieldColour, FieldColourValidator} from './field_colour.js'; -import {FieldDropdown, FieldDropdownValidator, MenuGenerator, MenuGeneratorFunction, MenuOption} from './field_dropdown.js'; -import {FieldImage} from './field_image.js'; -import {FieldLabel} from './field_label.js'; +import {Field, FieldConfig, FieldValidator, UnattachedFieldError} from './field.js'; +import {FieldAngle, FieldAngleConfig, FieldAngleFromJsonConfig, FieldAngleValidator} from './field_angle.js'; +import {FieldCheckbox, FieldCheckboxConfig, FieldCheckboxFromJsonConfig, FieldCheckboxValidator} from './field_checkbox.js'; +import {FieldColour, FieldColourConfig, FieldColourFromJsonConfig, FieldColourValidator} from './field_colour.js'; +import {FieldDropdown, FieldDropdownConfig, FieldDropdownFromJsonConfig, FieldDropdownValidator, MenuGenerator, MenuGeneratorFunction, MenuOption} from './field_dropdown.js'; +import {FieldImage, FieldImageConfig, FieldImageFromJsonConfig} from './field_image.js'; +import {FieldLabel, FieldLabelConfig, FieldLabelFromJsonConfig} from './field_label.js'; import {FieldLabelSerializable} from './field_label_serializable.js'; -import {FieldMultilineInput, FieldMultilineInputValidator} from './field_multilineinput.js'; -import {FieldNumber, FieldNumberValidator} from './field_number.js'; +import {FieldMultilineInput, FieldMultilineInputConfig, FieldMultilineInputFromJsonConfig, FieldMultilineInputValidator} from './field_multilineinput.js'; +import {FieldNumber, FieldNumberConfig, FieldNumberFromJsonConfig, FieldNumberValidator} from './field_number.js'; import * as fieldRegistry from './field_registry.js'; -import {FieldTextInput, FieldTextInputValidator} from './field_textinput.js'; -import {FieldVariable, FieldVariableValidator} from './field_variable.js'; +import {FieldTextInput, FieldTextInputConfig, FieldTextInputFromJsonConfig, FieldTextInputValidator} from './field_textinput.js'; +import {FieldVariable, FieldVariableConfig, FieldVariableFromJsonConfig, FieldVariableValidator} from './field_variable.js'; import {Flyout} from './flyout_base.js'; import {FlyoutButton} from './flyout_button.js'; import {HorizontalFlyout} from './flyout_horizontal.js'; @@ -99,6 +94,7 @@ import {IFlyout} from './interfaces/i_flyout.js'; import {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js'; import {IMetricsManager} from './interfaces/i_metrics_manager.js'; import {IMovable} from './interfaces/i_movable.js'; +import {IObservable, isObservable} from './interfaces/i_observable.js'; import {IPositionable} from './interfaces/i_positionable.js'; import {IRegistrable} from './interfaces/i_registrable.js'; import {ISelectable} from './interfaces/i_selectable.js'; @@ -106,6 +102,7 @@ import {ISelectableToolboxItem} from './interfaces/i_selectable_toolbox_item.js' import {IStyleable} from './interfaces/i_styleable.js'; import {IToolbox} from './interfaces/i_toolbox.js'; import {IToolboxItem} from './interfaces/i_toolbox_item.js'; +import {IVariableBackedParameterModel, isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; import * as internalConstants from './internal_constants.js'; import {ASTNode} from './keyboard_nav/ast_node.js'; import {BasicCursor} from './keyboard_nav/basic_cursor.js'; @@ -176,7 +173,6 @@ import {ZoomControls} from './zoom_controls.js'; * compiler to override this constant. * * @define {string} - * @alias Blockly.VERSION */ export const VERSION = 'uncompiled'; @@ -194,19 +190,16 @@ export const VERSION = 'uncompiled'; /** * @see Blockly.Input.Align.LEFT - * @alias Blockly.ALIGN_LEFT */ export const ALIGN_LEFT = Align.LEFT; /** * @see Blockly.Input.Align.CENTRE - * @alias Blockly.ALIGN_CENTRE */ export const ALIGN_CENTRE = Align.CENTRE; /** * @see Blockly.Input.Align.RIGHT - * @alias Blockly.ALIGN_RIGHT */ export const ALIGN_RIGHT = Align.RIGHT; /* @@ -215,31 +208,26 @@ export const ALIGN_RIGHT = Align.RIGHT; /** * @see ConnectionType.INPUT_VALUE - * @alias Blockly.INPUT_VALUE */ export const INPUT_VALUE = ConnectionType.INPUT_VALUE; /** * @see ConnectionType.OUTPUT_VALUE - * @alias Blockly.OUTPUT_VALUE */ export const OUTPUT_VALUE = ConnectionType.OUTPUT_VALUE; /** * @see ConnectionType.NEXT_STATEMENT - * @alias Blockly.NEXT_STATEMENT */ export const NEXT_STATEMENT = ConnectionType.NEXT_STATEMENT; /** * @see ConnectionType.PREVIOUS_STATEMENT - * @alias Blockly.PREVIOUS_STATEMENT */ export const PREVIOUS_STATEMENT = ConnectionType.PREVIOUS_STATEMENT; /** * @see inputTypes.DUMMY_INPUT - * @alias Blockly.DUMMY_INPUT */ export const DUMMY_INPUT = inputTypes.DUMMY; @@ -247,25 +235,21 @@ export const DUMMY_INPUT = inputTypes.DUMMY; /** * @see toolbox.Position.TOP - * @alias Blockly.TOOLBOX_AT_TOP */ export const TOOLBOX_AT_TOP = toolbox.Position.TOP; /** * @see toolbox.Position.BOTTOM - * @alias Blockly.TOOLBOX_AT_BOTTOM */ export const TOOLBOX_AT_BOTTOM = toolbox.Position.BOTTOM; /** * @see toolbox.Position.LEFT - * @alias Blockly.TOOLBOX_AT_LEFT */ export const TOOLBOX_AT_LEFT = toolbox.Position.LEFT; /** * @see toolbox.Position.RIGHT - * @alias Blockly.TOOLBOX_AT_RIGHT */ export const TOOLBOX_AT_RIGHT = toolbox.Position.RIGHT; @@ -282,7 +266,6 @@ export const TOOLBOX_AT_RIGHT = toolbox.Position.RIGHT; * * @param workspace Any workspace in the SVG. * @see Blockly.common.svgResize - * @alias Blockly.svgResize */ export const svgResize = common.svgResize; @@ -291,7 +274,6 @@ export const svgResize = common.svgResize; * * @param opt_onlyClosePopups Whether only popups should be closed. * @see Blockly.WorkspaceSvg.hideChaff - * @alias Blockly.hideChaff */ export function hideChaff(opt_onlyClosePopups?: boolean) { (common.getMainWorkspace() as WorkspaceSvg).hideChaff(opt_onlyClosePopups); @@ -303,14 +285,11 @@ export function hideChaff(opt_onlyClosePopups?: boolean) { * Blockly instances on a page. * * @see Blockly.common.getMainWorkspace - * @alias Blockly.getMainWorkspace */ export const getMainWorkspace = common.getMainWorkspace; /** * Returns the currently selected copyable object. - * - * @alias Blockly.common.getSelected */ export const getSelected = common.getSelected; @@ -320,7 +299,6 @@ export const getSelected = common.getSelected; * * @param jsonArray An array of JSON block definitions. * @see Blockly.common.defineBlocksWithJsonArray - * @alias Blockly.defineBlocksWithJsonArray */ export const defineBlocksWithJsonArray = common.defineBlocksWithJsonArray; @@ -332,7 +310,6 @@ export const defineBlocksWithJsonArray = common.defineBlocksWithJsonArray; * * @param container The container element. * @see Blockly.common.setParentContainer - * @alias Blockly.setParentContainer */ export const setParentContainer = common.setParentContainer; @@ -343,7 +320,6 @@ export const setParentContainer = common.setParentContainer; * @param workspace The workspace to resize. * @deprecated Use **workspace.resizeContents** instead. * @see Blockly.WorkspaceSvg.resizeContents - * @alias Blockly.resizeSvgContents */ function resizeSvgContentsLocal(workspace: WorkspaceSvg) { deprecation.warn( @@ -359,7 +335,6 @@ export const resizeSvgContents = resizeSvgContentsLocal; * @param toCopy Block or Workspace Comment to be copied. * @deprecated Use **Blockly.clipboard.copy** instead. * @see Blockly.clipboard.copy - * @alias Blockly.copy */ export function copy(toCopy: ICopyable) { deprecation.warn( @@ -374,7 +349,6 @@ export function copy(toCopy: ICopyable) { * @returns True if the paste was successful, false otherwise. * @deprecated Use **Blockly.clipboard.paste** instead. * @see Blockly.clipboard.paste - * @alias Blockly.paste */ export function paste(): boolean { deprecation.warn( @@ -389,7 +363,6 @@ export function paste(): boolean { * @param toDuplicate Block or Workspace Comment to be copied. * @deprecated Use **Blockly.clipboard.duplicate** instead. * @see Blockly.clipboard.duplicate - * @alias Blockly.duplicate */ export function duplicate(toDuplicate: ICopyable) { deprecation.warn( @@ -405,7 +378,6 @@ export function duplicate(toDuplicate: ICopyable) { * @returns True if number, false otherwise. * @deprecated Use **Blockly.utils.string.isNumber** instead. * @see Blockly.utils.string.isNumber - * @alias Blockly.isNumber */ export function isNumber(str: string): boolean { deprecation.warn( @@ -421,7 +393,6 @@ export function isNumber(str: string): boolean { * @returns RGB code, e.g. '#5ba65b'. * @deprecated Use **Blockly.utils.colour.hueToHex** instead. * @see Blockly.utils.colour.hueToHex - * @alias Blockly.hueToHex */ export function hueToHex(hue: number): string { deprecation.warn( @@ -443,7 +414,6 @@ export function hueToHex(hue: number): string { * @returns Opaque data that can be passed to unbindEvent_. * @deprecated Use **Blockly.browserEvents.bind** instead. * @see Blockly.browserEvents.bind - * @alias Blockly.bindEvent_ */ export function bindEvent_( node: EventTarget, name: string, thisObject: Object|null, @@ -462,7 +432,6 @@ export function bindEvent_( * @returns The function call. * @deprecated Use **Blockly.browserEvents.unbind** instead. * @see browserEvents.unbind - * @alias Blockly.unbindEvent_ */ export function unbindEvent_(bindData: browserEvents.Data): Function { deprecation.warn( @@ -488,7 +457,6 @@ export function unbindEvent_(bindData: browserEvents.Data): Function { * @returns Opaque data that can be passed to unbindEvent_. * @deprecated Use **Blockly.browserEvents.conditionalBind** instead. * @see browserEvents.conditionalBind - * @alias Blockly.bindEventWithChecks_ */ export function bindEventWithChecks_( node: EventTarget, name: string, thisObject: Object|null, func: Function, @@ -514,8 +482,6 @@ export const COLLAPSED_FIELD_NAME = constants.COLLAPSED_FIELD_NAME; * String for use in the "custom" attribute of a category in toolbox XML. * This string indicates that the category should be dynamically populated with * variable blocks. - * - * @alias Blockly.VARIABLE_CATEGORY_NAME */ export const VARIABLE_CATEGORY_NAME: string = Variables.CATEGORY_NAME; @@ -523,8 +489,6 @@ export const VARIABLE_CATEGORY_NAME: string = Variables.CATEGORY_NAME; * String for use in the "custom" attribute of a category in toolbox XML. * This string indicates that the category should be dynamically populated with * variable blocks. - * - * @alias Blockly.VARIABLE_DYNAMIC_CATEGORY_NAME */ export const VARIABLE_DYNAMIC_CATEGORY_NAME: string = VariablesDynamic.CATEGORY_NAME; @@ -532,8 +496,6 @@ export const VARIABLE_DYNAMIC_CATEGORY_NAME: string = * String for use in the "custom" attribute of a category in toolbox XML. * This string indicates that the category should be dynamically populated with * procedure blocks. - * - * @alias Blockly.PROCEDURE_CATEGORY_NAME */ export const PROCEDURE_CATEGORY_NAME: string = Procedures.CATEGORY_NAME; @@ -643,24 +605,61 @@ export {Cursor}; export {DeleteArea}; export {DragTarget}; export const DropDownDiv = dropDownDiv; -export {Field, FieldValidator}; -export {FieldAngle, FieldAngleValidator}; -export {FieldCheckbox, FieldCheckboxValidator}; -export {FieldColour, FieldColourValidator}; +export {Field, FieldConfig, FieldValidator, UnattachedFieldError}; +export { + FieldAngle, + FieldAngleConfig, + FieldAngleFromJsonConfig, + FieldAngleValidator, +}; +export { + FieldCheckbox, + FieldCheckboxConfig, + FieldCheckboxFromJsonConfig, + FieldCheckboxValidator, +}; +export { + FieldColour, + FieldColourConfig, + FieldColourFromJsonConfig, + FieldColourValidator, +}; export { FieldDropdown, + FieldDropdownConfig, + FieldDropdownFromJsonConfig, FieldDropdownValidator, MenuGenerator, MenuGeneratorFunction, MenuOption, }; -export {FieldImage}; -export {FieldLabel}; +export {FieldImage, FieldImageConfig, FieldImageFromJsonConfig}; +export {FieldLabel, FieldLabelConfig, FieldLabelFromJsonConfig}; export {FieldLabelSerializable}; -export {FieldMultilineInput, FieldMultilineInputValidator}; -export {FieldNumber, FieldNumberValidator}; -export {FieldTextInput, FieldTextInputValidator}; -export {FieldVariable, FieldVariableValidator}; +export { + FieldMultilineInput, + FieldMultilineInputConfig, + FieldMultilineInputFromJsonConfig, + FieldMultilineInputValidator, +}; +export { + FieldNumber, + FieldNumberConfig, + FieldNumberFromJsonConfig, + FieldNumberValidator, +}; +export { + FieldTextInput, + FieldTextInputConfig, + FieldTextInputFromJsonConfig, + FieldTextInputValidator, +}; +export { + FieldVariable, + FieldVariableConfig, + FieldVariableFromJsonConfig, + FieldVariableValidator, +}; export {Flyout}; export {FlyoutButton}; export {FlyoutMetricsManager}; @@ -693,6 +692,7 @@ export {IMetricsManager}; export {IMovable}; export {Input}; export {InsertionMarkerManager}; +export {IObservable, isObservable}; export {IPositionable}; export {IRegistrable}; export {ISelectable}; @@ -700,6 +700,7 @@ export {ISelectableToolboxItem}; export {IStyleable}; export {IToolbox}; export {IToolboxItem}; +export {IVariableBackedParameterModel, isVariableBackedParameterModel}; export {Marker}; export {MarkerManager}; export {Menu}; diff --git a/core/blockly_options.ts b/core/blockly_options.ts index 8933bd637..deabe1f96 100644 --- a/core/blockly_options.ts +++ b/core/blockly_options.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object that defines user-specified options for the workspace. - * - * @namespace Blockly.BlocklyOptions - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.BlocklyOptions'); @@ -19,8 +14,6 @@ import type {ToolboxDefinition} from './utils/toolbox.js'; /** * Blockly options. - * - * @alias Blockly.BlocklyOptions */ export interface BlocklyOptions { collapse?: boolean; diff --git a/core/blocks.ts b/core/blocks.ts index cb3348c74..0b381fa89 100644 --- a/core/blocks.ts +++ b/core/blocks.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * A mapping of block type names to block prototype objects. - * - * @namespace Blockly.blocks - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.blocks'); @@ -21,7 +16,5 @@ export type BlockDefinition = AnyDuringMigration; /** * A mapping of block type names to block prototype objects. - * - * @alias Blockly.blocks.Blocks */ export const Blocks: {[key: string]: BlockDefinition} = Object.create(null); diff --git a/core/browser_events.ts b/core/browser_events.ts index a36c7e537..6723aa7e5 100644 --- a/core/browser_events.ts +++ b/core/browser_events.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Browser event handling. - * - * @namespace Blockly.browserEvents - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.browserEvents'); @@ -20,8 +15,6 @@ import * as userAgent from './utils/useragent.js'; /** * Blockly opaque event data used to unbind events when using * `bind` and `conditionalBind`. - * - * @alias Blockly.browserEvents.Data */ export type Data = [EventTarget, string, (e: Event) => void][]; @@ -54,7 +47,6 @@ const PAGE_MODE_MULTIPLIER = 125; * simultaneous touches. False by default. * @param opt_noPreventDefault No-op, deprecated and will be removed in v10. * @returns Opaque data that can be passed to unbindEvent_. - * @alias Blockly.browserEvents.conditionalBind */ export function conditionalBind( node: EventTarget, name: string, thisObject: Object|null, func: Function, @@ -105,7 +97,6 @@ export function conditionalBind( * @param thisObject The value of 'this' in the function. * @param func Function to call when event is triggered. * @returns Opaque data that can be passed to unbindEvent_. - * @alias Blockly.browserEvents.bind */ export function bind( node: EventTarget, name: string, thisObject: Object|null, @@ -142,7 +133,6 @@ export function bind( * @param bindData Opaque data from bindEvent_. * This list is emptied during the course of calling this function. * @returns The function call. - * @alias Blockly.browserEvents.unbind */ export function unbind(bindData: Data): (e: Event) => void { // Accessing an element of the last property of the array is unsafe if the @@ -150,10 +140,7 @@ export function unbind(bindData: Data): (e: Event) => void { // should only pass Data from bind or conditionalBind. const callback = bindData[bindData.length - 1][2]; while (bindData.length) { - const bindDatum = bindData.pop(); - const node = bindDatum![0]; - const name = bindDatum![1]; - const func = bindDatum![2]; + const [node, name, func] = bindData.pop()!; node.removeEventListener(name, func, false); } return callback; @@ -164,7 +151,6 @@ export function unbind(bindData: Data): (e: Event) => void { * * @param e An event. * @returns True if text input. - * @alias Blockly.browserEvents.isTargetInput */ export function isTargetInput(e: Event): boolean { if (e.target instanceof HTMLElement) { @@ -194,7 +180,6 @@ export function isTargetInput(e: Event): boolean { * * @param e Mouse event. * @returns True if right-click. - * @alias Blockly.browserEvents.isRightButton */ export function isRightButton(e: MouseEvent): boolean { if (e.ctrlKey && userAgent.MAC) { @@ -213,7 +198,6 @@ export function isRightButton(e: MouseEvent): boolean { * @param svg SVG element. * @param matrix Inverted screen CTM to use. * @returns Object with .x and .y properties. - * @alias Blockly.browserEvents.mouseToSvg */ export function mouseToSvg( e: MouseEvent, svg: SVGSVGElement, matrix: SVGMatrix|null): SVGPoint { @@ -232,7 +216,6 @@ export function mouseToSvg( * * @param e Mouse event. * @returns Scroll delta object with .x and .y properties. - * @alias Blockly.browserEvents.getScrollDeltaPixels */ export function getScrollDeltaPixels(e: WheelEvent): {x: number, y: number} { switch (e.deltaMode) { diff --git a/core/bubble.ts b/core/bubble.ts index 054043c2e..c8fa2b0f3 100644 --- a/core/bubble.ts +++ b/core/bubble.ts @@ -30,8 +30,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for UI bubble. - * - * @alias Blockly.Bubble */ export class Bubble implements IBubble { /** Width of the border around the bubble. */ @@ -220,27 +218,26 @@ export class Bubble implements IBubble { 'blocklyResizeSE', }, this.bubbleGroup); - const resizeSize = 2 * Bubble.BORDER_WIDTH; + const size = 2 * Bubble.BORDER_WIDTH; dom.createSvgElement( - Svg.POLYGON, - {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, + Svg.POLYGON, {'points': `0,${size} ${size},${size} ${size},0`}, this.resizeGroup); dom.createSvgElement( Svg.LINE, { 'class': 'blocklyResizeLine', - 'x1': resizeSize / 3, - 'y1': resizeSize - 1, - 'x2': resizeSize - 1, - 'y2': resizeSize / 3, + 'x1': size / 3, + 'y1': size - 1, + 'x2': size - 1, + 'y2': size / 3, }, this.resizeGroup); dom.createSvgElement( Svg.LINE, { 'class': 'blocklyResizeLine', - 'x1': resizeSize * 2 / 3, - 'y1': resizeSize - 1, - 'x2': resizeSize - 1, - 'y2': resizeSize * 2 / 3, + 'x1': size * 2 / 3, + 'y1': size - 1, + 'x2': size - 1, + 'y2': size * 2 / 3, }, this.resizeGroup); } else { @@ -662,8 +659,8 @@ export class Bubble implements IBubble { height = Math.max(height, doubleBorderWidth + 20); this.width = width; this.height = height; - this.bubbleBack?.setAttribute('width', width.toString()); - this.bubbleBack?.setAttribute('height', height.toString()); + this.bubbleBack?.setAttribute('width', `${width}`); + this.bubbleBack?.setAttribute('height', `${height}`); if (this.resizeGroup) { if (this.workspace_.RTL) { // Mirror the resize group. @@ -903,8 +900,7 @@ export class Bubble implements IBubble { textElement = paragraphElement.childNodes[i] as SVGTSpanElement; i++) { textElement.setAttribute('text-anchor', 'end'); - textElement.setAttribute( - 'x', (maxWidth + Bubble.BORDER_WIDTH).toString()); + textElement.setAttribute('x', String(maxWidth + Bubble.BORDER_WIDTH)); } } return bubble; diff --git a/core/bubble_dragger.ts b/core/bubble_dragger.ts index edd67655b..f960e399f 100644 --- a/core/bubble_dragger.ts +++ b/core/bubble_dragger.ts @@ -28,8 +28,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * Class for a bubble dragger. It moves things on the bubble canvas around the * workspace when they are being dragged by a mouse or touch. These can be * block comments, mutators, warnings, or workspace comments. - * - * @alias Blockly.BubbleDragger */ export class BubbleDragger { /** Which drag target the mouse pointer is over, if any. */ diff --git a/core/bump_objects.ts b/core/bump_objects.ts index cd2c754a4..7396b7a0e 100644 --- a/core/bump_objects.ts +++ b/core/bump_objects.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utilities for bumping objects back into worksapce bounds. - * - * @namespace Blockly.bumpObjects - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.bumpObjects'); @@ -35,7 +30,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * in workspace coordinates. * @param object The object to bump. * @returns True if block was bumped. - * @alias Blockly.bumpObjects.bumpIntoBounds */ function bumpObjectIntoBounds( workspace: WorkspaceSvg, scrollMetrics: ContainerRegion, @@ -87,7 +81,6 @@ export const bumpIntoBounds = bumpObjectIntoBounds; * * @param workspace The workspace to handle. * @returns The event handler. - * @alias Blockly.bumpObjects.bumpIntoBoundsHandler */ export function bumpIntoBoundsHandler(workspace: WorkspaceSvg): (p1: Abstract) => void { @@ -107,7 +100,7 @@ export function bumpIntoBoundsHandler(workspace: WorkspaceSvg): return; } // Handle undo. - const oldGroup = eventUtils.getGroup(); + const existingGroup = eventUtils.getGroup() || false; eventUtils.setGroup(e.group); const wasBumped = bumpObjectIntoBounds( @@ -118,9 +111,7 @@ export function bumpIntoBoundsHandler(workspace: WorkspaceSvg): 'Moved object in bounds but there was no' + ' event group. This may break undo.'); } - if (oldGroup !== null) { - eventUtils.setGroup(oldGroup); - } + eventUtils.setGroup(existingGroup); } else if (e.type === eventUtils.VIEWPORT_CHANGE) { const viewportEvent = (e as ViewportChange); if (viewportEvent.scale && viewportEvent.oldScale && @@ -167,7 +158,6 @@ function extractObjectFromEvent( * Bumps the top objects in the given workspace into bounds. * * @param workspace The workspace. - * @alias Blockly.bumpObjects.bumpTopObjectsIntoBounds */ export function bumpTopObjectsIntoBounds(workspace: WorkspaceSvg) { const metricsManager = workspace.getMetricsManager(); diff --git a/core/clipboard.ts b/core/clipboard.ts index 4b3bcbb6f..6b402a5e9 100644 --- a/core/clipboard.ts +++ b/core/clipboard.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Blockly's internal clipboard for managing copy-paste. - * - * @namespace Blockly.clipboard - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.clipboard'); @@ -22,7 +17,6 @@ let copyData: CopyData|null = null; * Copy a block or workspace comment onto the local clipboard. * * @param toCopy Block or Workspace Comment to be copied. - * @alias Blockly.clipboard.copy * @internal */ export function copy(toCopy: ICopyable) { @@ -40,7 +34,6 @@ function copyInternal(toCopy: ICopyable) { * Paste a block or workspace comment on to the main workspace. * * @returns The pasted thing if the paste was successful, null otherwise. - * @alias Blockly.clipboard.paste * @internal */ export function paste(): ICopyable|null { @@ -66,7 +59,6 @@ export function paste(): ICopyable|null { * @param toDuplicate Block or Workspace Comment to be duplicated. * @returns The block or workspace comment that was duplicated, or null if the * duplication failed. - * @alias Blockly.clipboard.duplicate * @internal */ export function duplicate(toDuplicate: ICopyable): ICopyable|null { diff --git a/core/comment.ts b/core/comment.ts index d716aa2f0..b60d7547e 100644 --- a/core/comment.ts +++ b/core/comment.ts @@ -32,8 +32,6 @@ import {Svg} from './utils/svg.js'; /** * Class for a comment. - * - * @alias Blockly.Comment */ export class Comment extends Icon { private readonly model: CommentModel; @@ -44,17 +42,12 @@ export class Comment extends Icon { */ private cachedText: string|null = ''; - /** Mouse up event data. */ - private onMouseUpWrapper: browserEvents.Data|null = null; - - /** Wheel event data. */ - private onWheelWrapper: browserEvents.Data|null = null; - - /** Change event data. */ - private onChangeWrapper: browserEvents.Data|null = null; - - /** Input event data. */ - private onInputWrapper: browserEvents.Data|null = null; + /** + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. + */ + private boundEvents: browserEvents.Data[] = []; /** * The SVG element that contains the text edit area, or null if not created. @@ -149,14 +142,14 @@ export class Comment extends Icon { body.appendChild(textarea); this.foreignObject!.appendChild(body); - this.onMouseUpWrapper = browserEvents.conditionalBind( - textarea, 'focus', this, this.startEdit, true); + this.boundEvents.push(browserEvents.conditionalBind( + textarea, 'focus', this, this.startEdit, true)); // Don't zoom with mousewheel. - this.onWheelWrapper = browserEvents.conditionalBind( + this.boundEvents.push(browserEvents.conditionalBind( textarea, 'wheel', this, function(e: Event) { e.stopPropagation(); - }); - this.onChangeWrapper = browserEvents.conditionalBind( + })); + this.boundEvents.push(browserEvents.conditionalBind( textarea, 'change', this, /** * @param _e Unused event parameter. @@ -167,15 +160,15 @@ export class Comment extends Icon { this.getBlock(), 'comment', null, this.cachedText, this.model.text)); } - }); - this.onInputWrapper = browserEvents.conditionalBind( + })); + this.boundEvents.push(browserEvents.conditionalBind( textarea, 'input', this, /** * @param _e Unused event parameter. */ function(this: Comment, _e: Event) { this.model.text = textarea.value; - }); + })); setTimeout(textarea.focus.bind(textarea), 0); @@ -279,22 +272,10 @@ export class Comment extends Icon { * Dispose of the bubble. */ private disposeBubble() { - if (this.onMouseUpWrapper) { - browserEvents.unbind(this.onMouseUpWrapper); - this.onMouseUpWrapper = null; - } - if (this.onWheelWrapper) { - browserEvents.unbind(this.onWheelWrapper); - this.onWheelWrapper = null; - } - if (this.onChangeWrapper) { - browserEvents.unbind(this.onChangeWrapper); - this.onChangeWrapper = null; - } - if (this.onInputWrapper) { - browserEvents.unbind(this.onInputWrapper); - this.onInputWrapper = null; + for (const event of this.boundEvents) { + browserEvents.unbind(event); } + this.boundEvents.length = 0; if (this.bubble_) { this.bubble_.dispose(); this.bubble_ = null; diff --git a/core/common.ts b/core/common.ts index 3181e88e7..b50eb7b68 100644 --- a/core/common.ts +++ b/core/common.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Common functions used both internally and externally, but which - * must not be at the top level to avoid circular dependencies. - * - * @namespace Blockly.common - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.common'); @@ -79,7 +73,6 @@ let mainWorkspace: Workspace; * page. * * @returns The main workspace. - * @alias Blockly.common.getMainWorkspace */ export function getMainWorkspace(): Workspace { return mainWorkspace; @@ -89,7 +82,6 @@ export function getMainWorkspace(): Workspace { * Sets last used main workspace. * * @param workspace The most recently used top level workspace. - * @alias Blockly.common.setMainWorkspace */ export function setMainWorkspace(workspace: Workspace) { mainWorkspace = workspace; @@ -102,8 +94,6 @@ let selected: ICopyable|null = null; /** * Returns the currently selected copyable object. - * - * @alias Blockly.common.getSelected */ export function getSelected(): ICopyable|null { return selected; @@ -115,7 +105,6 @@ export function getSelected(): ICopyable|null { * programmatically select a block, use `BlockSvg#select`. * * @param newSelection The newly selected block. - * @alias Blockly.common.setSelected * @internal */ export function setSelected(newSelection: ICopyable|null) { @@ -132,7 +121,6 @@ let parentContainer: Element|null; * Tooltip. * * @returns The parent container. - * @alias Blockly.common.getParentContainer */ export function getParentContainer(): Element|null { return parentContainer; @@ -145,7 +133,6 @@ export function getParentContainer(): Element|null { * This method is a NOP if called after the first `Blockly.inject`. * * @param newParent The container element. - * @alias Blockly.common.setParentContainer */ export function setParentContainer(newParent: Element) { parentContainer = newParent; @@ -159,7 +146,6 @@ export function setParentContainer(newParent: Element) { * Record the height/width of the SVG image. * * @param workspace Any workspace in the SVG. - * @alias Blockly.common.svgResize */ export function svgResize(workspace: WorkspaceSvg) { let mainWorkspace = workspace; @@ -201,7 +187,6 @@ export const draggingConnections: Connection[] = []; * statements (blocks that are not inside a value or statement input * of the block). * @returns Map of types to type counts for descendants of the bock. - * @alias Blockly.common.getBlockTypeCounts */ export function getBlockTypeCounts( block: Block, opt_stripFollowing?: boolean): {[key: string]: number} { @@ -243,7 +228,6 @@ function jsonInitFactory(jsonDef: AnyDuringMigration): () => void { * by the Blockly Developer Tools. * * @param jsonArray An array of JSON block definitions. - * @alias Blockly.common.defineBlocksWithJsonArray */ export function defineBlocksWithJsonArray(jsonArray: AnyDuringMigration[]) { TEST_ONLY.defineBlocksWithJsonArrayInternal(jsonArray); @@ -263,7 +247,6 @@ function defineBlocksWithJsonArrayInternal(jsonArray: AnyDuringMigration[]) { * @param jsonArray An array of JSON block definitions. * @returns A map of the block * definitions created. - * @alias Blockly.common.defineBlocksWithJsonArray */ export function createBlockDefinitionsFromJsonArray( jsonArray: AnyDuringMigration[]): {[key: string]: BlockDefinition} { @@ -292,7 +275,6 @@ export function createBlockDefinitionsFromJsonArray( * * @param blocks A map of block * type names to block definitions. - * @alias Blockly.common.defineBlocks */ export function defineBlocks(blocks: {[key: string]: BlockDefinition}) { // Iterate over own enumerable properties. diff --git a/core/component_manager.ts b/core/component_manager.ts index 7ba9986e4..6b014baa4 100644 --- a/core/component_manager.ts +++ b/core/component_manager.ts @@ -43,8 +43,6 @@ class Capability<_T> { /** * Manager for all items registered with the workspace. - * - * @alias Blockly.ComponentManager */ export class ComponentManager { static Capability = Capability; @@ -120,7 +118,7 @@ export class ComponentManager { 'Plugin "' + id + 'already has capability "' + capability + '"'); return; } - capability = String(capability).toLowerCase(); + capability = `${capability}`.toLowerCase(); this.componentData.get(id)?.capabilities.push(capability); this.capabilityToComponentIds.get(capability)?.push(id); } @@ -143,7 +141,7 @@ export class ComponentManager { '" to remove'); return; } - capability = String(capability).toLowerCase(); + capability = `${capability}`.toLowerCase(); arrayUtils.removeElem(this.componentData.get(id)!.capabilities, capability); arrayUtils.removeElem(this.capabilityToComponentIds.get(capability)!, id); } @@ -156,7 +154,7 @@ export class ComponentManager { * @returns Whether the component has the capability. */ hasCapability(id: string, capability: string|Capability): boolean { - capability = String(capability).toLowerCase(); + capability = `${capability}`.toLowerCase(); return this.componentData.has(id) && this.componentData.get(id)!.capabilities.indexOf(capability) !== -1; } @@ -180,7 +178,7 @@ export class ComponentManager { */ getComponents( capability: string|Capability, sorted: boolean): T[] { - capability = String(capability).toLowerCase(); + capability = `${capability}`.toLowerCase(); const componentIds = this.capabilityToComponentIds.get(capability); if (!componentIds) { return []; diff --git a/core/config.ts b/core/config.ts index aa8bc9f5e..549a6aaf7 100644 --- a/core/config.ts +++ b/core/config.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * All the values that we expect developers to be able to change - * before injecting Blockly. Changing these values during run time is not - * generally recommended. - * - * @namespace Blockly.config - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.config'); @@ -39,7 +32,6 @@ export const config: Config = { /** * Number of pixels the mouse must move before a drag starts. * - * @alias Blockly.config.dragRadius */ dragRadius: 5, /** @@ -47,20 +39,17 @@ export const config: Config = { * flyout. Because the drag-intention is determined when this is reached, it * is larger than dragRadius so that the drag-direction is clearer. * - * @alias Blockly.config.flyoutDragRadius */ flyoutDragRadius: 10, /** * Maximum misalignment between connections for them to snap together. * - * @alias Blockly.config.snapRadius */ snapRadius: DEFAULT_SNAP_RADIUS, /** * Maximum misalignment between connections for them to snap together. * This should be the same as the snap radius. * - * @alias Blockly.config.connectingSnapRadius */ connectingSnapRadius: DEFAULT_SNAP_RADIUS, /** @@ -69,13 +58,11 @@ export const config: Config = { * this much closer to the matching connection on the block than it actually * is. * - * @alias Blockly.config.currentConnectionPreference */ currentConnectionPreference: 8, /** * Delay in ms between trigger and bumping unconnected block out of alignment. * - * @alias Blockly.config.bumpDelay */ bumpDelay: 250, }; diff --git a/core/connection.ts b/core/connection.ts index e495df85d..ee7ab8b99 100644 --- a/core/connection.ts +++ b/core/connection.ts @@ -25,8 +25,6 @@ import * as Xml from './xml.js'; /** * Class for a connection between blocks. - * - * @alias Blockly.Connection */ export class Connection implements IASTNodeLocationWithBlock { /** Constants for checking whether two connections are compatible. */ @@ -95,7 +93,7 @@ export class Connection implements IASTNodeLocationWithBlock { // Make sure the childConnection is available. if (childConnection.isConnected()) { - childConnection.disconnect(); + childConnection.disconnectInternal(false); } // Make sure the parentConnection is available. @@ -106,7 +104,7 @@ export class Connection implements IASTNodeLocationWithBlock { if (target!.isShadow()) { target!.dispose(false); } else { - this.disconnect(); + this.disconnectInternal(); orphan = target; } this.applyShadowState_(shadowState); @@ -129,8 +127,9 @@ export class Connection implements IASTNodeLocationWithBlock { if (orphan) { const orphanConnection = this.type === INPUT ? orphan.outputConnection : orphan.previousConnection; + if (!orphanConnection) return; const connection = Connection.getConnectionForOrphanedConnection( - childBlock, (orphanConnection)); + childBlock, orphanConnection); if (connection) { orphanConnection.connect(connection); } else { @@ -151,7 +150,7 @@ export class Connection implements IASTNodeLocationWithBlock { this.setShadowStateInternal_(); const targetBlock = this.targetBlock(); - if (targetBlock) { + if (targetBlock && !targetBlock.isDeadOrDying()) { // Disconnect the attached normal block. targetBlock.unplug(); } @@ -224,8 +223,8 @@ export class Connection implements IASTNodeLocationWithBlock { const checker = this.getConnectionChecker(); if (checker.canConnect(this, otherConnection, false)) { - const eventGroup = eventUtils.getGroup(); - if (!eventGroup) { + const existingGroup = eventUtils.getGroup(); + if (!existingGroup) { eventUtils.setGroup(true); } // Determine which block is superior (higher in the source stack). @@ -236,75 +235,83 @@ export class Connection implements IASTNodeLocationWithBlock { // Inferior block. otherConnection.connect_(this); } - if (!eventGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); } return this.isConnected(); } - /** Disconnect this connection. */ + /** + * Disconnect this connection. + */ disconnect() { - const otherConnection = this.targetConnection; - if (!otherConnection) { - throw Error('Source connection not connected.'); - } - if (otherConnection.targetConnection !== this) { - throw Error('Target connection not connected to source connection.'); - } - let parentBlock; - let childBlock; - let parentConnection; - if (this.isSuperior()) { - // Superior block. - parentBlock = this.sourceBlock_; - childBlock = otherConnection.getSourceBlock(); - /* eslint-disable-next-line @typescript-eslint/no-this-alias */ - parentConnection = this; - } else { - // Inferior block. - parentBlock = otherConnection.getSourceBlock(); - childBlock = this.sourceBlock_; - parentConnection = otherConnection; - } - - const eventGroup = eventUtils.getGroup(); - if (!eventGroup) { - eventUtils.setGroup(true); - } - this.disconnectInternal_(parentBlock, childBlock); - if (!childBlock.isShadow()) { - // If we were disconnecting a shadow, no need to spawn a new one. - parentConnection.respawnShadow_(); - } - if (!eventGroup) { - eventUtils.setGroup(false); - } + this.disconnectInternal(); } /** * Disconnect two blocks that are connected by this connection. * - * @param parentBlock The superior block. - * @param childBlock The inferior block. + * @param setParent Whether to set the parent of the disconnected block or + * not, defaults to true. + * If you do not set the parent, ensure that a subsequent action does, + * otherwise the view and model will be out of sync. */ - protected disconnectInternal_(parentBlock: Block, childBlock: Block) { + protected disconnectInternal(setParent = true) { + const {parentConnection, childConnection} = + this.getParentAndChildConnections(); + if (!parentConnection || !childConnection) { + throw Error('Source connection not connected.'); + } + + const existingGroup = eventUtils.getGroup(); + if (!existingGroup) { + eventUtils.setGroup(true); + } + let event; if (eventUtils.isEnabled()) { - event = - new (eventUtils.get(eventUtils.BLOCK_MOVE))(childBlock) as BlockMove; + event = new (eventUtils.get(eventUtils.BLOCK_MOVE))( + childConnection.getSourceBlock()) as BlockMove; } const otherConnection = this.targetConnection; if (otherConnection) { otherConnection.targetConnection = null; } this.targetConnection = null; - childBlock.setParent(null); + if (setParent) childConnection.getSourceBlock().setParent(null); if (event) { event.recordNew(); eventUtils.fire(event); } + + if (!childConnection.getSourceBlock().isShadow()) { + // If we were disconnecting a shadow, no need to spawn a new one. + parentConnection.respawnShadow_(); + } + + eventUtils.setGroup(existingGroup); + } + + /** + * Returns the parent connection (superior) and child connection (inferior) + * given this connection and the connection it is connected to. + * + * @returns The parent connection and child connection, given this connection + * and the connection it is connected to. + */ + protected getParentAndChildConnections(): + {parentConnection?: Connection, childConnection?: Connection} { + if (!this.targetConnection) return {}; + if (this.isSuperior()) { + return { + parentConnection: this, + childConnection: this.targetConnection, + }; + } + return { + parentConnection: this.targetConnection, + childConnection: this, + }; } /** @@ -545,6 +552,7 @@ export class Connection implements IASTNodeLocationWithBlock { } } else if (target.isShadow()) { target.dispose(false); + if (this.getSourceBlock().isDeadOrDying()) return; this.respawnShadow_(); if (this.targetBlock() && this.targetBlock()!.isShadow()) { this.serializeShadow_(this.targetBlock()); @@ -678,11 +686,11 @@ function getSingleConnection(block: Block, orphanBlock: Block): Connection| null { let foundConnection = null; const output = orphanBlock.outputConnection; - const typeChecker = output.getConnectionChecker(); + const typeChecker = output?.getConnectionChecker(); for (let i = 0, input; input = block.inputList[i]; i++) { const connection = input.connection; - if (connection && typeChecker.canConnect(output, connection, false)) { + if (connection && typeChecker?.canConnect(output, connection, false)) { if (foundConnection) { return null; // More than one connection. } diff --git a/core/connection_checker.ts b/core/connection_checker.ts index ccb54f539..599da547f 100644 --- a/core/connection_checker.ts +++ b/core/connection_checker.ts @@ -24,8 +24,6 @@ import type {RenderedConnection} from './rendered_connection.js'; /** * Class for connection type checking logic. - * - * @alias Blockly.ConnectionChecker */ export class ConnectionChecker implements IConnectionChecker { /** @@ -203,7 +201,7 @@ export class ConnectionChecker implements IConnectionChecker { /** * Check whether this connection can be made by dragging. * - * @param a Connection to compare. + * @param a Connection to compare (on the block that's being dragged). * @param b Connection to compare against. * @param distance The maximum allowable distance between connections. * @returns True if the connection is allowed during a drag. @@ -250,6 +248,12 @@ export class ConnectionChecker implements IConnectionChecker { !b.targetBlock()!.isShadow() && b.targetBlock()!.nextConnection) { return false; } + + // Don't offer to splice into a stack where the connected block is + // immovable. + if (b.targetBlock() && !b.targetBlock()!.isMovable()) { + return false; + } break; } default: diff --git a/core/connection_db.ts b/core/connection_db.ts index e2a2da999..9320d9f28 100644 --- a/core/connection_db.ts +++ b/core/connection_db.ts @@ -24,8 +24,6 @@ import type {Coordinate} from './utils/coordinate.js'; * Database of connections. * Connections are stored in order of their vertical component. This way * connections in an area may be looked up quickly using a binary search. - * - * @alias Blockly.ConnectionDB */ export class ConnectionDB { /** Array of connections sorted by y position in workspace units. */ diff --git a/core/connection_type.ts b/core/connection_type.ts index 4e2d123f9..5fe77b12b 100644 --- a/core/connection_type.ts +++ b/core/connection_type.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An enum for the possible types of connections. - * - * @namespace Blockly.ConnectionType - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.ConnectionType'); /** * Enum for the type of a connection or input. - * - * @alias Blockly.ConnectionType */ export enum ConnectionType { // A right-facing value input. E.g. 'set item to' or 'return'. diff --git a/core/constants.ts b/core/constants.ts index 68e807a21..ace571ff1 100644 --- a/core/constants.ts +++ b/core/constants.ts @@ -4,25 +4,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Blockly constants. - * - * @namespace Blockly.constants - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.constants'); /** * The language-neutral ID given to the collapsed input. - * - * @alias Blockly.constants.COLLAPSED_INPUT_NAME */ export const COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT'; /** * The language-neutral ID given to the collapsed field. - * - * @alias Blockly.constants.COLLAPSED_FIELD_NAME */ export const COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD'; diff --git a/core/contextmenu.ts b/core/contextmenu.ts index c7737a597..f9015a57e 100644 --- a/core/contextmenu.ts +++ b/core/contextmenu.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Functionality for the right-click context menus. - * - * @namespace Blockly.ContextMenu - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.ContextMenu'); @@ -44,7 +39,6 @@ const dummyOwner = {}; * Gets the block the context menu is currently attached to. * * @returns The block the context menu is attached to. - * @alias Blockly.ContextMenu.getCurrentBlock */ export function getCurrentBlock(): Block|null { return currentBlock; @@ -54,7 +48,6 @@ export function getCurrentBlock(): Block|null { * Sets the block the context menu is currently attached to. * * @param block The block the context menu is attached to. - * @alias Blockly.ContextMenu.setCurrentBlock */ export function setCurrentBlock(block: Block|null) { currentBlock = block; @@ -71,7 +64,6 @@ let menu_: Menu|null = null; * @param e Mouse event. * @param options Array of menu options. * @param rtl True if RTL, false if LTR. - * @alias Blockly.ContextMenu.show */ export function show( e: Event, options: (ContextMenuOption|LegacyContextMenuOption)[], @@ -120,11 +112,15 @@ function populate_( if (option.enabled) { const actionHandler = function() { hide(); - // If .scope does not exist on the option, then the callback will not - // be expecting a scope parameter, so there should be no problems. Just - // assume it is a ContextMenuOption and we'll pass undefined if it's - // not. - option.callback((option as ContextMenuOption).scope); + requestAnimationFrame(() => { + setTimeout(() => { + // If .scope does not exist on the option, then the callback + // will not be expecting a scope parameter, so there should be + // no problems. Just assume it is a ContextMenuOption and we'll + // pass undefined if it's not. + option.callback((option as ContextMenuOption).scope); + }, 0); + }); }; menuItem.onAction(actionHandler, {}); } @@ -200,8 +196,6 @@ function haltPropagation(e: Event) { /** * Hide the context menu. - * - * @alias Blockly.ContextMenu.hide */ export function hide() { WidgetDiv.hideIfOwner(dummyOwner); @@ -210,8 +204,6 @@ export function hide() { /** * Dispose of the menu. - * - * @alias Blockly.ContextMenu.dispose */ export function dispose() { if (menu_) { @@ -227,7 +219,6 @@ export function dispose() { * @param block Original block. * @param xml XML representation of new block. * @returns Function that creates a block. - * @alias Blockly.ContextMenu.callbackFactory */ export function callbackFactory(block: Block, xml: Element): Function { return () => { @@ -263,7 +254,6 @@ export function callbackFactory(block: Block, xml: Element): Function { * right-click originated. * @returns A menu option, * containing text, enabled, and a callback. - * @alias Blockly.ContextMenu.commentDeleteOption * @internal */ export function commentDeleteOption(comment: WorkspaceCommentSvg): @@ -287,7 +277,6 @@ export function commentDeleteOption(comment: WorkspaceCommentSvg): * right-click originated. * @returns A menu option, * containing text, enabled, and a callback. - * @alias Blockly.ContextMenu.commentDuplicateOption * @internal */ export function commentDuplicateOption(comment: WorkspaceCommentSvg): @@ -311,7 +300,6 @@ export function commentDuplicateOption(comment: WorkspaceCommentSvg): * @returns A menu option, containing text, enabled, and a callback. * @suppress {strictModuleDepCheck,checkTypes} Suppress checks while workspace * comments are not bundled in. - * @alias Blockly.ContextMenu.workspaceCommentOption * @internal */ export function workspaceCommentOption( diff --git a/core/contextmenu_items.ts b/core/contextmenu_items.ts index db87b2618..67d035307 100644 --- a/core/contextmenu_items.ts +++ b/core/contextmenu_items.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Registers default context menu items. - * - * @namespace Blockly.ContextMenuItems - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.ContextMenuItems'); @@ -20,14 +15,11 @@ import * as Events from './events/events.js'; import * as eventUtils from './events/utils.js'; import {inputTypes} from './input_types.js'; import {Msg} from './msg.js'; -import * as idGenerator from './utils/idgenerator.js'; import type {WorkspaceSvg} from './workspace_svg.js'; /** * Option to undo previous action. - * - * @alias Blockly.ContextMenuItems.registerUndo */ export function registerUndo() { const undoOption: RegistryItem = { @@ -52,8 +44,6 @@ export function registerUndo() { /** * Option to redo previous action. - * - * @alias Blockly.ContextMenuItems.registerRedo */ export function registerRedo() { const redoOption: RegistryItem = { @@ -78,8 +68,6 @@ export function registerRedo() { /** * Option to clean up blocks. - * - * @alias Blockly.ContextMenuItems.registerCleanup */ export function registerCleanup() { const cleanOption: RegistryItem = { @@ -135,8 +123,6 @@ function toggleOption_(shouldCollapse: boolean, topBlocks: BlockSvg[]) { /** * Option to collapse all blocks. - * - * @alias Blockly.ContextMenuItems.registerCollapse */ export function registerCollapse() { const collapseOption: RegistryItem = { @@ -171,8 +157,6 @@ export function registerCollapse() { /** * Option to expand all blocks. - * - * @alias Blockly.ContextMenuItems.registerExpand */ export function registerExpand() { const expandOption: RegistryItem = { @@ -240,13 +224,18 @@ function getDeletableBlocks_(workspace: WorkspaceSvg): BlockSvg[] { /** * Deletes the given blocks. Used to delete all blocks in the workspace. * - * @param deleteList list of blocks to delete. - * @param eventGroup event group ID with which all delete events should be - * associated. + * @param deleteList List of blocks to delete. + * @param eventGroup Event group ID with which all delete events should be + * associated. If not specified, create a new group. */ -function deleteNext_(deleteList: BlockSvg[], eventGroup: string) { +function deleteNext_(deleteList: BlockSvg[], eventGroup?: string) { const DELAY = 10; - eventUtils.setGroup(eventGroup); + if (eventGroup) { + eventUtils.setGroup(eventGroup); + } else { + eventUtils.setGroup(true); + eventGroup = eventUtils.getGroup(); + } const block = deleteList.shift(); if (block) { if (!block.isDeadOrDying()) { @@ -261,8 +250,6 @@ function deleteNext_(deleteList: BlockSvg[], eventGroup: string) { /** * Option to delete all blocks. - * - * @alias Blockly.ContextMenuItems.registerDeleteAll */ export function registerDeleteAll() { const deleteOption: RegistryItem = { @@ -273,10 +260,8 @@ export function registerDeleteAll() { const deletableBlocksLength = getDeletableBlocks_(scope.workspace).length; if (deletableBlocksLength === 1) { return Msg['DELETE_BLOCK']; - } else { - return Msg['DELETE_X_BLOCKS'].replace( - '%1', String(deletableBlocksLength)); } + return Msg['DELETE_X_BLOCKS'].replace('%1', `${deletableBlocksLength}`); }, preconditionFn(scope: Scope) { if (!scope.workspace) { @@ -291,16 +276,15 @@ export function registerDeleteAll() { } scope.workspace.cancelCurrentGesture(); const deletableBlocks = getDeletableBlocks_(scope.workspace); - const eventGroup = idGenerator.genUid(); if (deletableBlocks.length < 2) { - deleteNext_(deletableBlocks, eventGroup); + deleteNext_(deletableBlocks); } else { dialog.confirm( Msg['DELETE_ALL_BLOCKS'].replace( '%1', String(deletableBlocks.length)), function(ok) { if (ok) { - deleteNext_(deletableBlocks, eventGroup); + deleteNext_(deletableBlocks); } }); } @@ -323,8 +307,6 @@ function registerWorkspaceOptions_() { /** * Option to duplicate a block. - * - * @alias Blockly.ContextMenuItems.registerDuplicate */ export function registerDuplicate() { const duplicateOption: RegistryItem = { @@ -355,8 +337,6 @@ export function registerDuplicate() { /** * Option to add or remove block-level comment. - * - * @alias Blockly.ContextMenuItems.registerComment */ export function registerComment() { const commentOption: RegistryItem = { @@ -393,8 +373,6 @@ export function registerComment() { /** * Option to inline variables. - * - * @alias Blockly.ContextMenuItems.registerInline */ export function registerInline() { const inlineOption: RegistryItem = { @@ -428,8 +406,6 @@ export function registerInline() { /** * Option to collapse or expand a block. - * - * @alias Blockly.ContextMenuItems.registerCollapseExpandBlock */ export function registerCollapseExpandBlock() { const collapseExpandOption: RegistryItem = { @@ -457,8 +433,6 @@ export function registerCollapseExpandBlock() { /** * Option to disable or enable a block. - * - * @alias Blockly.ContextMenuItems.registerDisable */ export function registerDisable() { const disableOption: RegistryItem = { @@ -479,14 +453,12 @@ export function registerDisable() { }, callback(scope: Scope) { const block = scope.block; - const group = eventUtils.getGroup(); - if (!group) { + const existingGroup = eventUtils.getGroup(); + if (!existingGroup) { eventUtils.setGroup(true); } block!.setEnabled(!block!.isEnabled()); - if (!group) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); }, scopeType: ContextMenuRegistry.ScopeType.BLOCK, id: 'blockDisable', @@ -497,8 +469,6 @@ export function registerDisable() { /** * Option to delete a block. - * - * @alias Blockly.ContextMenuItems.registerDelete */ export function registerDelete() { const deleteOption: RegistryItem = { @@ -513,7 +483,7 @@ export function registerDelete() { } return descendantCount === 1 ? Msg['DELETE_BLOCK'] : - Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount)); + Msg['DELETE_X_BLOCKS'].replace('%1', `${descendantCount}`); }, preconditionFn(scope: Scope) { if (!scope.block!.isInFlyout && scope.block!.isDeletable()) { @@ -535,8 +505,6 @@ export function registerDelete() { /** * Option to open help for a block. - * - * @alias Blockly.ContextMenuItems.registerHelp */ export function registerHelp() { const helpOption: RegistryItem = { @@ -577,7 +545,6 @@ function registerBlockOptions_() { * Registers all default context menu items. This should be called once per * instance of ContextMenuRegistry. * - * @alias Blockly.ContextMenuItems.registerDefaultOptions * @internal */ export function registerDefaultOptions() { diff --git a/core/contextmenu_registry.ts b/core/contextmenu_registry.ts index 8f2a297b2..6f3eb5e1c 100644 --- a/core/contextmenu_registry.ts +++ b/core/contextmenu_registry.ts @@ -20,8 +20,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * Class for the registry of context menu items. This is intended to be a * singleton. You should not create a new instance, and only access this class * from ContextMenuRegistry.registry. - * - * @alias Blockly.ContextMenuRegistry */ export class ContextMenuRegistry { static registry: ContextMenuRegistry; diff --git a/core/css.ts b/core/css.ts index 81b2e15a9..f473aacf7 100644 --- a/core/css.ts +++ b/core/css.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Inject Blockly's CSS synchronously. - * - * @namespace Blockly.Css - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Css'); @@ -21,7 +16,6 @@ let injected = false; * components such as fields and the toolbox to store separate CSS. * * @param cssContent Multiline CSS string or an array of single lines of CSS. - * @alias Blockly.Css.register */ export function register(cssContent: string) { if (injected) { @@ -40,7 +34,6 @@ export function register(cssContent: string) { * @param hasCss If false, don't inject CSS (providing CSS becomes the * document's responsibility). * @param pathToMedia Path from page to the Blockly media directory. - * @alias Blockly.Css.inject */ export function inject(hasCss: boolean, pathToMedia: string) { // Only inject the CSS once. @@ -67,8 +60,6 @@ export function inject(hasCss: boolean, pathToMedia: string) { /** * The CSS content for Blockly. - * - * @alias Blockly.Css.content */ let content = ` .blocklySvg { @@ -235,16 +226,11 @@ let content = ` } .blocklyDraggable { - /* backup for browsers (e.g. IE11) that don't support grab */ - cursor: url("<<>>/handopen.cur"), auto; cursor: grab; cursor: -webkit-grab; } - /* backup for browsers (e.g. IE11) that don't support grabbing */ .blocklyDragging { - /* backup for browsers (e.g. IE11) that don't support grabbing */ - cursor: url("<<>>/handclosed.cur"), auto; cursor: grabbing; cursor: -webkit-grabbing; } @@ -252,8 +238,6 @@ let content = ` /* Changes cursor on mouse down. Not effective in Firefox because of https://bugzilla.mozilla.org/show_bug.cgi?id=771241 */ .blocklyDraggable:active { - /* backup for browsers (e.g. IE11) that don't support grabbing */ - cursor: url("<<>>/handclosed.cur"), auto; cursor: grabbing; cursor: -webkit-grabbing; } @@ -262,8 +246,6 @@ let content = ` ahead of block during a drag. This way the cursor is still a closed hand. */ .blocklyBlockDragSurface .blocklyDraggable { - /* backup for browsers (e.g. IE11) that don't support grabbing */ - cursor: url("<<>>/handclosed.cur"), auto; cursor: grabbing; cursor: -webkit-grabbing; } @@ -373,11 +355,15 @@ let content = ` box-sizing: border-box; } -/* Edge and IE introduce a close icon when the input value is longer than a - certain length. This affects our sizing calculations of the text input. - Hiding the close icon to avoid that. */ -.blocklyHtmlInput::-ms-clear { - display: none; +/* Remove the increase and decrease arrows on the field number editor */ +input.blocklyHtmlInput[type=number]::-webkit-inner-spin-button, +input.blocklyHtmlInput[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type=number] { + -moz-appearance: textfield; } .blocklyMainBackground { diff --git a/core/delete_area.ts b/core/delete_area.ts index 9bee66742..576d2475a 100644 --- a/core/delete_area.ts +++ b/core/delete_area.ts @@ -22,8 +22,6 @@ import type {IDraggable} from './interfaces/i_draggable.js'; /** * Abstract class for a component that can delete a block or bubble that is * dropped on top of it. - * - * @alias Blockly.DeleteArea */ export class DeleteArea extends DragTarget implements IDeleteArea { /** diff --git a/core/dialog.ts b/core/dialog.ts index c0d99d781..4c5d17852 100644 --- a/core/dialog.ts +++ b/core/dialog.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Wrapper functions around JS functions for showing alert/confirmation dialogs. - * - * @namespace Blockly.dialog - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.dialog'); @@ -37,7 +32,6 @@ let promptImplementation = function( * * @param message The message to display to the user. * @param opt_callback The callback when the alert is dismissed. - * @alias Blockly.dialog.alert */ export function alert(message: string, opt_callback?: () => void) { alertImplementation(message, opt_callback); @@ -48,7 +42,6 @@ export function alert(message: string, opt_callback?: () => void) { * * @param alertFunction The function to be run. * @see Blockly.dialog.alert - * @alias Blockly.dialog.setAlert */ export function setAlert(alertFunction: (p1: string, p2?: () => void) => void) { alertImplementation = alertFunction; @@ -60,7 +53,6 @@ export function setAlert(alertFunction: (p1: string, p2?: () => void) => void) { * * @param message The message to display to the user. * @param callback The callback for handling user response. - * @alias Blockly.dialog.confirm */ export function confirm(message: string, callback: (p1: boolean) => void) { TEST_ONLY.confirmInternal(message, callback); @@ -79,7 +71,6 @@ function confirmInternal(message: string, callback: (p1: boolean) => void) { * * @param confirmFunction The function to be run. * @see Blockly.dialog.confirm - * @alias Blockly.dialog.setConfirm */ export function setConfirm( confirmFunction: (p1: string, p2: (p1: boolean) => void) => void) { @@ -95,7 +86,6 @@ export function setConfirm( * @param message The message to display to the user. * @param defaultValue The value to initialize the prompt with. * @param callback The callback for handling user response. - * @alias Blockly.dialog.prompt */ export function prompt( message: string, defaultValue: string, @@ -108,7 +98,6 @@ export function prompt( * * @param promptFunction The function to be run. * @see Blockly.dialog.prompt - * @alias Blockly.dialog.setPrompt */ export function setPrompt( promptFunction: (p1: string, p2: string, p3: (p1: string|null) => void) => diff --git a/core/drag_target.ts b/core/drag_target.ts index a8977bca2..5ef9d82cc 100644 --- a/core/drag_target.ts +++ b/core/drag_target.ts @@ -21,8 +21,6 @@ import type {Rect} from './utils/rect.js'; /** * Abstract class for a component with custom behaviour when a block or bubble * is dragged over or dropped on top of it. - * - * @alias Blockly.DragTarget */ export class DragTarget implements IDragTarget { /** diff --git a/core/events/events.ts b/core/events/events.ts index c6ffe276e..edea5a6ff 100644 --- a/core/events/events.ts +++ b/core/events/events.ts @@ -4,16 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Events fired as a result of actions in Blockly's editor. - * - * @namespace Blockly.Events - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.Events'); -import {Abstract as AbstractEvent, AbstractEventJson} from './events_abstract.js'; +import {Abstract, AbstractEventJson} from './events_abstract.js'; import {BlockBase, BlockBaseJson} from './events_block_base.js'; import {BlockChange, BlockChangeJson} from './events_block_change.js'; import {BlockCreate, BlockCreateJson} from './events_block_create.js'; @@ -28,16 +23,6 @@ import {CommentCreate, CommentCreateJson} from './events_comment_create.js'; import {CommentDelete} from './events_comment_delete.js'; import {CommentMove, CommentMoveJson} from './events_comment_move.js'; import {MarkerMove, MarkerMoveJson} from './events_marker_move.js'; -import {ProcedureBase} from './events_procedure_base.js'; -import {ProcedureChangeReturn} from './events_procedure_change_return.js'; -import {ProcedureCreate} from './events_procedure_create.js'; -import {ProcedureDelete} from './events_procedure_delete.js'; -import {ProcedureEnable} from './events_procedure_enable.js'; -import {ProcedureRename} from './events_procedure_rename.js'; -import {ProcedureParameterBase} from './events_procedure_parameter_base.js'; -import {ProcedureParameterCreate} from './events_procedure_parameter_create.js'; -import {ProcedureParameterDelete} from './events_procedure_parameter_delete.js'; -import {ProcedureParameterRename} from './events_procedure_parameter_rename.js'; import {Selected, SelectedJson} from './events_selected.js'; import {ThemeChange, ThemeChangeJson} from './events_theme_change.js'; import {ToolboxItemSelect, ToolboxItemSelectJson} from './events_toolbox_item_select.js'; @@ -54,7 +39,7 @@ import {FinishedLoading, FinishedLoadingJson} from './workspace_events.js'; // Events. -export const Abstract = AbstractEvent; +export {Abstract}; export {AbstractEventJson}; export {BubbleOpen}; export {BubbleOpenJson}; @@ -87,16 +72,6 @@ export {FinishedLoading}; export {FinishedLoadingJson}; export {MarkerMove}; export {MarkerMoveJson}; -export {ProcedureBase}; -export {ProcedureChangeReturn}; -export {ProcedureCreate}; -export {ProcedureDelete}; -export {ProcedureEnable}; -export {ProcedureRename}; -export {ProcedureParameterBase}; -export {ProcedureParameterCreate}; -export {ProcedureParameterDelete}; -export {ProcedureParameterRename}; export {Selected}; export {SelectedJson}; export {ThemeChange}; diff --git a/core/events/events_abstract.ts b/core/events/events_abstract.ts index 39d01c040..a20d8c6b0 100644 --- a/core/events/events_abstract.ts +++ b/core/events/events_abstract.ts @@ -22,8 +22,6 @@ import * as eventUtils from './utils.js'; /** * Abstract class for an event. - * - * @alias Blockly.Events.Abstract */ export abstract class Abstract { /** @@ -34,7 +32,16 @@ export abstract class Abstract { /** The workspace identifier for this event. */ workspaceId?: string = undefined; + + /** + * An ID for the group of events this block is associated with. + * + * Groups define events that should be treated as an single action from the + * user's perspective, and should be undone together. + */ group: string; + + /** Whether this event is undoable or not. */ recordUndo: boolean; /** Whether or not the event is a UI event. */ @@ -43,16 +50,8 @@ export abstract class Abstract { /** Type of this event. */ type = ''; - /** @alias Blockly.Events.Abstract */ constructor() { - /** - * The event group ID for the group this event belongs to. Groups define - * events that should be treated as an single action from the user's - * perspective, and should be undone together. - */ this.group = eventUtils.getGroup(); - - /** Sets whether the event should be added to the undo stack. */ this.recordUndo = eventUtils.getRecordUndo(); } @@ -74,6 +73,9 @@ export abstract class Abstract { * @param json JSON representation. */ fromJson(json: AbstractEventJson) { + deprecation.warn( + 'Blockly.Events.Abstract.prototype.fromJson', 'version 9', 'version 10', + 'Blockly.Events.fromJson'); this.isBlank = false; this.group = json['group'] || ''; } @@ -89,9 +91,6 @@ export abstract class Abstract { */ static fromJson(json: AbstractEventJson, workspace: Workspace, event: any): Abstract { - deprecation.warn( - 'Blockly.Events.Abstract.prototype.fromJson', 'version 9', 'version 10', - 'Blockly.Events.fromJson'); event.isBlank = false; event.group = json['group'] || ''; event.workspaceId = workspace.id; diff --git a/core/events/events_block_base.ts b/core/events/events_block_base.ts index cd134c516..b279af43b 100644 --- a/core/events/events_block_base.ts +++ b/core/events/events_block_base.ts @@ -20,12 +20,12 @@ import {Abstract as AbstractEvent, AbstractEventJson} from './events_abstract.js /** - * Abstract class for a block event. - * - * @alias Blockly.Events.BlockBase + * Abstract class for any event related to blocks. */ export class BlockBase extends AbstractEvent { override isBlank = true; + + /** The ID of the block associated with this event. */ blockId?: string; /** @@ -38,10 +38,7 @@ export class BlockBase extends AbstractEvent { if (!opt_block) return; - /** The block ID for the block this event pertains to */ this.blockId = opt_block.id; - - /** The workspace identifier for this event. */ this.workspaceId = opt_block.workspace.id; } diff --git a/core/events/events_block_change.ts b/core/events/events_block_change.ts index e9c34013c..7218ea5d0 100644 --- a/core/events/events_block_change.ts +++ b/core/events/events_block_change.ts @@ -16,6 +16,7 @@ import type {Block} from '../block.js'; import type {BlockSvg} from '../block_svg.js'; import * as deprecation from '../utils/deprecation.js'; import * as registry from '../registry.js'; +import * as utilsXml from '../utils/xml.js'; import {Workspace} from '../workspace.js'; import * as Xml from '../xml.js'; @@ -24,15 +25,24 @@ import * as eventUtils from './utils.js'; /** - * Class for a block change event. - * - * @alias Blockly.Events.BlockChange + * Notifies listeners when some element of a block has changed (e.g. + * field values, comments, etc). */ export class BlockChange extends BlockBase { override type = eventUtils.BLOCK_CHANGE; + /** + * The element that changed; one of 'field', 'comment', 'collapsed', + * 'disabled', 'inline', or 'mutation' + */ element?: string; + + /** The name of the field that changed, if this is a change to a field. */ name?: string; + + /** The original value of the element. */ oldValue: unknown; + + /** The new value of the element. */ newValue: unknown; /** @@ -173,7 +183,8 @@ export class BlockChange extends BlockBase { if (block.loadExtraState) { block.loadExtraState(JSON.parse(value as string || '{}')); } else if (block.domToMutation) { - block.domToMutation(Xml.textToDom(value as string || '')); + block.domToMutation( + utilsXml.textToDom(value as string || '')); } eventUtils.fire( new BlockChange(block, 'mutation', null, oldState, value)); diff --git a/core/events/events_block_create.ts b/core/events/events_block_create.ts index 4a6ad8232..7e09ed581 100644 --- a/core/events/events_block_create.ts +++ b/core/events/events_block_create.ts @@ -16,6 +16,7 @@ import type {Block} from '../block.js'; import * as deprecation from '../utils/deprecation.js'; import * as registry from '../registry.js'; import * as blocks from '../serialization/blocks.js'; +import * as utilsXml from '../utils/xml.js'; import * as Xml from '../xml.js'; import {BlockBase, BlockBaseJson} from './events_block_base.js'; @@ -24,16 +25,21 @@ import {Workspace} from '../workspace.js'; /** - * Class for a block creation event. - * - * @alias Blockly.Events.BlockCreate + * Notifies listeners when a block (or connected stack of blocks) is + * created. */ export class BlockCreate extends BlockBase { override type = eventUtils.BLOCK_CREATE; + + /** The XML representation of the created block(s). */ xml?: Element|DocumentFragment; - ids?: string[]; + + /** The JSON respresentation of the created block(s). */ json?: blocks.State; + /** All of the IDs of created blocks. */ + ids?: string[]; + /** @param opt_block The created block. Undefined for a blank event. */ constructor(opt_block?: Block) { super(opt_block); @@ -50,7 +56,6 @@ export class BlockCreate extends BlockBase { this.xml = Xml.blockToDomWithXY(opt_block); this.ids = eventUtils.getDescendantIds(opt_block); - /** JSON representation of the block that was just created. */ this.json = blocks.save(opt_block, {addCoordinates: true}) as blocks.State; } @@ -95,7 +100,7 @@ export class BlockCreate extends BlockBase { 'Blockly.Events.BlockCreate.prototype.fromJson', 'version 9', 'version 10', 'Blockly.Events.fromJson'); super.fromJson(json); - this.xml = Xml.textToDom(json['xml']); + this.xml = utilsXml.textToDom(json['xml']); this.ids = json['ids']; this.json = json['json'] as blocks.State; if (json['recordUndo'] !== undefined) { @@ -117,7 +122,7 @@ export class BlockCreate extends BlockBase { const newEvent = super.fromJson(json, workspace, event ?? new BlockCreate()) as BlockCreate; - newEvent.xml = Xml.textToDom(json['xml']); + newEvent.xml = utilsXml.textToDom(json['xml']); newEvent.ids = json['ids']; newEvent.json = json['json'] as blocks.State; if (json['recordUndo'] !== undefined) { diff --git a/core/events/events_block_delete.ts b/core/events/events_block_delete.ts index 0f5cf56e8..2331041fa 100644 --- a/core/events/events_block_delete.ts +++ b/core/events/events_block_delete.ts @@ -16,6 +16,7 @@ import type {Block} from '../block.js'; import * as deprecation from '../utils/deprecation.js'; import * as registry from '../registry.js'; import * as blocks from '../serialization/blocks.js'; +import * as utilsXml from '../utils/xml.js'; import * as Xml from '../xml.js'; import {BlockBase, BlockBaseJson} from './events_block_base.js'; @@ -24,15 +25,22 @@ import {Workspace} from '../workspace.js'; /** - * Class for a block deletion event. - * - * @alias Blockly.Events.BlockDelete + * Notifies listeners when a block (or connected stack of blocks) is + * deleted. */ export class BlockDelete extends BlockBase { + /** The XML representation of the deleted block(s). */ oldXml?: Element|DocumentFragment; - ids?: string[]; - wasShadow?: boolean; + + /** The JSON respresentation of the deleted block(s). */ oldJson?: blocks.State; + + /** All of the IDs of deleted blocks. */ + ids?: string[]; + + /** True if the deleted block was a shadow block, false otherwise. */ + wasShadow?: boolean; + override type = eventUtils.BLOCK_DELETE; /** @param opt_block The deleted block. Undefined for a blank event. */ @@ -53,11 +61,7 @@ export class BlockDelete extends BlockBase { this.oldXml = Xml.blockToDomWithXY(opt_block); this.ids = eventUtils.getDescendantIds(opt_block); - - /** Was the block that was just deleted a shadow? */ this.wasShadow = opt_block.isShadow(); - - /** JSON representation of the block that was just deleted. */ this.oldJson = blocks.save(opt_block, {addCoordinates: true}) as blocks.State; } @@ -109,7 +113,7 @@ export class BlockDelete extends BlockBase { 'Blockly.Events.BlockDelete.prototype.fromJson', 'version 9', 'version 10', 'Blockly.Events.fromJson'); super.fromJson(json); - this.oldXml = Xml.textToDom(json['oldXml']); + this.oldXml = utilsXml.textToDom(json['oldXml']); this.ids = json['ids']; this.wasShadow = json['wasShadow'] || this.oldXml.tagName.toLowerCase() === 'shadow'; @@ -133,7 +137,7 @@ export class BlockDelete extends BlockBase { const newEvent = super.fromJson(json, workspace, event ?? new BlockDelete()) as BlockDelete; - newEvent.oldXml = Xml.textToDom(json['oldXml']); + newEvent.oldXml = utilsXml.textToDom(json['oldXml']); newEvent.ids = json['ids']; newEvent.wasShadow = json['wasShadow'] || newEvent.oldXml.tagName.toLowerCase() === 'shadow'; diff --git a/core/events/events_block_drag.ts b/core/events/events_block_drag.ts index 822e5dfce..4163da907 100644 --- a/core/events/events_block_drag.ts +++ b/core/events/events_block_drag.ts @@ -22,14 +22,21 @@ import {Workspace} from '../workspace.js'; /** - * Class for a block drag event. - * - * @alias Blockly.Events.BlockDrag + * Notifies listeners when a block is being manually dragged/dropped. */ export class BlockDrag extends UiBase { + /** The ID of the top-level block being dragged. */ blockId?: string; + + /** True if this is the start of a drag, false if this is the end of one. */ isStart?: boolean; + + /** + * A list of all of the blocks (i.e. all descendants of the block associated + * with the block ID) being dragged. + */ blocks?: Block[]; + override type = eventUtils.BLOCK_DRAG; /** @@ -46,11 +53,7 @@ export class BlockDrag extends UiBase { if (!opt_block) return; this.blockId = opt_block.id; - - /** Whether this is the start of a block drag. */ this.isStart = opt_isStart; - - /** The blocks affected by this drag event. */ this.blocks = opt_blocks; } diff --git a/core/events/events_block_move.ts b/core/events/events_block_move.ts index 2aaffa524..e886a06ac 100644 --- a/core/events/events_block_move.ts +++ b/core/events/events_block_move.ts @@ -30,18 +30,40 @@ interface BlockLocation { } /** - * Class for a block move event. Created before the move. - * - * @alias Blockly.Events.BlockMove + * Notifies listeners when a block is moved. This could be from one + * connection to another, or from one location on the workspace to another. */ export class BlockMove extends BlockBase { override type = eventUtils.BLOCK_MOVE; + + /** The ID of the old parent block. Undefined if it was a top-level block. */ oldParentId?: string; + + /** + * The name of the old input. Undefined if it was a top-level block or the + * parent's next block. + */ oldInputName?: string; + + /** + * The old X and Y workspace coordinates of the block if it was a top level + * block. Undefined if it was not a top level block. + */ oldCoordinate?: Coordinate; + /** The ID of the new parent block. Undefined if it is a top-level block. */ newParentId?: string; + + /** + * The name of the new input. Undefined if it is a top-level block or the + * parent's next block. + */ newInputName?: string; + + /** + * The new X and Y workspace coordinates of the block if it is a top level + * block. Undefined if it is not a top level block. + */ newCoordinate?: Coordinate; /** @param opt_block The moved block. Undefined for a blank event. */ @@ -239,7 +261,7 @@ export class BlockMove extends BlockBase { blockConnection = block.previousConnection; } let parentConnection; - const connectionType = blockConnection.type; + const connectionType = blockConnection?.type; if (inputName) { const input = parentBlock!.getInput(inputName); if (input) { @@ -248,7 +270,7 @@ export class BlockMove extends BlockBase { } else if (connectionType === ConnectionType.PREVIOUS_STATEMENT) { parentConnection = parentBlock!.nextConnection; } - if (parentConnection) { + if (parentConnection && blockConnection) { blockConnection.connect(parentConnection); } else { console.warn('Can\'t connect to non-existent input: ' + inputName); diff --git a/core/events/events_bubble_open.ts b/core/events/events_bubble_open.ts index 6e6c26934..8697d22c0 100644 --- a/core/events/events_bubble_open.ts +++ b/core/events/events_bubble_open.ts @@ -23,13 +23,17 @@ import type {Workspace} from '../workspace.js'; /** * Class for a bubble open event. - * - * @alias Blockly.Events.BubbleOpen */ export class BubbleOpen extends UiBase { + /** The ID of the block the bubble is attached to. */ blockId?: string; + + /** True if the bubble is opening, false if closing. */ isOpen?: boolean; + + /** The type of bubble; one of 'mutator', 'comment', or 'warning'. */ bubbleType?: BubbleType; + override type = eventUtils.BUBBLE_OPEN; /** @@ -46,11 +50,7 @@ export class BubbleOpen extends UiBase { if (!opt_block) return; this.blockId = opt_block.id; - - /** Whether the bubble is opening (false if closing). */ this.isOpen = opt_isOpen; - - /** The type of bubble. One of 'mutator', 'comment', or 'warning'. */ this.bubbleType = opt_bubbleType; } diff --git a/core/events/events_click.ts b/core/events/events_click.ts index a5cafd718..66915762a 100644 --- a/core/events/events_click.ts +++ b/core/events/events_click.ts @@ -23,12 +23,16 @@ import {Workspace} from '../workspace.js'; /** - * Class for a click event. - * - * @alias Blockly.Events.Click + * Notifies listeners that ome blockly element was clicked. */ export class Click extends UiBase { + /** The ID of the block that was clicked, if a block was clicked. */ blockId?: string; + + /** + * The type of element that was clicked; one of 'block', 'workspace', + * or 'zoom_controls'. + */ targetType?: ClickTarget; override type = eventUtils.CLICK; @@ -51,8 +55,6 @@ export class Click extends UiBase { super(workspaceId); this.blockId = opt_block ? opt_block.id : undefined; - - /** The type of element targeted by this click event. */ this.targetType = opt_targetType; } diff --git a/core/events/events_comment_base.ts b/core/events/events_comment_base.ts index dd681a79d..bee960886 100644 --- a/core/events/events_comment_base.ts +++ b/core/events/events_comment_base.ts @@ -26,11 +26,11 @@ import type {Workspace} from '../workspace.js'; /** * Abstract class for a comment event. - * - * @alias Blockly.Events.CommentBase */ export class CommentBase extends AbstractEvent { override isBlank = true; + + /** The ID of the comment that this event references. */ commentId?: string; /** @@ -44,20 +44,9 @@ export class CommentBase extends AbstractEvent { if (!opt_comment) return; - /** The ID of the comment this event pertains to. */ this.commentId = opt_comment.id; - - /** The workspace identifier for this event. */ this.workspaceId = opt_comment.workspace.id; - - /** - * The event group ID for the group this event belongs to. Groups define - * events that should be treated as an single action from the user's - * perspective, and should be undone together. - */ this.group = eventUtils.getGroup(); - - /** Sets whether the event should be added to the undo stack. */ this.recordUndo = eventUtils.getRecordUndo(); } diff --git a/core/events/events_comment_change.ts b/core/events/events_comment_change.ts index f1007ed6c..d154f6425 100644 --- a/core/events/events_comment_change.ts +++ b/core/events/events_comment_change.ts @@ -22,13 +22,16 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a comment change event. - * - * @alias Blockly.Events.CommentChange + * Notifies listeners that the contents of a workspace comment has changed. */ export class CommentChange extends CommentBase { override type = eventUtils.COMMENT_CHANGE; + + // TODO(#6774): We should remove underscores. + /** The previous contents of the comment. */ oldContents_?: string; + + /** The new contents of the comment. */ newContents_?: string; /** diff --git a/core/events/events_comment_create.ts b/core/events/events_comment_create.ts index fa54b0e96..261a6c00f 100644 --- a/core/events/events_comment_create.ts +++ b/core/events/events_comment_create.ts @@ -15,6 +15,7 @@ goog.declareModuleId('Blockly.Events.CommentCreate'); import * as deprecation from '../utils/deprecation.js'; import * as registry from '../registry.js'; import type {WorkspaceComment} from '../workspace_comment.js'; +import * as utilsXml from '../utils/xml.js'; import * as Xml from '../xml.js'; import {CommentBase, CommentBaseJson} from './events_comment_base.js'; @@ -23,13 +24,12 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a comment creation event. - * - * @alias Blockly.Events.CommentCreate + * Notifies listeners that a workspace comment was created. */ export class CommentCreate extends CommentBase { override type = eventUtils.COMMENT_CREATE; + /** The XML representation of the created workspace comment. */ xml?: Element|DocumentFragment; /** @@ -73,7 +73,7 @@ export class CommentCreate extends CommentBase { 'Blockly.Events.CommentCreate.prototype.fromJson', 'version 9', 'version 10', 'Blockly.Events.fromJson'); super.fromJson(json); - this.xml = Xml.textToDom(json['xml']); + this.xml = utilsXml.textToDom(json['xml']); } /** @@ -90,7 +90,7 @@ export class CommentCreate extends CommentBase { const newEvent = super.fromJson(json, workspace, event ?? new CommentCreate()) as CommentCreate; - newEvent.xml = Xml.textToDom(json['xml']); + newEvent.xml = utilsXml.textToDom(json['xml']); return newEvent; } diff --git a/core/events/events_comment_delete.ts b/core/events/events_comment_delete.ts index 8ec7b5913..736ef6223 100644 --- a/core/events/events_comment_delete.ts +++ b/core/events/events_comment_delete.ts @@ -17,17 +17,18 @@ import type {WorkspaceComment} from '../workspace_comment.js'; import {CommentBase, CommentBaseJson} from './events_comment_base.js'; import * as eventUtils from './utils.js'; +import * as utilsXml from '../utils/xml.js'; import * as Xml from '../xml.js'; import type {Workspace} from '../workspace.js'; /** - * Class for a comment deletion event. - * - * @alias Blockly.Events.CommentDelete + * Notifies listeners that a workspace comment has been deleted. */ export class CommentDelete extends CommentBase { override type = eventUtils.COMMENT_DELETE; + + /** The XML representation of the deleted workspace comment. */ xml?: Element; /** @@ -83,7 +84,7 @@ export class CommentDelete extends CommentBase { const newEvent = super.fromJson(json, workspace, event ?? new CommentDelete()) as CommentDelete; - newEvent.xml = Xml.textToDom(json['xml']); + newEvent.xml = utilsXml.textToDom(json['xml']); return newEvent; } } diff --git a/core/events/events_comment_move.ts b/core/events/events_comment_move.ts index e40c48569..31a893c0a 100644 --- a/core/events/events_comment_move.ts +++ b/core/events/events_comment_move.ts @@ -23,15 +23,19 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a comment move event. Created before the move. - * - * @alias Blockly.Events.CommentMove + * Notifies listeners that a workspace comment has moved. */ export class CommentMove extends CommentBase { override type = eventUtils.COMMENT_MOVE; + + /** The comment that is being moved. */ comment_?: WorkspaceComment; + + // TODO(#6774): We should remove underscores. + /** The location of the comment before the move, in workspace coordinates. */ oldCoordinate_?: Coordinate; - /** The location after the move, in workspace coordinates. */ + + /** The location of the comment after the move, in workspace coordinates. */ newCoordinate_?: Coordinate; /** @@ -45,13 +49,8 @@ export class CommentMove extends CommentBase { return; // Blank event to be populated by fromJson. } - /** - * The comment that is being moved. - */ this.comment_ = opt_comment; - - /** The location before the move, in workspace coordinates. */ - this.oldCoordinate_ = opt_comment.getXY(); + this.oldCoordinate_ = opt_comment.getRelativeToSurfaceXY(); } /** @@ -69,7 +68,7 @@ export class CommentMove extends CommentBase { 'The comment is undefined. Pass a comment to ' + 'the constructor if you want to use the record functionality'); } - this.newCoordinate_ = this.comment_.getXY(); + this.newCoordinate_ = this.comment_.getRelativeToSurfaceXY(); } /** @@ -179,7 +178,7 @@ export class CommentMove extends CommentBase { 'or call fromJson'); } // TODO: Check if the comment is being dragged, and give up if so. - const current = comment.getXY(); + const current = comment.getRelativeToSurfaceXY(); comment.moveBy(target.x - current.x, target.y - current.y); } } diff --git a/core/events/events_marker_move.ts b/core/events/events_marker_move.ts index 3639c738b..dcb4fe784 100644 --- a/core/events/events_marker_move.ts +++ b/core/events/events_marker_move.ts @@ -24,15 +24,26 @@ import * as eventUtils from './utils.js'; /** - * Class for a marker move event. - * - * @alias Blockly.Events.MarkerMove + * Notifies listeners that a marker (used for keyboard navigation) has + * moved. */ export class MarkerMove extends UiBase { + /** The ID of the block the marker is now on, if any. */ blockId?: string; + + /** The old node the marker used to be on, if any. */ oldNode?: ASTNode; + + /** The new node the marker is now on. */ newNode?: ASTNode; + + /** + * True if this is a cursor event, false otherwise. + * For information about cursors vs markers see {@link + * https://blocklycodelabs.dev/codelabs/keyboard-navigation/index.html?index=..%2F..index#1}. + */ isCursor?: boolean; + override type = eventUtils.MARKER_MOVE; /** @@ -54,16 +65,9 @@ export class MarkerMove extends UiBase { } super(workspaceId); - /** The block identifier for this event. */ this.blockId = opt_block?.id; - - /** The old node the marker used to be on. */ this.oldNode = opt_oldNode || undefined; - - /** The new node the marker is now on. */ this.newNode = opt_newNode; - - /** Whether this is a cursor event. */ this.isCursor = isCursor; } diff --git a/core/events/events_procedure_base.ts b/core/events/events_procedure_base.ts deleted file mode 100644 index 1c17db24a..000000000 --- a/core/events/events_procedure_base.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Abstract as AbstractEvent, AbstractEventJson} from './events_abstract.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import type {Workspace} from '../workspace.js'; - - -/** - * The base event for an event associated with a procedure. - */ -export abstract class ProcedureBase extends AbstractEvent { - isBlank = false; - - constructor(workspace: Workspace, public readonly model: IProcedureModel) { - super(); - this.workspaceId = workspace.id; - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureBaseJson { - const json = super.toJson() as ProcedureBaseJson; - json['procedureId'] = this.model.getId(); - return json; - } -} - -export interface ProcedureBaseJson extends AbstractEventJson { - procedureId: string; -} diff --git a/core/events/events_procedure_change_return.ts b/core/events/events_procedure_change_return.ts deleted file mode 100644 index a6e3c6be7..000000000 --- a/core/events/events_procedure_change_return.ts +++ /dev/null @@ -1,87 +0,0 @@ - -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; -import * as eventUtils from './utils.js'; - - -/** - * Represents a procedure's return type/status changing. - */ -export class ProcedureChangeReturn extends ProcedureBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_CHANGE_RETURN; - - /** The new type(s) the procedure's return has been set to. */ - private newTypes: string[]|null; - - /** - * @param oldTypes The type(s) the procedure's return was set to before it - * changed. - */ - constructor( - workpace: Workspace, model: IProcedureModel, - public readonly oldTypes: string[]|null) { - super(workpace, model); - - this.newTypes = model.getReturnTypes(); - } - - run(forward: boolean) { - const procedureModel = - this.getEventWorkspace_().getProcedureMap().get(this.model.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the type of a procedure that does not exist ' + - 'in the procedure map'); - } - if (forward) { - procedureModel.setReturnTypes(this.newTypes); - } else { - procedureModel.setReturnTypes(this.oldTypes); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureChangeReturnJson { - const json = super.toJson() as ProcedureChangeReturnJson; - json['oldTypes'] = this.oldTypes; - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureChangeReturnJson, workspace: Workspace): - ProcedureChangeReturn { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure change return event because the ' + - 'target procedure does not exist'); - } - return new ProcedureChangeReturn(workspace, model, json['oldTypes']); - } -} - -export interface ProcedureChangeReturnJson extends ProcedureBaseJson { - oldTypes: string[]|null; -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_CHANGE_RETURN, - ProcedureChangeReturn); diff --git a/core/events/events_procedure_create.ts b/core/events/events_procedure_create.ts deleted file mode 100644 index ddccfb983..000000000 --- a/core/events/events_procedure_create.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {ObservableParameterModel, ObservableProcedureModel} from '../procedures.js'; -import * as registry from '../registry.js'; -import {loadProcedure, saveProcedure, State as ProcedureState} from '../serialization/procedures.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; -import * as eventUtils from './utils.js'; - - -/** - * Represents a procedure data model being created. - */ -export class ProcedureCreate extends ProcedureBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_CREATE; - - constructor(workspace: Workspace, model: IProcedureModel) { - super(workspace, model); - } - - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.model.getId()); - if (forward) { - if (procedureModel) return; - // TODO: This should add the model to the map instead of creating a dupe. - procedureMap.add(new ObservableProcedureModel( - workspace, this.model.getName(), this.model.getId())); - } else { - if (!procedureModel) return; - procedureMap.delete(this.model.getId()); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureCreateJson { - const json = super.toJson() as ProcedureCreateJson; - json['model'] = saveProcedure(this.model); - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureCreateJson, workspace: Workspace): - ProcedureCreate { - return new ProcedureCreate( - workspace, - loadProcedure( - ObservableProcedureModel, ObservableParameterModel, json['model'], - workspace)); - } -} - -export interface ProcedureCreateJson extends ProcedureBaseJson { - model: ProcedureState, -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_CREATE, ProcedureCreate); diff --git a/core/events/events_procedure_delete.ts b/core/events/events_procedure_delete.ts deleted file mode 100644 index e7555aeba..000000000 --- a/core/events/events_procedure_delete.ts +++ /dev/null @@ -1,71 +0,0 @@ - -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {ObservableProcedureModel} from '../procedures.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; -import * as eventUtils from './utils.js'; - - -/** - * Represents a procedure data model being deleted. - */ -export class ProcedureDelete extends ProcedureBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_DELETE; - - constructor(workspace: Workspace, model: IProcedureModel) { - super(workspace, model); - } - - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.model.getId()); - if (forward) { - if (!procedureModel) return; - procedureMap.delete(this.model.getId()); - } else { - if (procedureModel) return; - procedureMap.add(new ObservableProcedureModel( - workspace, this.model.getName(), this.model.getId())); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureDeleteJson { - return super.toJson() as ProcedureDeleteJson; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureDeleteJson, workspace: Workspace): - ProcedureDelete { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure delete event because the ' + - 'target procedure does not exist'); - } - return new ProcedureDelete(workspace, model); - } -} - -export interface ProcedureDeleteJson extends ProcedureBaseJson {} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_DELETE, ProcedureDelete); diff --git a/core/events/events_procedure_enable.ts b/core/events/events_procedure_enable.ts deleted file mode 100644 index 3ae52e93f..000000000 --- a/core/events/events_procedure_enable.ts +++ /dev/null @@ -1,76 +0,0 @@ - -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; -import * as eventUtils from './utils.js'; - -/** - * Represents a procedure data model being enabled or disabled. - */ -export class ProcedureEnable extends ProcedureBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_ENABLE; - - private oldState: boolean; - private newState: boolean; - - constructor(workspace: Workspace, model: IProcedureModel) { - super(workspace, model); - - this.oldState = !model.getEnabled(); - this.newState = model.getEnabled(); - } - - run(forward: boolean) { - const procedureModel = - this.getEventWorkspace_().getProcedureMap().get(this.model.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the enabled state of a procedure that does not ' + - 'exist in the procedure map'); - } - if (forward) { - procedureModel.setEnabled(this.newState); - } else { - procedureModel.setEnabled(this.oldState); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureEnableJson { - return super.toJson() as ProcedureEnableJson; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureEnableJson, workspace: Workspace): - ProcedureEnable { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure enable event because the ' + - 'target procedure does not exist'); - } - return new ProcedureEnable(workspace, model); - } -} - -export interface ProcedureEnableJson extends ProcedureBaseJson {} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_ENABLE, ProcedureEnable); diff --git a/core/events/events_procedure_parameter_base.ts b/core/events/events_procedure_parameter_base.ts deleted file mode 100644 index 1bbfb2429..000000000 --- a/core/events/events_procedure_parameter_base.ts +++ /dev/null @@ -1,39 +0,0 @@ - -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {IParameterModel} from '../interfaces/i_parameter_model.js'; -import {IProcedureModel} from '../interfaces/i_procedure_model.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; - -import type {Workspace} from '../workspace.js'; - -/** - * The base event for an event associated with a procedure parameter. - */ -export abstract class ProcedureParameterBase extends ProcedureBase { - constructor( - workspace: Workspace, model: IProcedureModel, - public readonly parameter: IParameterModel) { - super(workspace, model); - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterBaseJson { - const json = super.toJson() as ProcedureParameterBaseJson; - json['parameterId'] = this.model.getId(); - return json; - } -} - -export interface ProcedureParameterBaseJson extends ProcedureBaseJson { - parameterId: string, -} diff --git a/core/events/events_procedure_parameter_create.ts b/core/events/events_procedure_parameter_create.ts deleted file mode 100644 index 1271effc3..000000000 --- a/core/events/events_procedure_parameter_create.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IParameterModel} from '../interfaces/i_parameter_model.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {ObservableParameterModel} from '../procedures/observable_parameter_model.js'; -import * as registry from '../registry.js'; -import {loadParameter, ParameterState, saveParameter} from '../serialization/procedures.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureParameterBase, ProcedureParameterBaseJson} from './events_procedure_parameter_base.js'; -import * as eventUtils from './utils.js'; - - -/** - * Represents a parameter being added to a procedure. - */ -export class ProcedureParameterCreate extends ProcedureParameterBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_PARAMETER_CREATE; - - /** - * @param parameter The parameter model that was just added to the procedure. - * @param index The index the parameter was inserted at. - */ - constructor( - workspace: Workspace, procedure: IProcedureModel, - parameter: IParameterModel, public readonly index: number) { - super(workspace, procedure, parameter); - } - - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.model.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot add a parameter to a procedure that does not exist ' + - 'in the procedure map'); - } - const parameterModel = procedureModel.getParameter(this.index); - if (forward) { - if (this.parameterMatches(parameterModel)) return; - // TODO: This should just add the parameter instead of creating a dupe. - procedureModel.insertParameter( - new ObservableParameterModel( - workspace, this.parameter.getName(), this.parameter.getId()), - this.index); - } else { - if (!this.parameterMatches(parameterModel)) return; - procedureModel.deleteParameter(this.index); - } - } - - parameterMatches(param: IParameterModel) { - return param && param.getId() === this.parameter.getId(); - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterCreateJson { - const json = super.toJson() as ProcedureParameterCreateJson; - json['parameter'] = saveParameter(this.parameter); - json['index'] = this.index; - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureParameterCreateJson, workspace: Workspace): - ProcedureParameterCreate { - const procedure = workspace.getProcedureMap().get(json['procedureId']); - if (!procedure) { - throw new Error( - 'Cannot deserialize parameter create event because the ' + - 'target procedure does not exist'); - } - return new ProcedureParameterCreate( - workspace, procedure, - loadParameter(ObservableParameterModel, json['parameter'], workspace), - json['index']); - } -} - -export interface ProcedureParameterCreateJson extends - ProcedureParameterBaseJson { - parameter: ParameterState, index: number, -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_PARAMETER_CREATE, - ProcedureParameterCreate); diff --git a/core/events/events_procedure_parameter_delete.ts b/core/events/events_procedure_parameter_delete.ts deleted file mode 100644 index 4ee43bb0b..000000000 --- a/core/events/events_procedure_parameter_delete.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IParameterModel} from '../interfaces/i_parameter_model.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {ObservableParameterModel} from '../procedures/observable_parameter_model.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureParameterBase, ProcedureParameterBaseJson} from './events_procedure_parameter_base.js'; -import * as eventUtils from './utils.js'; - -/** - * Represents a parameter being removed from a procedure. - */ -export class ProcedureParameterDelete extends ProcedureParameterBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_PARAMETER_DELETE; - - /** - * @param parameter The parameter model that was just removed from the - * procedure. - * @param index The index the parameter was at before it was removed. - */ - constructor( - workspace: Workspace, procedure: IProcedureModel, - parameter: IParameterModel, public readonly index: number) { - super(workspace, procedure, parameter); - } - - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.model.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot add a parameter to a procedure that does not exist ' + - 'in the procedure map'); - } - const parameterModel = procedureModel.getParameter(this.index); - if (forward) { - if (!this.parameterMatches(parameterModel)) return; - procedureModel.deleteParameter(this.index); - } else { - if (this.parameterMatches(parameterModel)) return; - // TODO: this should just insert the model instead of creating a dupe. - procedureModel.insertParameter( - new ObservableParameterModel( - workspace, this.parameter.getName(), this.parameter.getId()), - this.index); - } - } - - parameterMatches(param: IParameterModel) { - return param && param.getId() === this.parameter.getId(); - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterDeleteJson { - const json = super.toJson() as ProcedureParameterDeleteJson; - json['index'] = this.index; - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureParameterDeleteJson, workspace: Workspace): - ProcedureParameterDelete { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure delete event because the ' + - 'target procedure does not exist'); - } - const param = model.getParameter(json['index']); - return new ProcedureParameterDelete(workspace, model, param, json['index']); - } -} - -export interface ProcedureParameterDeleteJson extends - ProcedureParameterBaseJson { - index: number; -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_PARAMETER_DELETE, - ProcedureParameterDelete); diff --git a/core/events/events_procedure_parameter_rename.ts b/core/events/events_procedure_parameter_rename.ts deleted file mode 100644 index 9baafc11b..000000000 --- a/core/events/events_procedure_parameter_rename.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IParameterModel} from '../interfaces/i_parameter_model.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureParameterBase, ProcedureParameterBaseJson} from './events_procedure_parameter_base.js'; -import * as eventUtils from './utils.js'; - -/** - * Represents a parameter of a procedure being renamed. - */ -export class ProcedureParameterRename extends ProcedureParameterBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_PARAMETER_RENAME; - private readonly newName: string; - - constructor( - workspace: Workspace, procedure: IProcedureModel, - parameter: IParameterModel, public readonly oldName: string) { - super(workspace, procedure, parameter); - - this.newName = parameter.getName(); - } - - run(forward: boolean) { - const parameterModel = findMatchingParameter( - this.getEventWorkspace_(), this.model.getId(), this.parameter.getId()); - if (!parameterModel) { - throw new Error( - 'Cannot rename a parameter that does not exist ' + - 'in the procedure map'); - } - if (forward) { - parameterModel.setName(this.newName); - } else { - parameterModel.setName(this.oldName); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterRenameJson { - const json = super.toJson() as ProcedureParameterRenameJson; - json['oldName'] = this.oldName; - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureParameterRenameJson, workspace: Workspace): - ProcedureParameterRename { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure delete event because the ' + - 'target procedure does not exist'); - } - const param = findMatchingParameter( - workspace, json['procedureId'], json['parameterId']); - if (!param) { - throw new Error( - 'Cannot deserialize parameter rename event because the ' + - 'target parameter does not exist'); - } - return new ProcedureParameterRename( - workspace, model, param, json['oldName']); - } -} - -function findMatchingParameter( - workspace: Workspace, modelId: string, paramId: string): IParameterModel| - undefined { - const procedureModel = workspace.getProcedureMap().get(modelId); - if (!procedureModel) { - throw new Error( - 'Cannot rename the parameter of a procedure that does not exist ' + - 'in the procedure map'); - } - return procedureModel.getParameters().find((p) => p.getId() === paramId); -} - - -export interface ProcedureParameterRenameJson extends - ProcedureParameterBaseJson { - oldName: string; -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_PARAMETER_RENAME, - ProcedureParameterRename); diff --git a/core/events/events_procedure_rename.ts b/core/events/events_procedure_rename.ts deleted file mode 100644 index 0b849d771..000000000 --- a/core/events/events_procedure_rename.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import * as registry from '../registry.js'; -import type {Workspace} from '../workspace.js'; - -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base.js'; -import * as eventUtils from './utils.js'; - -/** - * Represents a procedure being renamed. - */ -export class ProcedureRename extends ProcedureBase { - /** A string used to check the type of the event. */ - type = eventUtils.PROCEDURE_RENAME; - private newName: string; - - constructor( - workspace: Workspace, model: IProcedureModel, - public readonly oldName: string) { - super(workspace, model); - - this.newName = model.getName(); - } - - run(forward: boolean) { - const procedureModel = - this.getEventWorkspace_().getProcedureMap().get(this.model.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the type of a procedure that does not exist ' + - 'in the procedure map'); - } - if (forward) { - procedureModel.setName(this.newName); - } else { - procedureModel.setName(this.oldName); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureRenameJson { - const json = super.toJson() as ProcedureRenameJson; - json['oldName'] = this.oldName; - return json; - } - - /** - * Deserializes the JSON event. - * - * @internal - */ - static fromJson(json: ProcedureRenameJson, workspace: Workspace): - ProcedureRename { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure rename event because the ' + - 'target procedure does not exist'); - } - return new ProcedureRename(workspace, model, json['oldName']); - } -} - -export interface ProcedureRenameJson extends ProcedureBaseJson { - oldName: string; -} - -registry.register( - registry.Type.EVENT, eventUtils.PROCEDURE_RENAME, ProcedureRename); diff --git a/core/events/events_selected.ts b/core/events/events_selected.ts index 347bdb22a..fc1d6ce3f 100644 --- a/core/events/events_selected.ts +++ b/core/events/events_selected.ts @@ -23,12 +23,18 @@ import type {Workspace} from '../workspace.js'; /** * Class for a selected event. - * - * @alias Blockly.Events.Selected + * Notifies listeners that a new element has been selected. */ export class Selected extends UiBase { + /** The id of the last selected selectable element. */ oldElementId?: string; + + /** + * The id of the newly selected selectable element, + * or undefined if unselected. + */ newElementId?: string; + override type = eventUtils.SELECTED; /** @@ -44,10 +50,7 @@ export class Selected extends UiBase { opt_workspaceId?: string) { super(opt_workspaceId); - /** The id of the last selected element. */ this.oldElementId = opt_oldElementId ?? undefined; - - /** The id of the selected element. */ this.newElementId = opt_newElementId ?? undefined; } diff --git a/core/events/events_theme_change.ts b/core/events/events_theme_change.ts index 75c5641e2..d7ebef5bf 100644 --- a/core/events/events_theme_change.ts +++ b/core/events/events_theme_change.ts @@ -21,12 +21,12 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a theme change event. - * - * @alias Blockly.Events.ThemeChange + * Notifies listeners that the workspace theme has changed. */ export class ThemeChange extends UiBase { + /** The name of the new theme that has been set. */ themeName?: string; + override type = eventUtils.THEME_CHANGE; /** @@ -36,8 +36,6 @@ export class ThemeChange extends UiBase { */ constructor(opt_themeName?: string, opt_workspaceId?: string) { super(opt_workspaceId); - - /** The theme name. */ this.themeName = opt_themeName; } diff --git a/core/events/events_toolbox_item_select.ts b/core/events/events_toolbox_item_select.ts index 81e8a7eda..4eca80b4d 100644 --- a/core/events/events_toolbox_item_select.ts +++ b/core/events/events_toolbox_item_select.ts @@ -21,13 +21,15 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a toolbox item select event. - * - * @alias Blockly.Events.ToolboxItemSelect + * Notifies listeners that a toolbox item has been selected. */ export class ToolboxItemSelect extends UiBase { + /** The previously selected toolbox item. */ oldItem?: string; + + /** The newly selected toolbox item. */ newItem?: string; + override type = eventUtils.TOOLBOX_ITEM_SELECT; /** @@ -42,11 +44,7 @@ export class ToolboxItemSelect extends UiBase { opt_oldItem?: string|null, opt_newItem?: string|null, opt_workspaceId?: string) { super(opt_workspaceId); - - /** The previously selected toolbox item. */ this.oldItem = opt_oldItem ?? undefined; - - /** The newly selected toolbox item. */ this.newItem = opt_newItem ?? undefined; } diff --git a/core/events/events_trashcan_open.ts b/core/events/events_trashcan_open.ts index fd6001dfd..fd03b2da6 100644 --- a/core/events/events_trashcan_open.ts +++ b/core/events/events_trashcan_open.ts @@ -22,11 +22,13 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a trashcan open event. - * - * @alias Blockly.Events.TrashcanOpen + * Notifies listeners when the trashcan is opening or closing. */ export class TrashcanOpen extends UiBase { + /** + * True if the trashcan is currently opening (previously closed). + * False if it is currently closing (previously open). + */ isOpen?: boolean; override type = eventUtils.TRASHCAN_OPEN; @@ -38,8 +40,6 @@ export class TrashcanOpen extends UiBase { */ constructor(opt_isOpen?: boolean, opt_workspaceId?: string) { super(opt_workspaceId); - - /** Whether the trashcan flyout is opening (false if closing). */ this.isOpen = opt_isOpen; } diff --git a/core/events/events_ui.ts b/core/events/events_ui.ts index 670d9143d..f743f14d9 100644 --- a/core/events/events_ui.ts +++ b/core/events/events_ui.ts @@ -23,7 +23,6 @@ import * as eventUtils from './utils.js'; * Class for a UI event. * * @deprecated December 2020. Instead use a more specific UI event. - * @alias Blockly.Events.Ui */ export class Ui extends UiBase { blockId: AnyDuringMigration; diff --git a/core/events/events_ui_base.ts b/core/events/events_ui_base.ts index 5f585f079..be5a60d59 100644 --- a/core/events/events_ui_base.ts +++ b/core/events/events_ui_base.ts @@ -22,8 +22,6 @@ import {Abstract as AbstractEvent} from './events_abstract.js'; * editing to work (e.g. scrolling the workspace, zooming, opening toolbox * categories). * UI events do not undo or redo. - * - * @alias Blockly.Events.UiBase */ export class UiBase extends AbstractEvent { override isBlank = true; diff --git a/core/events/events_var_base.ts b/core/events/events_var_base.ts index 41370702d..f25628888 100644 --- a/core/events/events_var_base.ts +++ b/core/events/events_var_base.ts @@ -21,11 +21,10 @@ import type {Workspace} from '../workspace.js'; /** * Abstract class for a variable event. - * - * @alias Blockly.Events.VarBase */ export class VarBase extends AbstractEvent { override isBlank = true; + /** The ID of the variable this event references. */ varId?: string; /** @@ -37,10 +36,7 @@ export class VarBase extends AbstractEvent { this.isBlank = typeof opt_variable === 'undefined'; if (!opt_variable) return; - /** The variable id for the variable this event pertains to. */ this.varId = opt_variable.getId(); - - /** The workspace identifier for this event. */ this.workspaceId = opt_variable.workspace.id; } diff --git a/core/events/events_var_create.ts b/core/events/events_var_create.ts index 925071c59..eb8ccfe9f 100644 --- a/core/events/events_var_create.ts +++ b/core/events/events_var_create.ts @@ -22,13 +22,15 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a variable creation event. - * - * @alias Blockly.Events.VarCreate + * Notifies listeners that a variable model has been created. */ export class VarCreate extends VarBase { override type = eventUtils.VAR_CREATE; + + /** The type of the variable that was created. */ varType?: string; + + /** The name of the variable that was created. */ varName?: string; /** @@ -51,7 +53,7 @@ export class VarCreate extends VarBase { */ override toJson(): VarCreateJson { const json = super.toJson() as VarCreateJson; - if (!this.varType) { + if (this.varType === undefined) { throw new Error( 'The var type is undefined. Either pass a variable to ' + 'the constructor, or call fromJson'); diff --git a/core/events/events_var_delete.ts b/core/events/events_var_delete.ts index ca9e2de97..be0fec4fe 100644 --- a/core/events/events_var_delete.ts +++ b/core/events/events_var_delete.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Classes for all types of variable events. - * - * @class - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.Events.VarDelete'); @@ -22,13 +17,15 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a variable deletion event. + * Notifies listeners that a variable model has been deleted. * - * @alias Blockly.Events.VarDelete + * @class */ export class VarDelete extends VarBase { override type = eventUtils.VAR_DELETE; + /** The type of the variable that was deleted. */ varType?: string; + /** The name of the variable that was deleted. */ varName?: string; /** @@ -51,7 +48,7 @@ export class VarDelete extends VarBase { */ override toJson(): VarDeleteJson { const json = super.toJson() as VarDeleteJson; - if (!this.varType) { + if (this.varType === undefined) { throw new Error( 'The var type is undefined. Either pass a variable to ' + 'the constructor, or call fromJson'); diff --git a/core/events/events_var_rename.ts b/core/events/events_var_rename.ts index 278a1510d..bed95cf62 100644 --- a/core/events/events_var_rename.ts +++ b/core/events/events_var_rename.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class for a variable rename event. - * - * @class - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.Events.VarRename'); @@ -22,13 +17,17 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a variable rename event. + * Notifies listeners that a variable model was renamed. * - * @alias Blockly.Events.VarRename + * @class */ export class VarRename extends VarBase { override type = eventUtils.VAR_RENAME; + + /** The previous name of the variable. */ oldName?: string; + + /** The new name of the variable. */ newName?: string; /** diff --git a/core/events/events_viewport.ts b/core/events/events_viewport.ts index 3367e35f8..f0287a399 100644 --- a/core/events/events_viewport.ts +++ b/core/events/events_viewport.ts @@ -21,15 +21,30 @@ import type {Workspace} from '../workspace.js'; /** - * Class for a viewport change event. + * Notifies listeners that the workspace surface's position or scale has + * changed. * - * @alias Blockly.Events.ViewportChange + * Does not notify when the workspace itself resizes. */ export class ViewportChange extends UiBase { + /** + * Top edge of the visible portion of the workspace, relative to the + * workspace origin. + */ viewTop?: number; + + /** + * The left edge of the visible portion of the workspace, relative to + * the workspace origin. + */ viewLeft?: number; + + /** The scale of the workpace. */ scale?: number; + + /** The previous scale of the workspace. */ oldScale?: number; + override type = eventUtils.VIEWPORT_CHANGE; /** @@ -48,22 +63,9 @@ export class ViewportChange extends UiBase { opt_workspaceId?: string, opt_oldScale?: number) { super(opt_workspaceId); - /** - * Top-edge of the visible portion of the workspace, relative to the - * workspace origin. - */ this.viewTop = opt_top; - - /** - * Left-edge of the visible portion of the workspace, relative to the - * workspace origin. - */ this.viewLeft = opt_left; - - /** The scale of the workspace. */ this.scale = opt_scale; - - /** The old scale of the workspace. */ this.oldScale = opt_oldScale; } diff --git a/core/events/utils.ts b/core/events/utils.ts index 9ac08b9fc..e8505f38d 100644 --- a/core/events/utils.ts +++ b/core/events/utils.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Helper methods for events that are fired as a result of - * actions in Blockly's editor. - * - * @namespace Blockly.Events.utils - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.Events.utils'); @@ -39,7 +33,6 @@ let recordUndo = true; * Sets whether events should be added to the undo stack. * * @param newValue True if events should be added to the undo stack. - * @alias Blockly.Events.utils.setRecordUndo */ export function setRecordUndo(newValue: boolean) { recordUndo = newValue; @@ -49,7 +42,6 @@ export function setRecordUndo(newValue: boolean) { * Returns whether or not events will be added to the undo stack. * * @returns True if events will be added to the undo stack. - * @alias Blockly.Events.utils.getRecordUndo */ export function getRecordUndo(): boolean { return recordUndo; @@ -60,218 +52,140 @@ let disabled = 0; /** * Name of event that creates a block. Will be deprecated for BLOCK_CREATE. - * - * @alias Blockly.Events.utils.CREATE */ export const CREATE = 'create'; /** * Name of event that creates a block. - * - * @alias Blockly.Events.utils.BLOCK_CREATE */ export const BLOCK_CREATE = CREATE; /** * Name of event that deletes a block. Will be deprecated for BLOCK_DELETE. - * - * @alias Blockly.Events.utils.DELETE */ export const DELETE = 'delete'; /** * Name of event that deletes a block. - * - * @alias Blockly.Events.utils.BLOCK_DELETE */ export const BLOCK_DELETE = DELETE; /** * Name of event that changes a block. Will be deprecated for BLOCK_CHANGE. - * - * @alias Blockly.Events.utils.CHANGE */ export const CHANGE = 'change'; /** * Name of event that changes a block. - * - * @alias Blockly.Events.utils.BLOCK_CHANGE */ export const BLOCK_CHANGE = CHANGE; /** * Name of event that moves a block. Will be deprecated for BLOCK_MOVE. - * - * @alias Blockly.Events.utils.MOVE */ export const MOVE = 'move'; /** * Name of event that moves a block. - * - * @alias Blockly.Events.utils.BLOCK_MOVE */ export const BLOCK_MOVE = MOVE; /** * Name of event that creates a variable. - * - * @alias Blockly.Events.utils.VAR_CREATE */ export const VAR_CREATE = 'var_create'; /** * Name of event that deletes a variable. - * - * @alias Blockly.Events.utils.VAR_DELETE */ export const VAR_DELETE = 'var_delete'; /** * Name of event that renames a variable. - * - * @alias Blockly.Events.utils.VAR_RENAME */ export const VAR_RENAME = 'var_rename'; /** * Name of generic event that records a UI change. - * - * @alias Blockly.Events.utils.UI */ export const UI = 'ui'; /** * Name of event that record a block drags a block. - * - * @alias Blockly.Events.utils.BLOCK_DRAG */ export const BLOCK_DRAG = 'drag'; /** * Name of event that records a change in selected element. - * - * @alias Blockly.Events.utils.SELECTED */ export const SELECTED = 'selected'; /** * Name of event that records a click. - * - * @alias Blockly.Events.utils.CLICK */ export const CLICK = 'click'; /** * Name of event that records a marker move. - * - * @alias Blockly.Events.utils.MARKER_MOVE */ export const MARKER_MOVE = 'marker_move'; /** * Name of event that records a bubble open. - * - * @alias Blockly.Events.utils.BUBBLE_OPEN */ export const BUBBLE_OPEN = 'bubble_open'; /** * Name of event that records a trashcan open. - * - * @alias Blockly.Events.utils.TRASHCAN_OPEN */ export const TRASHCAN_OPEN = 'trashcan_open'; /** * Name of event that records a toolbox item select. - * - * @alias Blockly.Events.utils.TOOLBOX_ITEM_SELECT */ export const TOOLBOX_ITEM_SELECT = 'toolbox_item_select'; /** * Name of event that records a theme change. - * - * @alias Blockly.Events.utils.THEME_CHANGE */ export const THEME_CHANGE = 'theme_change'; /** * Name of event that records a viewport change. - * - * @alias Blockly.Events.utils.VIEWPORT_CHANGE */ export const VIEWPORT_CHANGE = 'viewport_change'; /** * Name of event that creates a comment. - * - * @alias Blockly.Events.utils.COMMENT_CREATE */ export const COMMENT_CREATE = 'comment_create'; /** * Name of event that deletes a comment. - * - * @alias Blockly.Events.utils.COMMENT_DELETE */ export const COMMENT_DELETE = 'comment_delete'; /** * Name of event that changes a comment. - * - * @alias Blockly.Events.utils.COMMENT_CHANGE */ export const COMMENT_CHANGE = 'comment_change'; /** * Name of event that moves a comment. - * - * @alias Blockly.Events.utils.COMMENT_MOVE */ export const COMMENT_MOVE = 'comment_move'; /** * Name of event that records a workspace load. - * - * @alias Blockly.Events.utils.FINISHED_LOADING */ export const FINISHED_LOADING = 'finished_loading'; -/** Name of event that creates a procedure model. */ -export const PROCEDURE_CREATE = 'procedure_create'; - -/** Name of event that deletes a procedure model. */ -export const PROCEDURE_DELETE = 'procedure_delete'; - -/** Name of event that renames a procedure model. */ -export const PROCEDURE_RENAME = 'procedure_rename'; - -/** Name of event that enables/disables a procedure model. */ -export const PROCEDURE_ENABLE = 'procedure_enable'; - -/** Name of event that changes the returntype of a procedure model. */ -export const PROCEDURE_CHANGE_RETURN = 'procedure_change_return'; - -/** Name of event that creates a procedure parameter. */ -export const PROCEDURE_PARAMETER_CREATE = 'procedure_parameter_create'; - -/** Name of event that deletes a procedure parameter. */ -export const PROCEDURE_PARAMETER_DELETE = 'procedure_parameter_delete'; - -/** Name of event that renames a procedure parameter. */ -export const PROCEDURE_PARAMETER_RENAME = 'procedure_parameter_rename'; - /** * Type of events that cause objects to be bumped back into the visible * portion of the workspace. * * Not to be confused with bumping so that disconnected connections do not * appear connected. - * - * @alias Blockly.Events.utils.BumpEvent */ export type BumpEvent = BlockCreate|BlockMove|CommentCreate|CommentMove; @@ -281,8 +195,6 @@ export type BumpEvent = BlockCreate|BlockMove|CommentCreate|CommentMove; * * Not to be confused with bumping so that disconnected connections do not * appear connected. - * - * @alias Blockly.Events.utils.BUMP_EVENTS */ export const BUMP_EVENTS: string[] = [BLOCK_CREATE, BLOCK_MOVE, COMMENT_CREATE, COMMENT_MOVE]; @@ -294,7 +206,6 @@ const FIRE_QUEUE: Abstract[] = []; * Create a custom event and fire it. * * @param event Custom data for event. - * @alias Blockly.Events.utils.fire */ export function fire(event: Abstract) { TEST_ONLY.fireInternal(event); @@ -309,7 +220,17 @@ function fireInternal(event: Abstract) { } if (!FIRE_QUEUE.length) { // First event added; schedule a firing of the event queue. - setTimeout(fireNow, 0); + try { + // If we are in a browser context, we want to make sure that the event + // fires after blocks have been rerendered this frame. + requestAnimationFrame(() => { + setTimeout(fireNow, 0); + }); + } catch (e) { + // Otherwise we just want to delay so events can be coallesced. + // requestAnimationFrame will error triggering this. + setTimeout(fireNow, 0); + } } FIRE_QUEUE.push(event); } @@ -336,7 +257,6 @@ function fireNow() { * @param queueIn Array of events. * @param forward True if forward (redo), false if backward (undo). * @returns Array of filtered events. - * @alias Blockly.Events.utils.filter */ export function filter(queueIn: Abstract[], forward: boolean): Abstract[] { let queue = queueIn.slice(); @@ -419,8 +339,6 @@ export function filter(queueIn: Abstract[], forward: boolean): Abstract[] { /** * Modify pending undo events so that when they are fired they don't land * in the undo stack. Called by Workspace.clearUndo. - * - * @alias Blockly.Events.utils.clearPendingUndo */ export function clearPendingUndo() { for (let i = 0, event; event = FIRE_QUEUE[i]; i++) { @@ -430,8 +348,6 @@ export function clearPendingUndo() { /** * Stop sending events. Every call to this function MUST also call enable. - * - * @alias Blockly.Events.utils.disable */ export function disable() { disabled++; @@ -440,8 +356,6 @@ export function disable() { /** * Start sending events. Unless events were already disabled when the * corresponding call to disable was made. - * - * @alias Blockly.Events.utils.enable */ export function enable() { disabled--; @@ -451,7 +365,6 @@ export function enable() { * Returns whether events may be fired or not. * * @returns True if enabled. - * @alias Blockly.Events.utils.isEnabled */ export function isEnabled(): boolean { return disabled === 0; @@ -461,7 +374,6 @@ export function isEnabled(): boolean { * Current group. * * @returns ID string. - * @alias Blockly.Events.utils.getGroup */ export function getGroup(): string { return group; @@ -472,7 +384,6 @@ export function getGroup(): string { * * @param state True to start new group, false to end group. * String to set group explicitly. - * @alias Blockly.Events.utils.setGroup */ export function setGroup(state: boolean|string) { TEST_ONLY.setGroupInternal(state); @@ -494,7 +405,6 @@ function setGroupInternal(state: boolean|string) { * * @param block The root block. * @returns List of block IDs. - * @alias Blockly.Events.utils.getDescendantIds * @internal */ export function getDescendantIds(block: Block): string[] { @@ -513,7 +423,6 @@ export function getDescendantIds(block: Block): string[] { * @param workspace Target workspace for event. * @returns The event represented by the JSON. * @throws {Error} if an event type is not found in the registry. - * @alias Blockly.Events.utils.fromJson */ export function fromJson( json: AnyDuringMigration, workspace: Workspace): Abstract { @@ -550,7 +459,6 @@ function eventClassHasStaticFromJson(eventClass: new (...p: any[]) => Abstract): * * @param eventType The type of the event to get. * @returns The event class with the given type. - * @alias Blockly.Events.utils.get */ export function get(eventType: string): (new (...p1: AnyDuringMigration[]) => Abstract) { @@ -568,7 +476,6 @@ export function get(eventType: string): * users don't try to re-enable disabled orphan blocks. * * @param event Custom data for event. - * @alias Blockly.Events.utils.disableOrphans */ export function disableOrphans(event: Abstract) { if (event.type === MOVE || event.type === CREATE) { diff --git a/core/events/workspace_events.ts b/core/events/workspace_events.ts index 95b533d54..30fab99b7 100644 --- a/core/events/workspace_events.ts +++ b/core/events/workspace_events.ts @@ -19,12 +19,8 @@ import * as eventUtils from './utils.js'; /** - * Class for a finished loading event. - * Used to notify the developer when the workspace has finished loading (i.e - * domToWorkspace). - * Finished loading events do not record undo or redo. - * - * @alias Blockly.Events.FinishedLoading + * Notifies listeners when the workspace has finished deserializing from + * JSON/XML. */ export class FinishedLoading extends AbstractEvent { override isBlank = true; @@ -37,12 +33,10 @@ export class FinishedLoading extends AbstractEvent { */ constructor(opt_workspace?: Workspace) { super(); - /** Whether or not the event is blank (to be populated by fromJson). */ this.isBlank = !!opt_workspace; if (!opt_workspace) return; - /** The workspace identifier for this event. */ this.workspaceId = opt_workspace.id; } diff --git a/core/extensions.ts b/core/extensions.ts index c30cb314a..20e1ed47e 100644 --- a/core/extensions.ts +++ b/core/extensions.ts @@ -4,14 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Extensions are functions that help initialize blocks, usually - * adding dynamic behavior such as onchange handlers and mutators. These - * are applied using Block.applyExtension(), or the JSON "extensions" - * array attribute. - * - * @namespace Blockly.Extensions - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Extensions'); @@ -36,7 +28,6 @@ export const TEST_ONLY = {allExtensions}; * @param initFn The function to initialize an extended block. * @throws {Error} if the extension name is empty, the extension is already * registered, or extensionFn is not a function. - * @alias Blockly.Extensions.register */ export function register(name: string, initFn: Function) { if (typeof name !== 'string' || name.trim() === '') { @@ -58,7 +49,6 @@ export function register(name: string, initFn: Function) { * @param mixinObj The values to mix in. * @throws {Error} if the extension name is empty or the extension is already * registered. - * @alias Blockly.Extensions.registerMixin */ export function registerMixin(name: string, mixinObj: AnyDuringMigration) { if (!mixinObj || typeof mixinObj !== 'object') { @@ -81,7 +71,6 @@ export function registerMixin(name: string, mixinObj: AnyDuringMigration) { * @param opt_blockList A list of blocks to appear in the flyout of the mutator * dialog. * @throws {Error} if the mutation is invalid or can't be applied to the block. - * @alias Blockly.Extensions.registerMutator */ export function registerMutator( name: string, mixinObj: AnyDuringMigration, @@ -113,7 +102,6 @@ export function registerMutator( * Unregisters the extension registered with the given name. * * @param name The name of the extension to unregister. - * @alias Blockly.Extensions.unregister */ export function unregister(name: string) { if (isRegistered(name)) { @@ -129,7 +117,6 @@ export function unregister(name: string) { * * @param name The name of the extension to check for. * @returns True if the extension is registered. False if it is not registered. - * @alias Blockly.Extensions.isRegistered */ export function isRegistered(name: string): boolean { return !!allExtensions[name]; @@ -143,7 +130,6 @@ export function isRegistered(name: string): boolean { * @param block The block to apply the named extension to. * @param isMutator True if this extension defines a mutator. * @throws {Error} if the extension is not found. - * @alias Blockly.Extensions.apply */ export function apply(name: string, block: Block, isMutator: boolean) { const extensionFn = allExtensions[name]; @@ -387,7 +373,6 @@ export function runAfterPageLoad(fn: () => void) { * lookup table. * @param lookupTable The table of field values to tooltip text. * @returns The extension function. - * @alias Blockly.Extensions.buildTooltipForDropdown */ export function buildTooltipForDropdown( dropdownName: string, lookupTable: {[key: string]: string}): Function { @@ -470,7 +455,6 @@ function checkDropdownOptionsInTable( * placeholder. * @param fieldName The field with the replacement text. * @returns The extension function. - * @alias Blockly.Extensions.buildTooltipWithFieldText */ export function buildTooltipWithFieldText( msgTemplate: string, fieldName: string): Function { diff --git a/core/field.ts b/core/field.ts index cf9148e1c..eda991fe4 100644 --- a/core/field.ts +++ b/core/field.ts @@ -35,7 +35,6 @@ import type {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; import {Rect} from './utils/rect.js'; -import {Sentinel} from './utils/sentinel.js'; import {Size} from './utils/size.js'; import * as style from './utils/style.js'; import {Svg} from './utils/svg.js'; @@ -43,14 +42,28 @@ import * as userAgent from './utils/useragent.js'; import * as utilsXml from './utils/xml.js'; import * as WidgetDiv from './widgetdiv.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -import * as Xml from './xml.js'; -export type FieldValidator = (value?: T) => T|null|undefined; +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldValidator = (newValue: T) => T|null|undefined; /** * Abstract class for an editable field. * - * @alias Blockly.Field + * @typeParam T - The value stored on the field. */ export abstract class Field implements IASTNodeLocationSvg, IASTNodeLocationWithBlock, @@ -75,7 +88,7 @@ export abstract class Field implements IASTNodeLocationSvg, * field's value or run configure_, and should allow a subclass to do that * instead. */ - static readonly SKIP_SETUP = new Sentinel(); + static readonly SKIP_SETUP = Symbol('SKIP_SETUP'); /** * Name of field. Unique within each block. @@ -186,16 +199,16 @@ export abstract class Field implements IASTNodeLocationSvg, * Also accepts Field.SKIP_SETUP if you wish to skip setup (only used by * subclasses that want to handle configuration and setting the field value * after their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a value & returns a validated value, or null to * abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * Refer to the individual field's documentation for a list of properties * this parameter supports. */ constructor( - value: T|Sentinel, opt_validator?: FieldValidator|null, - opt_config?: FieldConfig) { + value: T|typeof Field.SKIP_SETUP, validator?: FieldValidator|null, + config?: FieldConfig) { /** * A generic value possessed by the field. * Should generally be non-null, only null when the field is created. @@ -207,15 +220,13 @@ export abstract class Field implements IASTNodeLocationSvg, /** The size of the area rendered by the field. */ this.size_ = new Size(0, 0); - if (value === Field.SKIP_SETUP) { - return; - } - if (opt_config) { - this.configure_(opt_config); + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } this.setValue(value); - if (opt_validator) { - this.setValidator(opt_validator); + if (validator) { + this.setValidator(validator); } } @@ -372,7 +383,8 @@ export abstract class Field implements IASTNodeLocationSvg, * @internal */ fromXml(fieldElement: Element) { - this.setValue(fieldElement.textContent); + // Any because gremlins live here. No touchie! + this.setValue(fieldElement.textContent as any); } /** @@ -384,7 +396,8 @@ export abstract class Field implements IASTNodeLocationSvg, * @internal */ toXml(fieldElement: Element): Element { - fieldElement.textContent = this.getValue(); + // Any because gremlins live here. No touchie! + fieldElement.textContent = this.getValue() as any; return fieldElement; } @@ -434,7 +447,7 @@ export abstract class Field implements IASTNodeLocationSvg, callingClass.prototype.toXml !== this.toXml) { const elem = utilsXml.createElement('field'); elem.setAttribute('name', this.name || ''); - const text = Xml.domToText(this.toXml(elem)); + const text = utilsXml.domToText(this.toXml(elem)); return text.replace( ' xmlns="https://developers.google.com/blockly/xml"', ''); } @@ -456,7 +469,7 @@ export abstract class Field implements IASTNodeLocationSvg, boolean { if (callingClass.prototype.loadState === this.loadState && callingClass.prototype.fromXml !== this.fromXml) { - this.fromXml(Xml.textToDom(state as string)); + this.fromXml(utilsXml.textToDom(state as string)); return true; } // Either they called this on purpose from their loadState, or they have @@ -472,14 +485,11 @@ export abstract class Field implements IASTNodeLocationSvg, dispose() { dropDownDiv.hideIfOwner(this); WidgetDiv.hideIfOwner(this); - Tooltip.unbindMouseEvents(this.getClickTarget_()); - if (this.mouseDownWrapper_) { - browserEvents.unbind(this.mouseDownWrapper_); + if (!this.getSourceBlock()?.isDeadOrDying()) { + dom.removeNode(this.fieldGroup_); } - dom.removeNode(this.fieldGroup_); - this.disposed = true; } @@ -619,7 +629,7 @@ export abstract class Field implements IASTNodeLocationSvg, * * @returns Validation function, or null. */ - getValidator(): Function|null { + getValidator(): FieldValidator|null { return this.validator_; } @@ -698,14 +708,14 @@ export abstract class Field implements IASTNodeLocationSvg, * Calls showEditor_ when the field is clicked if the field is clickable. * Do not override. * - * @param opt_e Optional mouse event that triggered the field to open, or + * @param e Optional mouse event that triggered the field to open, or * undefined if triggered programmatically. * @sealed * @internal */ - showEditor(opt_e?: Event) { + showEditor(e?: Event) { if (this.isClickable()) { - this.showEditor_(opt_e); + this.showEditor_(e); } } @@ -722,11 +732,11 @@ export abstract class Field implements IASTNodeLocationSvg, /** * Updates the size of the field based on the text. * - * @param opt_margin margin to use when positioning the text element. + * @param margin margin to use when positioning the text element. */ - protected updateSize_(opt_margin?: number) { + protected updateSize_(margin?: number) { const constants = this.getConstants(); - const xOffset = opt_margin !== undefined ? opt_margin : + const xOffset = margin !== undefined ? margin : this.borderRect_ ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING : 0; let totalWidth = xOffset * 2; @@ -766,17 +776,17 @@ export abstract class Field implements IASTNodeLocationSvg, this.textElement_.setAttribute( 'x', - `${ + String( this.getSourceBlock()?.RTL ? this.size_.width - contentWidth - xOffset : - xOffset}`); + xOffset)); this.textElement_.setAttribute( 'y', - `${ + String( constants!.FIELD_TEXT_BASELINE_CENTER ? halfHeight : halfHeight - constants!.FIELD_TEXT_HEIGHT / 2 + - constants!.FIELD_TEXT_BASELINE}`); + constants!.FIELD_TEXT_BASELINE)); } /** Position a field's border rect after a size change. */ @@ -784,12 +794,12 @@ export abstract class Field implements IASTNodeLocationSvg, if (!this.borderRect_) { return; } - this.borderRect_.setAttribute('width', `${this.size_.width}`); - this.borderRect_.setAttribute('height', `${this.size_.height}`); + this.borderRect_.setAttribute('width', String(this.size_.width)); + this.borderRect_.setAttribute('height', String(this.size_.height)); this.borderRect_.setAttribute( - 'rx', `${this.getConstants()!.FIELD_BORDER_RECT_RADIUS}`); + 'rx', String(this.getConstants()!.FIELD_BORDER_RECT_RADIUS)); this.borderRect_.setAttribute( - 'ry', `${this.getConstants()!.FIELD_BORDER_RECT_RADIUS}`); + 'ry', String(this.getConstants()!.FIELD_BORDER_RECT_RADIUS)); } /** @@ -943,9 +953,8 @@ export abstract class Field implements IASTNodeLocationSvg, forceRerender() { this.isDirty_ = true; if (this.sourceBlock_ && this.sourceBlock_.rendered) { - (this.sourceBlock_ as BlockSvg).render(); + (this.sourceBlock_ as BlockSvg).queueRender(); (this.sourceBlock_ as BlockSvg).bumpNeighbours(); - this.updateMarkers_(); } } @@ -965,41 +974,37 @@ export abstract class Field implements IASTNodeLocationSvg, return; } - let validatedValue = this.doClassValidation_(newValue); - // Class validators might accidentally forget to return, we'll ignore that. - newValue = this.processValidation_(newValue, validatedValue); - if (newValue instanceof Error) { + const classValidation = this.doClassValidation_(newValue); + const classValue = this.processValidation_(newValue, classValidation); + if (classValue instanceof Error) { doLogging && console.log('invalid class validation, return'); return; } - const localValidator = this.getValidator(); - if (localValidator) { - validatedValue = localValidator.call(this, newValue); - // Local validators might accidentally forget to return, we'll ignore - // that. - newValue = this.processValidation_(newValue, validatedValue); - if (newValue instanceof Error) { - doLogging && console.log('invalid local validation, return'); - return; - } + const localValidation = this.getValidator()?.call(this, classValue); + const localValue = this.processValidation_(classValue, localValidation); + if (localValue instanceof Error) { + doLogging && console.log('invalid local validation, return'); + return; } + const source = this.sourceBlock_; if (source && source.disposed) { doLogging && console.log('source disposed, return'); return; } + const oldValue = this.getValue(); - if (oldValue === newValue) { + if (oldValue === localValue) { doLogging && console.log('same, doValueUpdate_, return'); - this.doValueUpdate_(newValue); + this.doValueUpdate_(localValue); return; } - this.doValueUpdate_(newValue); + this.doValueUpdate_(localValue); if (source && eventUtils.isEnabled()) { eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))( - source, 'field', this.name || null, oldValue, newValue)); + source, 'field', this.name || null, oldValue, localValue)); } if (this.isDirty_) { this.forceRerender(); @@ -1015,8 +1020,7 @@ export abstract class Field implements IASTNodeLocationSvg, * @returns New value, or an Error object. */ private processValidation_( - newValue: AnyDuringMigration, - validatedValue: AnyDuringMigration): AnyDuringMigration { + newValue: AnyDuringMigration, validatedValue: T|null|undefined): T|Error { if (validatedValue === null) { this.doValueInvalid_(newValue); if (this.isDirty_) { @@ -1024,10 +1028,7 @@ export abstract class Field implements IASTNodeLocationSvg, } return Error(); } - if (validatedValue !== undefined) { - newValue = validatedValue; - } - return newValue; + return validatedValue === undefined ? newValue as T : validatedValue; } /** @@ -1035,23 +1036,39 @@ export abstract class Field implements IASTNodeLocationSvg, * * @returns Current value. */ - getValue(): AnyDuringMigration { + getValue(): T|null { return this.value_; } /** - * Used to validate a value. Returns input by default. Can be overridden by - * subclasses, see FieldDropdown. + * Validate the changes to a field's value before they are set. See + * **FieldDropdown** for an example of subclass implementation. * - * @param opt_newValue The value to be validated. - * @returns The validated value, same as input by default. + * **NOTE:** Validation returns one option between `T`, `null`, and + * `undefined`. **Field**'s implementation will never return `undefined`, but + * it is valid for a subclass to return `undefined` if the new value is + * compatible with `T`. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue - The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. */ - protected doClassValidation_(opt_newValue?: AnyDuringMigration): - AnyDuringMigration { - if (opt_newValue === null || opt_newValue === undefined) { + protected doClassValidation_(newValue: T): T|null|undefined; + protected doClassValidation_(newValue?: AnyDuringMigration): T|null; + protected doClassValidation_(newValue?: T|AnyDuringMigration): T|null + |undefined { + if (newValue === null || newValue === undefined) { return null; } - return opt_newValue; + + return newValue as T; } /** @@ -1060,7 +1077,7 @@ export abstract class Field implements IASTNodeLocationSvg, * * @param newValue The value to be saved. */ - protected doValueUpdate_(newValue: AnyDuringMigration) { + protected doValueUpdate_(newValue: T) { this.value_ = newValue; this.isDirty_ = true; } @@ -1086,7 +1103,7 @@ export abstract class Field implements IASTNodeLocationSvg, } const gesture = (this.sourceBlock_.workspace as WorkspaceSvg).getGesture(e); if (gesture) { - gesture.setStartField(this as Field); + gesture.setStartField(this); } } @@ -1261,8 +1278,12 @@ export abstract class Field implements IASTNodeLocationSvg, this.markerSvg_ = markerSvg; } - /** Redraw any attached marker or cursor svgs if needed. */ - protected updateMarkers_() { + /** + * Redraw any attached marker or cursor svgs if needed. + * + * @internal + */ + updateMarkers_() { const block = this.getSourceBlock(); if (!block) { throw new UnattachedFieldError(); @@ -1288,6 +1309,8 @@ export interface FieldConfig { /** * For use by Field and descendants of Field. Constructors can change * in descendants, though they should contain all of Field's prototype methods. + * + * @internal */ export type FieldProto = Pick; diff --git a/core/field_angle.ts b/core/field_angle.ts index 448147c65..e5fbbf35a 100644 --- a/core/field_angle.ts +++ b/core/field_angle.ts @@ -20,30 +20,24 @@ import {Field, UnattachedFieldError} from './field.js'; import * as fieldRegistry from './field_registry.js'; import {FieldInput, FieldInputConfig, FieldInputValidator} from './field_input.js'; import * as dom from './utils/dom.js'; -import {KeyCodes} from './utils/keycodes.js'; import * as math from './utils/math.js'; -import type {Sentinel} from './utils/sentinel.js'; import {Svg} from './utils/svg.js'; import * as userAgent from './utils/useragent.js'; import * as WidgetDiv from './widgetdiv.js'; -export type FieldAngleValidator = FieldInputValidator; - /** * Class for an editable angle field. - * - * @alias Blockly.FieldAngle */ export class FieldAngle extends FieldInput { - /** - * The default amount to round angles to when using a mouse or keyboard nav - * input. Must be a positive integer to support keyboard navigation. - */ - static readonly ROUND = 15; - /** Half the width of protractor image. */ static readonly HALF = 100 / 2; + /** + * Radius of protractor circle. Slightly smaller than protractor size since + * otherwise SVG crops off half the border at the edges. + */ + static readonly RADIUS: number = FieldAngle.HALF - 1; + /** * Default property describing which direction makes an angle field's value * increase. Angle increases clockwise (true) or counterclockwise (false). @@ -64,88 +58,73 @@ export class FieldAngle extends FieldInput { static readonly WRAP = 360; /** - * Radius of protractor circle. Slightly smaller than protractor size since - * otherwise SVG crops off half the border at the edges. + * The default amount to round angles to when using a mouse or keyboard nav + * input. Must be a positive integer to support keyboard navigation. */ - static readonly RADIUS: number = FieldAngle.HALF - 1; + static readonly ROUND = 15; /** * Whether the angle should increase as the angle picker is moved clockwise * (true) or counterclockwise (false). */ - private clockwise_ = FieldAngle.CLOCKWISE; + private clockwise = FieldAngle.CLOCKWISE; /** * The offset of zero degrees (and all other angles). */ - private offset_ = FieldAngle.OFFSET; + private offset = FieldAngle.OFFSET; /** * The maximum angle to allow before wrapping. */ - private wrap_ = FieldAngle.WRAP; + private wrap = FieldAngle.WRAP; /** * The amount to round angles to when using a mouse or keyboard nav input. */ - private round_ = FieldAngle.ROUND; + private round = FieldAngle.ROUND; - /** The angle picker's SVG element. */ - private editor_: SVGSVGElement|null = null; + /** + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. + */ + private boundEvents: browserEvents.Data[] = []; - /** The angle picker's gauge path depending on the value. */ - gauge_: SVGPathElement|null = null; + /** Dynamic red line pointing at the value's angle. */ + private line: SVGLineElement|null = null; - /** The angle picker's line drawn representing the value's angle. */ - line_: SVGLineElement|null = null; + /** Dynamic pink area extending from 0 to the value's angle. */ + private gauge: SVGPathElement|null = null; /** The degree symbol for this field. */ - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'SVGTSpanElement'. - protected symbol_: SVGTSpanElement = null as AnyDuringMigration; - - /** Wrapper click event data. */ - private clickWrapper_: browserEvents.Data|null = null; - - /** Surface click event data. */ - private clickSurfaceWrapper_: browserEvents.Data|null = null; - - /** Surface mouse move event data. */ - private moveSurfaceWrapper_: browserEvents.Data|null = null; + protected symbol_: SVGTSpanElement|null = null; /** - * Serializable fields are saved by the serializer, non-serializable fields - * are not. Editable fields should also be serializable. - */ - override SERIALIZABLE = true; - - /** - * @param opt_value The initial value of the field. Should cast to a number. + * @param value The initial value of the field. Should cast to a number. * Defaults to 0. Also accepts Field.SKIP_SETUP if you wish to skip setup * (only used by subclasses that want to handle configuration and setting * the field value after their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a number & returns a validated number, or null * to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/angle#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|number|Sentinel, opt_validator?: FieldAngleValidator, - opt_config?: FieldAngleConfig) { + value?: string|number|typeof Field.SKIP_SETUP, + validator?: FieldAngleValidator, config?: FieldAngleConfig) { super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } - if (opt_config) { - this.configure_(opt_config); - } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } @@ -159,22 +138,22 @@ export class FieldAngle extends FieldInput { switch (config.mode) { case Mode.COMPASS: - this.clockwise_ = true; - this.offset_ = 90; + this.clockwise = true; + this.offset = 90; break; case Mode.PROTRACTOR: // This is the default mode, so we could do nothing. But just to // future-proof, we'll set it anyway. - this.clockwise_ = false; - this.offset_ = 0; + this.clockwise = false; + this.offset = 0; break; } // Allow individual settings to override the mode setting. - if (config.clockwise) this.clockwise_ = config.clockwise; - if (config.offset) this.offset_ = config.offset; - if (config.wrap) this.wrap_ = config.wrap; - if (config.round) this.round_ = config.round; + if (config.clockwise) this.clockwise = config.clockwise; + if (config.offset) this.offset = config.offset; + if (config.wrap) this.wrap = config.wrap; + if (config.round) this.round = config.round; } /** @@ -184,32 +163,32 @@ export class FieldAngle extends FieldInput { */ override initView() { super.initView(); - // Add the degree symbol to the left of the number, even in RTL (issue - // #2380) + // Add the degree symbol to the left of the number, + // even in RTL (issue #2380). this.symbol_ = dom.createSvgElement(Svg.TSPAN, {}); this.symbol_.appendChild(document.createTextNode('°')); this.getTextElement().appendChild(this.symbol_); } - /** Updates the graph when the field rerenders. */ + /** Updates the angle when the field rerenders. */ protected override render_() { super.render_(); - this.updateGraph_(); + this.updateGraph(); } /** * Create and show the angle field's editor. * - * @param opt_e Optional mouse event that triggered the field to open, or - * undefined if triggered programmatically. + * @param e Optional mouse event that triggered the field to open, + * or undefined if triggered programmatically. */ - protected override showEditor_(opt_e?: Event) { + protected override showEditor_(e?: Event) { // Mobile browsers have issues with in-line textareas (focus & keyboards). const noFocus = userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD; - super.showEditor_(opt_e, noFocus); + super.showEditor_(e, noFocus); - this.dropdownCreate_(); - dropDownDiv.getContentDiv().appendChild(this.editor_!); + const editor = this.dropdownCreate(); + dropDownDiv.getContentDiv().appendChild(editor); if (this.sourceBlock_ instanceof BlockSvg) { dropDownDiv.setColour( @@ -217,16 +196,17 @@ export class FieldAngle extends FieldInput { this.sourceBlock_.style.colourTertiary); } - // AnyDuringMigration because: Argument of type 'this' is not assignable to - // parameter of type 'Field'. - dropDownDiv.showPositionedByField( - this as AnyDuringMigration, this.dropdownDispose_.bind(this)); + dropDownDiv.showPositionedByField(this, this.dropdownDispose.bind(this)); - this.updateGraph_(); + this.updateGraph(); } - /** Create the angle dropdown editor. */ - private dropdownCreate_() { + /** + * Creates the angle dropdown editor. + * + * @returns The newly created slider. + */ + private dropdownCreate(): SVGSVGElement { const svg = dom.createSvgElement(Svg.SVG, { 'xmlns': dom.SVG_NS, 'xmlns:html': dom.HTML_NS, @@ -244,9 +224,9 @@ export class FieldAngle extends FieldInput { 'class': 'blocklyAngleCircle', }, svg); - this.gauge_ = + this.gauge = dom.createSvgElement(Svg.PATH, {'class': 'blocklyAngleGauge'}, svg); - this.line_ = dom.createSvgElement( + this.line = dom.createSvgElement( Svg.LINE, { 'x1': FieldAngle.HALF, 'y1': FieldAngle.HALF, @@ -272,38 +252,30 @@ export class FieldAngle extends FieldInput { // The angle picker is different from other fields in that it updates on // mousemove even if it's not in the middle of a drag. In future we may // change this behaviour. - this.clickWrapper_ = - browserEvents.conditionalBind(svg, 'click', this, this.hide_); + this.boundEvents.push( + browserEvents.conditionalBind(svg, 'click', this, this.hide)); // On touch devices, the picker's value is only updated with a drag. Add // a click handler on the drag surface to update the value if the surface // is clicked. - this.clickSurfaceWrapper_ = browserEvents.conditionalBind( - circle, 'pointerdown', this, this.onMouseMove_, true); - this.moveSurfaceWrapper_ = browserEvents.conditionalBind( - circle, 'pointermove', this, this.onMouseMove_, true); - this.editor_ = svg; + this.boundEvents.push(browserEvents.conditionalBind( + circle, 'pointerdown', this, this.onMouseMove_, true)); + this.boundEvents.push(browserEvents.conditionalBind( + circle, 'pointermove', this, this.onMouseMove_, true)); + return svg; } /** Disposes of events and DOM-references belonging to the angle editor. */ - private dropdownDispose_() { - if (this.clickWrapper_) { - browserEvents.unbind(this.clickWrapper_); - this.clickWrapper_ = null; + private dropdownDispose() { + for (const event of this.boundEvents) { + browserEvents.unbind(event); } - if (this.clickSurfaceWrapper_) { - browserEvents.unbind(this.clickSurfaceWrapper_); - this.clickSurfaceWrapper_ = null; - } - if (this.moveSurfaceWrapper_) { - browserEvents.unbind(this.moveSurfaceWrapper_); - this.moveSurfaceWrapper_ = null; - } - this.gauge_ = null; - this.line_ = null; + this.boundEvents.length = 0; + this.gauge = null; + this.line = null; } /** Hide the editor. */ - private hide_() { + private hide() { dropDownDiv.hideIfOwner(this); WidgetDiv.hide(); } @@ -315,7 +287,7 @@ export class FieldAngle extends FieldInput { */ protected onMouseMove_(e: PointerEvent) { // Calculate angle. - const bBox = this.gauge_!.ownerSVGElement!.getBoundingClientRect(); + const bBox = this.gauge!.ownerSVGElement!.getBoundingClientRect(); const dx = e.clientX - bBox.left - FieldAngle.HALF; const dy = e.clientY - bBox.top - FieldAngle.HALF; let angle = Math.atan(-dy / dx); @@ -332,13 +304,13 @@ export class FieldAngle extends FieldInput { } // Do offsetting. - if (this.clockwise_) { - angle = this.offset_ + 360 - angle; + if (this.clockwise) { + angle = this.offset + 360 - angle; } else { - angle = 360 - (this.offset_ - angle); + angle = 360 - (this.offset - angle); } - this.displayMouseOrKeyboardValue_(angle); + this.displayMouseOrKeyboardValue(angle); } /** @@ -348,31 +320,31 @@ export class FieldAngle extends FieldInput { * * @param angle New angle. */ - private displayMouseOrKeyboardValue_(angle: number) { - if (this.round_) { - angle = Math.round(angle / this.round_) * this.round_; + private displayMouseOrKeyboardValue(angle: number) { + if (this.round) { + angle = Math.round(angle / this.round) * this.round; } - angle = this.wrapValue_(angle); + angle = this.wrapValue(angle); if (angle !== this.value_) { this.setEditorValue_(angle); } } /** Redraw the graph with the current angle. */ - private updateGraph_() { - if (!this.gauge_) { + private updateGraph() { + if (!this.gauge || !this.line) { return; } // Always display the input (i.e. getText) even if it is invalid. - let angleDegrees = Number(this.getText()) + this.offset_; + let angleDegrees = Number(this.getText()) + this.offset; angleDegrees %= 360; let angleRadians = math.toRadians(angleDegrees); const path = ['M ', FieldAngle.HALF, ',', FieldAngle.HALF]; let x2 = FieldAngle.HALF; let y2 = FieldAngle.HALF; if (!isNaN(angleRadians)) { - const clockwiseFlag = Number(this.clockwise_); - const angle1 = math.toRadians(this.offset_); + const clockwiseFlag = Number(this.clockwise); + const angle1 = math.toRadians(this.offset); const x1 = Math.cos(angle1) * FieldAngle.RADIUS; const y1 = Math.sin(angle1) * -FieldAngle.RADIUS; if (clockwiseFlag) { @@ -390,13 +362,9 @@ export class FieldAngle extends FieldInput { ' l ', x1, ',', y1, ' A ', FieldAngle.RADIUS, ',', FieldAngle.RADIUS, ' 0 ', largeFlag, ' ', clockwiseFlag, ' ', x2, ',', y2, ' z'); } - this.gauge_.setAttribute('d', path.join('')); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.line_!.setAttribute('x2', x2 as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.line_!.setAttribute('y2', y2 as AnyDuringMigration); + this.gauge.setAttribute('d', path.join('')); + this.line.setAttribute('x2', `${x2}`); + this.line.setAttribute('y2', `${y2}`); } /** @@ -404,31 +372,35 @@ export class FieldAngle extends FieldInput { * * @param e Keyboard event. */ - protected override onHtmlInputKeyDown_(e: Event) { + protected override onHtmlInputKeyDown_(e: KeyboardEvent) { super.onHtmlInputKeyDown_(e); const block = this.getSourceBlock(); if (!block) { throw new UnattachedFieldError(); } - const keyboardEvent = e as KeyboardEvent; - let multiplier; - if (keyboardEvent.keyCode === KeyCodes.LEFT) { - // decrement (increment in RTL) - multiplier = block.RTL ? 1 : -1; - } else if (keyboardEvent.keyCode === KeyCodes.RIGHT) { - // increment (decrement in RTL) - multiplier = block.RTL ? -1 : 1; - } else if (keyboardEvent.keyCode === KeyCodes.DOWN) { - // decrement - multiplier = -1; - } else if (keyboardEvent.keyCode === KeyCodes.UP) { - // increment - multiplier = 1; + let multiplier = 0; + switch (e.key) { + case 'ArrowLeft': + // decrement (increment in RTL) + multiplier = block.RTL ? 1 : -1; + break; + case 'ArrowRight': + // increment (decrement in RTL) + multiplier = block.RTL ? -1 : 1; + break; + case 'ArrowDown': + // decrement + multiplier = -1; + break; + case 'ArrowUp': + // increment + multiplier = 1; + break; } if (multiplier) { const value = this.getValue() as number; - this.displayMouseOrKeyboardValue_(value + multiplier * this.round_); + this.displayMouseOrKeyboardValue(value + multiplier * this.round); e.preventDefault(); e.stopPropagation(); } @@ -437,16 +409,15 @@ export class FieldAngle extends FieldInput { /** * Ensure that the input value is a valid angle. * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid angle, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - number|null { - const value = Number(opt_newValue); + protected override doClassValidation_(newValue?: any): number|null { + const value = Number(newValue); if (isNaN(value) || !isFinite(value)) { return null; } - return this.wrapValue_(value); + return this.wrapValue(value); } /** @@ -455,12 +426,12 @@ export class FieldAngle extends FieldInput { * @param value The value to wrap. * @returns The wrapped value. */ - private wrapValue_(value: number): number { + private wrapValue(value: number): number { value %= 360; if (value < 0) { value += 360; } - if (value > this.wrap_) { + if (value > this.wrap) { value -= 360; } return value; @@ -481,13 +452,20 @@ export class FieldAngle extends FieldInput { } } -/** CSS for angle field. See css.js for use. */ +fieldRegistry.register('field_angle', FieldAngle); + +FieldAngle.prototype.DEFAULT_VALUE = 0; + + +/** + * CSS for angle field. + */ Css.register(` .blocklyAngleCircle { stroke: #444; stroke-width: 1; fill: #ddd; - fill-opacity: .8; + fill-opacity: 0.8; } .blocklyAngleMarks { @@ -497,7 +475,7 @@ Css.register(` .blocklyAngleGauge { fill: #f88; - fill-opacity: .8; + fill-opacity: 0.8; pointer-events: none; } @@ -509,10 +487,6 @@ Css.register(` } `); -fieldRegistry.register('field_angle', FieldAngle); - -FieldAngle.prototype.DEFAULT_VALUE = 0; - /** * The two main modes of the angle field. * Compass specifies: @@ -549,3 +523,20 @@ export interface FieldAngleConfig extends FieldInputConfig { export interface FieldAngleFromJsonConfig extends FieldAngleConfig { angle?: number; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldAngleValidator = FieldInputValidator; diff --git a/core/field_checkbox.ts b/core/field_checkbox.ts index 1007e1884..3f26d6700 100644 --- a/core/field_checkbox.ts +++ b/core/field_checkbox.ts @@ -18,16 +18,14 @@ import './events/events_block_change.js'; import * as dom from './utils/dom.js'; import {Field, FieldConfig, FieldValidator} from './field.js'; import * as fieldRegistry from './field_registry.js'; -import type {Sentinel} from './utils/sentinel.js'; -export type FieldCheckboxValidator = FieldValidator; +type BoolString = 'TRUE'|'FALSE'; +type CheckboxBool = BoolString|boolean; /** * Class for a checkbox field. - * - * @alias Blockly.FieldCheckbox */ -export class FieldCheckbox extends Field { +export class FieldCheckbox extends Field { /** Default character for the checkmark. */ static readonly CHECK_CHAR = '✓'; private checkChar_: string; @@ -42,26 +40,30 @@ export class FieldCheckbox extends Field { * Mouse cursor style when over the hotspot that initiates editability. */ override CURSOR = 'default'; - override value_: AnyDuringMigration; /** - * @param opt_value The initial value of the field. Should either be 'TRUE', + * NOTE: The default value is set in `Field`, so maintain that value instead + * of overwriting it here or in the constructor. + */ + override value_: boolean|null = this.value_; + + /** + * @param value The initial value of the field. Should either be 'TRUE', * 'FALSE' or a boolean. Defaults to 'FALSE'. Also accepts * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses * that want to handle configuration and setting the field value after * their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a value ('TRUE' or 'FALSE') & returns a * validated value ('TRUE' or 'FALSE'), or null to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/checkbox#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|boolean|Sentinel, - opt_validator?: FieldCheckboxValidator, - opt_config?: FieldCheckboxConfig) { + value?: CheckboxBool|typeof Field.SKIP_SETUP, + validator?: FieldCheckboxValidator, config?: FieldCheckboxConfig) { super(Field.SKIP_SETUP); /** @@ -70,15 +72,13 @@ export class FieldCheckbox extends Field { */ this.checkChar_ = FieldCheckbox.CHECK_CHAR; - if (opt_value === Field.SKIP_SETUP) { - return; + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } - if (opt_config) { - this.configure_(opt_config); - } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } @@ -149,15 +149,15 @@ export class FieldCheckbox extends Field { /** * Ensure that the input value is valid ('TRUE' or 'FALSE'). * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid value ('TRUE' or 'FALSE), or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - string|null { - if (opt_newValue === true || opt_newValue === 'TRUE') { + protected override doClassValidation_(newValue?: AnyDuringMigration): + BoolString|null { + if (newValue === true || newValue === 'TRUE') { return 'TRUE'; } - if (opt_newValue === false || opt_newValue === 'FALSE') { + if (newValue === false || newValue === 'FALSE') { return 'FALSE'; } return null; @@ -169,7 +169,7 @@ export class FieldCheckbox extends Field { * @param newValue The value to be saved. The default validator guarantees * that this is a either 'TRUE' or 'FALSE'. */ - protected override doValueUpdate_(newValue: AnyDuringMigration) { + protected override doValueUpdate_(newValue: BoolString) { this.value_ = this.convertValueToBool_(newValue); // Update visual. if (this.textElement_) { @@ -182,7 +182,7 @@ export class FieldCheckbox extends Field { * * @returns The value of this field. */ - override getValue(): string { + override getValue(): BoolString { return this.value_ ? 'TRUE' : 'FALSE'; } @@ -191,8 +191,8 @@ export class FieldCheckbox extends Field { * * @returns The boolean value of this field. */ - getValueBoolean(): boolean { - return this.value_ as boolean; + getValueBoolean(): boolean|null { + return this.value_; } /** @@ -213,12 +213,9 @@ export class FieldCheckbox extends Field { * @param value The value to convert. * @returns The converted value. */ - private convertValueToBool_(value: AnyDuringMigration): boolean { - if (typeof value === 'string') { - return value === 'TRUE'; - } else { - return !!value; - } + private convertValueToBool_(value: CheckboxBool|null): boolean { + if (typeof value === 'string') return value === 'TRUE'; + return !!value; } /** @@ -253,3 +250,20 @@ export interface FieldCheckboxConfig extends FieldConfig { export interface FieldCheckboxFromJsonConfig extends FieldCheckboxConfig { checked?: boolean; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldCheckboxValidator = FieldValidator; diff --git a/core/field_colour.ts b/core/field_colour.ts index 729ebe54f..87c34b99d 100644 --- a/core/field_colour.ts +++ b/core/field_colour.ts @@ -25,16 +25,10 @@ import * as fieldRegistry from './field_registry.js'; import * as aria from './utils/aria.js'; import * as colour from './utils/colour.js'; import * as idGenerator from './utils/idgenerator.js'; -import {KeyCodes} from './utils/keycodes.js'; -import type {Sentinel} from './utils/sentinel.js'; import {Size} from './utils/size.js'; -export type FieldColourValidator = FieldValidator; - /** * Class for a colour input field. - * - * @alias Blockly.FieldColour */ export class FieldColour extends Field { /** @@ -80,25 +74,17 @@ export class FieldColour extends Field { static COLUMNS = 7; /** The field's colour picker element. */ - private picker_: Element|null = null; + private picker: HTMLElement|null = null; /** Index of the currently highlighted element. */ - private highlightedIndex_: number|null = null; + private highlightedIndex: number|null = null; - /** Mouse click event data. */ - private onClickWrapper_: browserEvents.Data|null = null; - - /** Mouse move event data. */ - private onMouseMoveWrapper_: browserEvents.Data|null = null; - - /** Mouse enter event data. */ - private onMouseEnterWrapper_: browserEvents.Data|null = null; - - /** Mouse leave event data. */ - private onMouseLeaveWrapper_: browserEvents.Data|null = null; - - /** Key down event data. */ - private onKeyDownWrapper_: browserEvents.Data|null = null; + /** + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. + */ + private boundEvents: browserEvents.Data[] = []; /** * Serializable fields are saved by the serializer, non-serializable fields @@ -117,55 +103,46 @@ export class FieldColour extends Field { protected override isDirty_ = false; /** Array of colours used by this field. If null, use the global list. */ - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'string[]'. - private colours_: string[] = null as AnyDuringMigration; + private colours: string[]|null = null; /** * Array of colour tooltips used by this field. If null, use the global * list. */ - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'string[]'. - private titles_: string[] = null as AnyDuringMigration; + private titles: string[]|null = null; /** * Number of colour columns used by this field. If 0, use the global * setting. By default use the global constants for columns. */ - private columns_ = 0; - override size_: AnyDuringMigration; - override clickTarget_: AnyDuringMigration; - override value_: AnyDuringMigration; + private columns = 0; /** - * @param opt_value The initial value of the field. Should be in '#rrggbb' + * @param value The initial value of the field. Should be in '#rrggbb' * format. Defaults to the first value in the default colour array. Also * accepts Field.SKIP_SETUP if you wish to skip setup (only used by * subclasses that want to handle configuration and setting the field * value after their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a colour string & returns a validated colour - * string ('#rrggbb' format), or null to abort the change.Blockly. - * @param opt_config A map of options used to configure the field. + * string ('#rrggbb' format), or null to abort the change. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|Sentinel, opt_validator?: FieldColourValidator, - opt_config?: FieldColourConfig) { + value?: string|typeof Field.SKIP_SETUP, validator?: FieldColourValidator, + config?: FieldColourConfig) { super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } - if (opt_config) { - this.configure_(opt_config); - } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } @@ -176,9 +153,9 @@ export class FieldColour extends Field { */ protected override configure_(config: FieldColourConfig) { super.configure_(config); - if (config.colourOptions) this.colours_ = config.colourOptions; - if (config.colourTitles) this.titles_ = config.colourTitles; - if (config.columns) this.columns_ = config.columns; + if (config.colourOptions) this.colours = config.colourOptions; + if (config.colourTitles) this.titles = config.colourTitles; + if (config.columns) this.columns = config.columns; } /** @@ -198,6 +175,11 @@ export class FieldColour extends Field { } } + /** + * Updates text field to match the colour/style of the block. + * + * @internal + */ override applyColour() { if (!this.getConstants()!.FIELD_COLOUR_FULL_BLOCK) { if (this.borderRect_) { @@ -213,15 +195,14 @@ export class FieldColour extends Field { /** * Ensure that the input value is a valid colour. * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid colour, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - string|null { - if (typeof opt_newValue !== 'string') { + protected override doClassValidation_(newValue?: any): string|null { + if (typeof newValue !== 'string') { return null; } - return colour.parse(opt_newValue); + return colour.parse(newValue); } /** @@ -230,15 +211,14 @@ export class FieldColour extends Field { * @param newValue The value to be saved. The default validator guarantees * that this is a colour in '#rrggbb' format. */ - protected override doValueUpdate_(newValue: AnyDuringMigration) { + protected override doValueUpdate_(newValue: string) { this.value_ = newValue; if (this.borderRect_) { - this.borderRect_.style.fill = newValue as string; + this.borderRect_.style.fill = newValue; } else if ( this.sourceBlock_ && this.sourceBlock_.rendered && this.sourceBlock_ instanceof BlockSvg) { - this.sourceBlock_.pathObject.svgPath.setAttribute( - 'fill', newValue as string); + this.sourceBlock_.pathObject.svgPath.setAttribute('fill', newValue); this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff'); } } @@ -262,14 +242,14 @@ export class FieldColour extends Field { * * @param colours Array of colours for this block, or null to use default * (FieldColour.COLOURS). - * @param opt_titles Optional array of colour tooltips, or null to use default + * @param titles Optional array of colour tooltips, or null to use default * (FieldColour.TITLES). * @returns Returns itself (for method chaining). */ - setColours(colours: string[], opt_titles?: string[]): FieldColour { - this.colours_ = colours; - if (opt_titles) { - this.titles_ = opt_titles; + setColours(colours: string[], titles?: string[]): FieldColour { + this.colours = colours; + if (titles) { + this.titles = titles; } return this; } @@ -282,23 +262,19 @@ export class FieldColour extends Field { * @returns Returns itself (for method chaining). */ setColumns(columns: number): FieldColour { - this.columns_ = columns; + this.columns = columns; return this; } /** Create and show the colour field's editor. */ protected override showEditor_() { - this.dropdownCreate_(); - // AnyDuringMigration because: Argument of type 'Element | null' is not - // assignable to parameter of type 'Node'. - dropDownDiv.getContentDiv().appendChild(this.picker_ as AnyDuringMigration); + this.dropdownCreate(); + dropDownDiv.getContentDiv().appendChild(this.picker!); - dropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this)); + dropDownDiv.showPositionedByField(this, this.dropdownDispose.bind(this)); // Focus so we can start receiving keyboard events. - // AnyDuringMigration because: Property 'focus' does not exist on type - // 'Element'. - (this.picker_ as AnyDuringMigration)!.focus({preventScroll: true}); + this.picker!.focus({preventScroll: true}); } /** @@ -306,7 +282,7 @@ export class FieldColour extends Field { * * @param e Mouse event. */ - private onClick_(e: PointerEvent) { + private onClick(e: PointerEvent) { const cell = e.target as Element; const colour = cell && cell.getAttribute('data-colour'); if (colour !== null) { @@ -321,31 +297,35 @@ export class FieldColour extends Field { * * @param e Keyboard event. */ - private onKeyDown_(e: KeyboardEvent) { - let handled = false; - if (e.keyCode === KeyCodes.UP) { - this.moveHighlightBy_(0, -1); - handled = true; - } else if (e.keyCode === KeyCodes.DOWN) { - this.moveHighlightBy_(0, 1); - handled = true; - } else if (e.keyCode === KeyCodes.LEFT) { - this.moveHighlightBy_(-1, 0); - handled = true; - } else if (e.keyCode === KeyCodes.RIGHT) { - this.moveHighlightBy_(1, 0); - handled = true; - } else if (e.keyCode === KeyCodes.ENTER) { - // Select the highlighted colour. - const highlighted = this.getHighlighted_(); - if (highlighted) { - const colour = highlighted && highlighted.getAttribute('data-colour'); - if (colour !== null) { - this.setValue(colour); + private onKeyDown(e: KeyboardEvent) { + let handled = true; + let highlighted: HTMLElement|null; + switch (e.key) { + case 'ArrowUp': + this.moveHighlightBy(0, -1); + break; + case 'ArrowDown': + this.moveHighlightBy(0, 1); + break; + case 'ArrowLeft': + this.moveHighlightBy(-1, 0); + break; + case 'ArrowRight': + this.moveHighlightBy(1, 0); + break; + case 'Enter': + // Select the highlighted colour. + highlighted = this.getHighlighted(); + if (highlighted) { + const colour = highlighted.getAttribute('data-colour'); + if (colour !== null) { + this.setValue(colour); + } } - } - dropDownDiv.hideWithoutAnimation(); - handled = true; + dropDownDiv.hideWithoutAnimation(); + break; + default: + handled = false; } if (handled) { e.stopPropagation(); @@ -355,22 +335,22 @@ export class FieldColour extends Field { /** * Move the currently highlighted position by dx and dy. * - * @param dx Change of x - * @param dy Change of y + * @param dx Change of x. + * @param dy Change of y. */ - private moveHighlightBy_(dx: number, dy: number) { - if (!this.highlightedIndex_) { + private moveHighlightBy(dx: number, dy: number) { + if (!this.highlightedIndex) { return; } - const colours = this.colours_ || FieldColour.COLOURS; - const columns = this.columns_ || FieldColour.COLUMNS; + const colours = this.colours || FieldColour.COLOURS; + const columns = this.columns || FieldColour.COLUMNS; - // Get the current x and y coordinates - let x = this.highlightedIndex_ % columns; - let y = Math.floor(this.highlightedIndex_ / columns); + // Get the current x and y coordinates. + let x = this.highlightedIndex % columns; + let y = Math.floor(this.highlightedIndex / columns); - // Add the offset + // Add the offset. x += dx; y += dy; @@ -405,9 +385,9 @@ export class FieldColour extends Field { } // Move the highlight to the new coordinates. - const cell = this.picker_!.childNodes[y].childNodes[x] as Element; + const cell = this.picker!.childNodes[y].childNodes[x] as Element; const index = y * columns + x; - this.setHighlightedCell_(cell, index); + this.setHighlightedCell(cell, index); } /** @@ -415,30 +395,26 @@ export class FieldColour extends Field { * * @param e Mouse event. */ - private onMouseMove_(e: PointerEvent) { + private onMouseMove(e: PointerEvent) { const cell = e.target as Element; const index = cell && Number(cell.getAttribute('data-index')); - if (index !== null && index !== this.highlightedIndex_) { - this.setHighlightedCell_(cell, index); + if (index !== null && index !== this.highlightedIndex) { + this.setHighlightedCell(cell, index); } } /** Handle a mouse enter event. Focus the picker. */ - private onMouseEnter_() { - // AnyDuringMigration because: Property 'focus' does not exist on type - // 'Element'. - (this.picker_ as AnyDuringMigration)!.focus({preventScroll: true}); + private onMouseEnter() { + this.picker?.focus({preventScroll: true}); } /** * Handle a mouse leave event. Blur the picker and unhighlight * the currently highlighted colour. */ - private onMouseLeave_() { - // AnyDuringMigration because: Property 'blur' does not exist on type - // 'Element'. - (this.picker_ as AnyDuringMigration)!.blur(); - const highlighted = this.getHighlighted_(); + private onMouseLeave() { + this.picker?.blur(); + const highlighted = this.getHighlighted(); if (highlighted) { dom.removeClass(highlighted, 'blocklyColourHighlighted'); } @@ -449,55 +425,53 @@ export class FieldColour extends Field { * * @returns Highlighted item (null if none). */ - private getHighlighted_(): HTMLElement|null { - if (!this.highlightedIndex_) { + private getHighlighted(): HTMLElement|null { + if (!this.highlightedIndex) { return null; } - const columns = this.columns_ || FieldColour.COLUMNS; - const x = this.highlightedIndex_ % columns; - const y = Math.floor(this.highlightedIndex_ / columns); - const row = this.picker_!.childNodes[y]; + const columns = this.columns || FieldColour.COLUMNS; + const x = this.highlightedIndex % columns; + const y = Math.floor(this.highlightedIndex / columns); + const row = this.picker!.childNodes[y]; if (!row) { return null; } - const col = row.childNodes[x] as HTMLElement; - return col; + return row.childNodes[x] as HTMLElement; } /** * Update the currently highlighted cell. * - * @param cell the new cell to highlight - * @param index the index of the new cell + * @param cell The new cell to highlight. + * @param index The index of the new cell. */ - private setHighlightedCell_(cell: Element, index: number) { + private setHighlightedCell(cell: Element, index: number) { // Unhighlight the current item. - const highlighted = this.getHighlighted_(); + const highlighted = this.getHighlighted(); if (highlighted) { dom.removeClass(highlighted, 'blocklyColourHighlighted'); } // Highlight new item. dom.addClass(cell, 'blocklyColourHighlighted'); // Set new highlighted index. - this.highlightedIndex_ = index; + this.highlightedIndex = index; // Update accessibility roles. - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string | number | boolean | string[]'. - aria.setState( - this.picker_ as Element, aria.State.ACTIVEDESCENDANT, - cell.getAttribute('id') as AnyDuringMigration); + const cellId = cell.getAttribute('id'); + if (cellId && this.picker) { + aria.setState(this.picker, aria.State.ACTIVEDESCENDANT, cellId); + } } /** Create a colour picker dropdown editor. */ - private dropdownCreate_() { - const columns = this.columns_ || FieldColour.COLUMNS; - const colours = this.colours_ || FieldColour.COLOURS; - const titles = this.titles_ || FieldColour.TITLES; + private dropdownCreate() { + const columns = this.columns || FieldColour.COLUMNS; + const colours = this.colours || FieldColour.COLOURS; + const titles = this.titles || FieldColour.TITLES; const selectedColour = this.getValue(); // Create the palette. - const table = (document.createElement('table')); + const table = document.createElement('table'); table.className = 'blocklyColourTable'; table.tabIndex = 0; table.dir = 'ltr'; @@ -519,58 +493,40 @@ export class FieldColour extends Field { cell.setAttribute('data-colour', colours[i]); cell.title = titles[i] || colours[i]; cell.id = idGenerator.getNextUniqueId(); - // AnyDuringMigration because: Argument of type 'number' is not - // assignable to parameter of type 'string'. - cell.setAttribute('data-index', i as AnyDuringMigration); + cell.setAttribute('data-index', `${i}`); aria.setRole(cell, aria.Role.GRIDCELL); aria.setState(cell, aria.State.LABEL, colours[i]); aria.setState(cell, aria.State.SELECTED, colours[i] === selectedColour); cell.style.backgroundColor = colours[i]; if (colours[i] === selectedColour) { cell.className = 'blocklyColourSelected'; - this.highlightedIndex_ = i; + this.highlightedIndex = i; } } // Configure event handler on the table to listen for any event in a cell. - this.onClickWrapper_ = browserEvents.conditionalBind( - table, 'pointerdown', this, this.onClick_, true); - this.onMouseMoveWrapper_ = browserEvents.conditionalBind( - table, 'pointermove', this, this.onMouseMove_, true); - this.onMouseEnterWrapper_ = browserEvents.conditionalBind( - table, 'pointerenter', this, this.onMouseEnter_, true); - this.onMouseLeaveWrapper_ = browserEvents.conditionalBind( - table, 'pointerleave', this, this.onMouseLeave_, true); - this.onKeyDownWrapper_ = - browserEvents.conditionalBind(table, 'keydown', this, this.onKeyDown_); + this.boundEvents.push(browserEvents.conditionalBind( + table, 'pointerdown', this, this.onClick, true)); + this.boundEvents.push(browserEvents.conditionalBind( + table, 'pointermove', this, this.onMouseMove, true)); + this.boundEvents.push(browserEvents.conditionalBind( + table, 'pointerenter', this, this.onMouseEnter, true)); + this.boundEvents.push(browserEvents.conditionalBind( + table, 'pointerleave', this, this.onMouseLeave, true)); + this.boundEvents.push(browserEvents.conditionalBind( + table, 'keydown', this, this.onKeyDown, false)); - this.picker_ = table; + this.picker = table; } /** Disposes of events and DOM-references belonging to the colour editor. */ - private dropdownDispose_() { - if (this.onClickWrapper_) { - browserEvents.unbind(this.onClickWrapper_); - this.onClickWrapper_ = null; + private dropdownDispose() { + for (const event of this.boundEvents) { + browserEvents.unbind(event); } - if (this.onMouseMoveWrapper_) { - browserEvents.unbind(this.onMouseMoveWrapper_); - this.onMouseMoveWrapper_ = null; - } - if (this.onMouseEnterWrapper_) { - browserEvents.unbind(this.onMouseEnterWrapper_); - this.onMouseEnterWrapper_ = null; - } - if (this.onMouseLeaveWrapper_) { - browserEvents.unbind(this.onMouseLeaveWrapper_); - this.onMouseLeaveWrapper_ = null; - } - if (this.onKeyDownWrapper_) { - browserEvents.unbind(this.onKeyDownWrapper_); - this.onKeyDownWrapper_ = null; - } - this.picker_ = null; - this.highlightedIndex_ = null; + this.boundEvents.length = 0; + this.picker = null; + this.highlightedIndex = null; } /** @@ -584,14 +540,19 @@ export class FieldColour extends Field { static fromJson(options: FieldColourFromJsonConfig): FieldColour { // `this` might be a subclass of FieldColour if that class doesn't override // the static fromJson method. - return new this(options['colour'], undefined, options); + return new this(options.colour, undefined, options); } } /** The default value for this field. */ FieldColour.prototype.DEFAULT_VALUE = FieldColour.COLOURS[0]; -/** CSS for colour picker. See css.js for use. */ +fieldRegistry.register('field_colour', FieldColour); + + +/** + * CSS for colour picker. + */ Css.register(` .blocklyColourTable { border-collapse: collapse; @@ -601,7 +562,7 @@ Css.register(` } .blocklyColourTable>tr>td { - border: .5px solid #888; + border: 0.5px solid #888; box-sizing: border-box; cursor: pointer; display: inline-block; @@ -612,7 +573,7 @@ Css.register(` .blocklyColourTable>tr>td.blocklyColourHighlighted { border-color: #eee; - box-shadow: 2px 2px 7px 2px rgba(0,0,0,.3); + box-shadow: 2px 2px 7px 2px rgba(0, 0, 0, 0.3); position: relative; } @@ -623,8 +584,6 @@ Css.register(` } `); -fieldRegistry.register('field_colour', FieldColour); - /** * Config options for the colour field. */ @@ -640,3 +599,20 @@ export interface FieldColourConfig extends FieldConfig { export interface FieldColourFromJsonConfig extends FieldColourConfig { colour?: string; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldColourValidator = FieldValidator; diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index eb14d766f..9b1fdf615 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -20,20 +20,16 @@ import {Field, FieldConfig, FieldValidator, UnattachedFieldError} from './field. import * as fieldRegistry from './field_registry.js'; import {Menu} from './menu.js'; import {MenuItem} from './menuitem.js'; +import * as style from './utils/style.js'; import * as aria from './utils/aria.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; import * as utilsString from './utils/string.js'; import {Svg} from './utils/svg.js'; -export type FieldDropdownValidator = FieldValidator; - /** * Class for an editable dropdown field. - * - * @alias Blockly.FieldDropdown */ export class FieldDropdown extends Field { /** Horizontal distance that a checkmark overhangs the dropdown. */ @@ -92,7 +88,7 @@ export class FieldDropdown extends Field { */ override suffixField: string|null = null; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - private selectedOption_!: Array; + private selectedOption_!: MenuOption; override clickTarget_: SVGElement|null = null; /** @@ -101,11 +97,11 @@ export class FieldDropdown extends Field { * if you wish to skip setup (only used by subclasses that want to handle * configuration and setting the field value after their own constructors * have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a language-neutral dropdown option & returns a * validated language-neutral dropdown option, or null to abort the * change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creation} * for a list of properties this parameter supports. @@ -113,19 +109,19 @@ export class FieldDropdown extends Field { */ constructor( menuGenerator: MenuGenerator, - opt_validator?: FieldDropdownValidator, - opt_config?: FieldConfig, + validator?: FieldDropdownValidator, + config?: FieldDropdownConfig, ); - constructor(menuGenerator: Sentinel); + constructor(menuGenerator: typeof Field.SKIP_SETUP); constructor( - menuGenerator: MenuGenerator|Sentinel, - opt_validator?: FieldDropdownValidator, - opt_config?: FieldConfig, + menuGenerator: MenuGenerator|typeof Field.SKIP_SETUP, + validator?: FieldDropdownValidator, + config?: FieldDropdownConfig, ) { super(Field.SKIP_SETUP); // If we pass SKIP_SETUP, don't do *anything* with the menu generator. - if (!isMenuGenerator(menuGenerator)) return; + if (menuGenerator === Field.SKIP_SETUP) return; if (Array.isArray(menuGenerator)) { validateOptions(menuGenerator); @@ -143,12 +139,12 @@ export class FieldDropdown extends Field { */ this.selectedOption_ = this.getOptions(false)[0]; - if (opt_config) { - this.configure_(opt_config); + if (config) { + this.configure_(config); } this.setValue(this.selectedOption_[1]); - if (opt_validator) { - this.setValidator(opt_validator); + if (validator) { + this.setValidator(validator); } } @@ -248,17 +244,17 @@ export class FieldDropdown extends Field { /** * Create a dropdown menu under the text. * - * @param opt_e Optional mouse event that triggered the field to open, or + * @param e Optional mouse event that triggered the field to open, or * undefined if triggered programmatically. */ - protected override showEditor_(opt_e?: MouseEvent) { + protected override showEditor_(e?: MouseEvent) { const block = this.getSourceBlock(); if (!block) { throw new UnattachedFieldError(); } this.dropdownCreate_(); - if (opt_e && typeof opt_e.clientX === 'number') { - this.menu_!.openingCoords = new Coordinate(opt_e.clientX, opt_e.clientY); + if (e && typeof e.clientX === 'number') { + this.menu_!.openingCoords = new Coordinate(e.clientX, e.clientY); } else { this.menu_!.openingCoords = null; } @@ -287,6 +283,9 @@ export class FieldDropdown extends Field { if (this.selectedMenuItem_) { this.menu_!.setHighlighted(this.selectedMenuItem_); + style.scrollIntoContainerView( + this.selectedMenuItem_.getElement()!, dropDownDiv.getContentDiv(), + true); } this.applyColour(); @@ -332,7 +331,7 @@ export class FieldDropdown extends Field { /** * Disposes of events and DOM-references belonging to the dropdown editor. */ - private dropdownDispose_() { + protected dropdownDispose_() { if (this.menu_) { this.menu_.dispose(); } @@ -372,20 +371,20 @@ export class FieldDropdown extends Field { /** * Return a list of the options for this dropdown. * - * @param opt_useCache For dynamic options, whether or not to use the cached + * @param useCache For dynamic options, whether or not to use the cached * options or to re-generate them. * @returns A non-empty array of option tuples: * (human-readable text or image, language-neutral name). * @throws {TypeError} If generated options are incorrectly structured. */ - getOptions(opt_useCache?: boolean): MenuOption[] { + getOptions(useCache?: boolean): MenuOption[] { if (!this.menuGenerator_) { // A subclass improperly skipped setup without defining the menu // generator. throw TypeError('A menu generator was never defined.'); } if (Array.isArray(this.menuGenerator_)) return this.menuGenerator_; - if (opt_useCache && this.generatedOptions_) return this.generatedOptions_; + if (useCache && this.generatedOptions_) return this.generatedOptions_; this.generatedOptions_ = this.menuGenerator_(); validateOptions(this.generatedOptions_); @@ -395,24 +394,23 @@ export class FieldDropdown extends Field { /** * Ensure that the input value is a valid language-neutral option. * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid language-neutral option, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: MenuOption[1]): string - |null { + protected override doClassValidation_(newValue?: string): string|null { const options = this.getOptions(true); - const isValueValid = options.some((option) => option[1] === opt_newValue); + const isValueValid = options.some((option) => option[1] === newValue); if (!isValueValid) { if (this.sourceBlock_) { console.warn( 'Cannot set the dropdown\'s value to an unavailable option.' + ' Block type: ' + this.sourceBlock_.type + - ', Field name: ' + this.name + ', Value: ' + opt_newValue); + ', Field name: ' + this.name + ', Value: ' + newValue); } return null; } - return opt_newValue as string; + return newValue as string; } /** @@ -421,7 +419,7 @@ export class FieldDropdown extends Field { * @param newValue The value to be saved. The default validator guarantees * that this is one of the valid dropdown options. */ - protected override doValueUpdate_(newValue: MenuOption[1]) { + protected override doValueUpdate_(newValue: string) { super.doValueUpdate_(newValue); const options = this.getOptions(true); for (let i = 0, option; option = options[i]; i++) { @@ -465,7 +463,7 @@ export class FieldDropdown extends Field { // Show correct element. const option = this.selectedOption_ && this.selectedOption_[0]; if (option && typeof option === 'object') { - this.renderSelectedImage_((option)); + this.renderSelectedImage_(option); } else { this.renderSelectedText_(); } @@ -486,8 +484,8 @@ export class FieldDropdown extends Field { this.imageElement_!.style.display = ''; this.imageElement_!.setAttributeNS( dom.XLINK_NS, 'xlink:href', imageJson.src); - this.imageElement_!.setAttribute('height', `${imageJson.height}`); - this.imageElement_!.setAttribute('width', `${imageJson.width}`); + this.imageElement_!.setAttribute('height', String(imageJson.height)); + this.imageElement_!.setAttribute('width', String(imageJson.width)); const imageHeight = Number(imageJson.height); const imageWidth = Number(imageJson.width); @@ -517,14 +515,13 @@ export class FieldDropdown extends Field { let arrowX = 0; if (block.RTL) { const imageX = xPadding + arrowWidth; - this.imageElement_!.setAttribute('x', imageX.toString()); + this.imageElement_!.setAttribute('x', `${imageX}`); } else { arrowX = imageWidth + arrowWidth; this.getTextElement().setAttribute('text-anchor', 'end'); - this.imageElement_!.setAttribute('x', xPadding.toString()); + this.imageElement_!.setAttribute('x', `${xPadding}`); } - this.imageElement_!.setAttribute( - 'y', (height / 2 - imageHeight / 2).toString()); + this.imageElement_!.setAttribute('y', String(height / 2 - imageHeight / 2)); this.positionTextElement_(arrowX + xPadding, imageWidth + arrowWidth); } @@ -588,8 +585,8 @@ export class FieldDropdown extends Field { /** * Use the `getText_` developer hook to override the field's text - * representation. Get the selected option text. If the selected option is an - * image we return the image alt text. + * representation. Get the selected option text. If the selected option is + * an image we return the image alt text. * * @returns Selected option text. */ @@ -654,13 +651,35 @@ export type MenuGeneratorFunction = (this: FieldDropdown) => MenuOption[]; */ export type MenuGenerator = MenuOption[]|MenuGeneratorFunction; +/** + * Config options for the dropdown field. + */ +export type FieldDropdownConfig = FieldConfig; + /** * fromJson config for the dropdown field. */ -export interface FieldDropdownFromJsonConfig extends FieldConfig { +export interface FieldDropdownFromJsonConfig extends FieldDropdownConfig { options?: MenuOption[]; } +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldDropdownValidator = FieldValidator; + /** * The y offset from the top of the field to the top of the image, if an image * is selected. @@ -670,15 +689,6 @@ const IMAGE_Y_OFFSET = 5; /** The total vertical padding above and below an image. */ const IMAGE_Y_PADDING: number = IMAGE_Y_OFFSET * 2; -/** - * NOTE: Because Sentinel is an empty class, proving a value is Sentinel does - * not resolve in TS that it isn't a MenuGenerator. - */ -function isMenuGenerator(menuGenerator: MenuGenerator| - Sentinel): menuGenerator is MenuGenerator { - return menuGenerator !== Field.SKIP_SETUP; -} - /** * Factor out common words in statically defined options. * Create prefix and/or suffix labels. diff --git a/core/field_image.ts b/core/field_image.ts index 728be7e94..ecd702f3f 100644 --- a/core/field_image.ts +++ b/core/field_image.ts @@ -16,14 +16,11 @@ import {Field, FieldConfig} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; import {Size} from './utils/size.js'; import {Svg} from './utils/svg.js'; /** * Class for an image on a block. - * - * @alias Blockly.FieldImage */ export class FieldImage extends Field { /** @@ -35,12 +32,10 @@ export class FieldImage extends Field { private readonly imageHeight_: number; /** The function to be called when this field is clicked. */ - private clickHandler_: ((p1: FieldImage) => AnyDuringMigration)|null = null; + private clickHandler_: ((p1: FieldImage) => void)|null = null; /** The rendered field's image element. */ - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'SVGImageElement'. - private imageElement_: SVGImageElement = null as AnyDuringMigration; + private imageElement_: SVGImageElement|null = null; /** * Editable fields usually show some sort of UI indicating they are @@ -60,7 +55,6 @@ export class FieldImage extends Field { /** Alt text of this image. */ private altText_ = ''; - override value_: AnyDuringMigration; /** * @param src The URL of the image. @@ -69,19 +63,19 @@ export class FieldImage extends Field { * after their own constructors have run). * @param width Width of the image. * @param height Height of the image. - * @param opt_alt Optional alt text for when block is collapsed. - * @param opt_onClick Optional function to be called when the image is - * clicked. If opt_onClick is defined, opt_alt must also be defined. - * @param opt_flipRtl Whether to flip the icon in RTL. - * @param opt_config A map of options used to configure the field. + * @param alt Optional alt text for when block is collapsed. + * @param onClick Optional function to be called when the image is + * clicked. If onClick is defined, alt must also be defined. + * @param flipRtl Whether to flip the icon in RTL. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/image#creation} * for a list of properties this parameter supports. */ constructor( - src: string|Sentinel, width: string|number, height: string|number, - opt_alt?: string, opt_onClick?: (p1: FieldImage) => AnyDuringMigration, - opt_flipRtl?: boolean, opt_config?: FieldImageConfig) { + src: string|typeof Field.SKIP_SETUP, width: string|number, + height: string|number, alt?: string, onClick?: (p1: FieldImage) => void, + flipRtl?: boolean, config?: FieldImageConfig) { super(Field.SKIP_SETUP); const imageHeight = Number(parsing.replaceMessageReferences(height)); @@ -105,19 +99,17 @@ export class FieldImage extends Field { */ this.imageHeight_ = imageHeight; - if (typeof opt_onClick === 'function') { - this.clickHandler_ = opt_onClick; + if (typeof onClick === 'function') { + this.clickHandler_ = onClick; } - if (src === Field.SKIP_SETUP) { - return; - } + if (src === Field.SKIP_SETUP) return; - if (opt_config) { - this.configure_(opt_config); + if (config) { + this.configure_(config); } else { - this.flipRtl_ = !!opt_flipRtl; - this.altText_ = parsing.replaceMessageReferences(opt_alt) || ''; + this.flipRtl_ = !!flipRtl; + this.altText_ = parsing.replaceMessageReferences(alt) || ''; } this.setValue(parsing.replaceMessageReferences(src)); } @@ -162,15 +154,14 @@ export class FieldImage extends Field { /** * Ensure that the input value (the source URL) is a string. * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A string, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - string|null { - if (typeof opt_newValue !== 'string') { + protected override doClassValidation_(newValue?: any): string|null { + if (typeof newValue !== 'string') { return null; } - return opt_newValue; + return newValue; } /** @@ -179,11 +170,11 @@ export class FieldImage extends Field { * @param newValue The value to be saved. The default validator guarantees * that this is a string. */ - protected override doValueUpdate_(newValue: AnyDuringMigration) { + protected override doValueUpdate_(newValue: string) { this.value_ = newValue; if (this.imageElement_) { this.imageElement_.setAttributeNS( - dom.XLINK_NS, 'xlink:href', String(this.value_)); + dom.XLINK_NS, 'xlink:href', this.value_); } } @@ -227,7 +218,7 @@ export class FieldImage extends Field { * @param func The function that is called when the image is clicked, or null * to remove. */ - setOnClickHandler(func: ((p1: FieldImage) => AnyDuringMigration)|null) { + setOnClickHandler(func: ((p1: FieldImage) => void)|null) { this.clickHandler_ = func; } diff --git a/core/field_input.ts b/core/field_input.ts index b7e36d05b..ba86b0449 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -25,21 +25,24 @@ import {Field, FieldConfig, FieldValidator, UnattachedFieldError} from './field. import {Msg} from './msg.js'; import * as aria from './utils/aria.js'; import {Coordinate} from './utils/coordinate.js'; -import {KeyCodes} from './utils/keycodes.js'; -import type {Sentinel} from './utils/sentinel.js'; import * as userAgent from './utils/useragent.js'; import * as WidgetDiv from './widgetdiv.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -export type InputTypes = string|number; -export type FieldInputValidator = FieldValidator; +/** + * Supported types for FieldInput subclasses. + * + * @internal + */ +type InputTypes = string|number; /** - * Class for an editable text field. + * Abstract class for an editable input field. * - * @alias Blockly.FieldInput + * @typeParam T - The value stored on the field. + * @internal */ -export abstract class FieldInput extends Field { +export abstract class FieldInput extends Field { /** * Pixel size of input border radius. * Should match blocklyText's border-radius in CSS. @@ -83,38 +86,33 @@ export abstract class FieldInput extends Field { /** Mouse cursor style when over the hotspot that initiates the editor. */ override CURSOR = 'text'; - override clickTarget_: AnyDuringMigration; - override value_: AnyDuringMigration; - override isDirty_: AnyDuringMigration; /** - * @param opt_value The initial value of the field. Should cast to a string. + * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses * that want to handle configuration and setting the field value after * their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a string & returns a validated string, or null * to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/text-input#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|Sentinel, opt_validator?: FieldInputValidator|null, - opt_config?: FieldInputConfig) { + value?: string|typeof Field.SKIP_SETUP, + validator?: FieldInputValidator|null, config?: FieldInputConfig) { super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } - if (opt_config) { - this.configure_(opt_config); - } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } @@ -161,20 +159,6 @@ export abstract class FieldInput extends Field { this.createTextElement_(); } - /** - * Ensure that the input value casts to a valid string. - * - * @param opt_newValue The input value. - * @returns A valid string, or null if invalid. - */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - AnyDuringMigration { - if (opt_newValue === null || opt_newValue === undefined) { - return null; - } - return String(opt_newValue); - } - /** * Called by setValue if the text input is not valid. If the field is * currently being edited it reverts value of the field to the previous @@ -207,7 +191,7 @@ export abstract class FieldInput extends Field { * @param newValue The value to be saved. The default validator guarantees * that this is a string. */ - protected override doValueUpdate_(newValue: AnyDuringMigration) { + protected override doValueUpdate_(newValue: string|T) { this.isDirty_ = true; this.isTextValid_ = true; this.value_ = newValue; @@ -276,14 +260,13 @@ export abstract class FieldInput extends Field { * Shows a prompt editor for mobile browsers if the modalInputs option is * enabled. * - * @param _opt_e Optional mouse event that triggered the field to open, or + * @param _e Optional mouse event that triggered the field to open, or * undefined if triggered programmatically. - * @param opt_quietInput True if editor should be created without focus. + * @param quietInput True if editor should be created without focus. * Defaults to false. */ - protected override showEditor_(_opt_e?: Event, opt_quietInput?: boolean) { + protected override showEditor_(_e?: Event, quietInput = false) { this.workspace_ = (this.sourceBlock_ as BlockSvg).workspace; - const quietInput = opt_quietInput || false; if (!quietInput && this.workspace_.options.modalInputs && (userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD)) { this.showPromptEditor_(); @@ -372,7 +355,7 @@ export abstract class FieldInput extends Field { div!.style.transition = 'box-shadow 0.25s ease 0s'; if (this.getConstants()!.FIELD_TEXTINPUT_BOX_SHADOW) { div!.style.boxShadow = - 'rgba(255, 255, 255, 0.3) 0 0 0 ' + 4 * scale + 'px'; + 'rgba(255, 255, 255, 0.3) 0 0 0 ' + (4 * scale) + 'px'; } } htmlInput.style.borderRadius = borderRadius; @@ -380,7 +363,7 @@ export abstract class FieldInput extends Field { div!.appendChild(htmlInput); htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_); - htmlInput.setAttribute('data-untyped-default-value', this.value_); + htmlInput.setAttribute('data-untyped-default-value', String(this.value_)); this.resizeEditor_(); @@ -457,29 +440,19 @@ export abstract class FieldInput extends Field { * * @param e Keyboard event. */ - protected onHtmlInputKeyDown_(e: Event) { - // AnyDuringMigration because: Property 'keyCode' does not exist on type - // 'Event'. - if ((e as AnyDuringMigration).keyCode === KeyCodes.ENTER) { + protected onHtmlInputKeyDown_(e: KeyboardEvent) { + if (e.key === 'Enter') { WidgetDiv.hide(); dropDownDiv.hideWithoutAnimation(); - // AnyDuringMigration because: Property 'keyCode' does not exist on type - // 'Event'. - } else if ((e as AnyDuringMigration).keyCode === KeyCodes.ESC) { + } else if (e.key === 'Escape') { this.setValue( this.htmlInput_!.getAttribute('data-untyped-default-value')); WidgetDiv.hide(); dropDownDiv.hideWithoutAnimation(); - // AnyDuringMigration because: Property 'keyCode' does not exist on type - // 'Event'. - } else if ((e as AnyDuringMigration).keyCode === KeyCodes.TAB) { + } else if (e.key === 'Tab') { WidgetDiv.hide(); dropDownDiv.hideWithoutAnimation(); - // AnyDuringMigration because: Property 'shiftKey' does not exist on type - // 'Event'. AnyDuringMigration because: Argument of type 'this' is not - // assignable to parameter of type 'Field'. - (this.sourceBlock_ as BlockSvg) - .tab(this as AnyDuringMigration, !(e as AnyDuringMigration).shiftKey); + (this.sourceBlock_ as BlockSvg).tab(this, !e.shiftKey); e.preventDefault(); } } @@ -567,7 +540,7 @@ export abstract class FieldInput extends Field { * @returns The text to show on the HTML input. */ protected getEditorText_(value: AnyDuringMigration): string { - return String(value); + return `${value}`; } /** @@ -587,7 +560,28 @@ export abstract class FieldInput extends Field { /** * Config options for the input field. + * + * @internal */ export interface FieldInputConfig extends FieldConfig { spellcheck?: boolean; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + * @internal + */ +export type FieldInputValidator = + FieldValidator; diff --git a/core/field_label.ts b/core/field_label.ts index 2a4730ff2..024646495 100644 --- a/core/field_label.ts +++ b/core/field_label.ts @@ -17,15 +17,12 @@ import * as dom from './utils/dom.js'; import {Field, FieldConfig} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; /** * Class for a non-editable, non-serializable text field. - * - * @alias Blockly.FieldLabel */ export class FieldLabel extends Field { - /** The html class name to use for this field. */ + /** The HTML class name to use for this field. */ private class_: string|null = null; /** @@ -35,31 +32,29 @@ export class FieldLabel extends Field { override EDITABLE = false; /** - * @param opt_value The initial value of the field. Should cast to a string. + * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses * that want to handle configuration and setting the field value after * their own constructors have run). - * @param opt_class Optional CSS class for the field's text. - * @param opt_config A map of options used to configure the field. + * @param textClass Optional CSS class for the field's text. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|Sentinel, opt_class?: string, - opt_config?: FieldLabelConfig) { + value?: string|typeof Field.SKIP_SETUP, textClass?: string, + config?: FieldLabelConfig) { super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; - } - if (opt_config) { - this.configure_(opt_config); + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } else { - this.class_ = opt_class || null; + this.class_ = textClass || null; } - this.setValue(opt_value); + this.setValue(value); } protected override configure_(config: FieldLabelConfig) { @@ -82,15 +77,15 @@ export class FieldLabel extends Field { /** * Ensure that the input value casts to a valid string. * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid string, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - string|null { - if (opt_newValue === null || opt_newValue === undefined) { + protected override doClassValidation_(newValue?: AnyDuringMigration): string + |null { + if (newValue === null || newValue === undefined) { return null; } - return String(opt_newValue); + return `${newValue}`; } /** diff --git a/core/field_label_serializable.ts b/core/field_label_serializable.ts index ad1a5a06e..55ef8a1fb 100644 --- a/core/field_label_serializable.ts +++ b/core/field_label_serializable.ts @@ -20,8 +20,6 @@ import * as parsing from './utils/parsing.js'; /** * Class for a non-editable, serializable text field. - * - * @alias Blockly.FieldLabelSerializable */ export class FieldLabelSerializable extends FieldLabel { /** @@ -38,17 +36,16 @@ export class FieldLabelSerializable extends FieldLabel { override SERIALIZABLE = true; /** - * @param opt_value The initial value of the field. Should cast to a string. + * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. - * @param opt_class Optional CSS class for the field's text. - * @param opt_config A map of options used to configure the field. + * @param textClass Optional CSS class for the field's text. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation} * for a list of properties this parameter supports. */ - constructor( - opt_value?: string, opt_class?: string, opt_config?: FieldLabelConfig) { - super(String(opt_value ?? ''), opt_class, opt_config); + constructor(value?: string, textClass?: string, config?: FieldLabelConfig) { + super(String(value ?? ''), textClass, config); } /** diff --git a/core/field_multilineinput.ts b/core/field_multilineinput.ts index abd53193a..1472c8996 100644 --- a/core/field_multilineinput.ts +++ b/core/field_multilineinput.ts @@ -18,28 +18,20 @@ import * as fieldRegistry from './field_registry.js'; import {FieldTextInput, FieldTextInputConfig, FieldTextInputValidator} from './field_textinput.js'; import * as aria from './utils/aria.js'; import * as dom from './utils/dom.js'; -import {KeyCodes} from './utils/keycodes.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; import {Svg} from './utils/svg.js'; import * as userAgent from './utils/useragent.js'; import * as WidgetDiv from './widgetdiv.js'; -export type FieldMultilineInputValidator = FieldTextInputValidator; - /** * Class for an editable text area field. - * - * @alias Blockly.FieldMultilineInput */ export class FieldMultilineInput extends FieldTextInput { /** * The SVG group element that will contain a text element for each text row * when initialized. */ - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'SVGGElement'. - textGroup_: SVGGElement = null as AnyDuringMigration; + textGroup: SVGGElement|null = null; /** * Defines the maximum number of lines of field. @@ -51,37 +43,41 @@ export class FieldMultilineInput extends FieldTextInput { protected isOverflowedY_ = false; /** - * @param opt_value The initial content of the field. Should cast to a string. + * @param value The initial content of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses * that want to handle configuration and setting the field value after * their own constructors have run). - * @param opt_validator An optional function that is called to validate any + * @param validator An optional function that is called to validate any * constraints on what the user entered. Takes the new text as an * argument and returns either the accepted text, a replacement text, or * null to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|Sentinel, opt_validator?: FieldMultilineInputValidator, - opt_config?: FieldMultilineInputConfig) { + value?: string|typeof Field.SKIP_SETUP, + validator?: FieldMultilineInputValidator, + config?: FieldMultilineInputConfig) { super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } - if (opt_config) { - this.configure_(opt_config); - } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } + /** + * Configure the field based on the given map of options. + * + * @param config A map of options to configure the field based on. + */ protected override configure_(config: FieldMultilineInputConfig) { super.configure_(config); if (config.maxLines) this.setMaxLines(config.maxLines); @@ -118,6 +114,8 @@ export class FieldMultilineInput extends FieldTextInput { /** * Saves this field's value. + * This function only exists for subclasses of FieldMultilineInput which + * predate the load/saveState API and only define to/fromXml. * * @returns The state of this field. * @internal @@ -132,6 +130,8 @@ export class FieldMultilineInput extends FieldTextInput { /** * Sets the field's value based on the given state. + * This function only exists for subclasses of FieldMultilineInput which + * predate the load/saveState API and only define to/fromXml. * * @param state The state of the variable to assign to this variable field. * @internal @@ -150,7 +150,7 @@ export class FieldMultilineInput extends FieldTextInput { */ override initView() { this.createBorderRect_(); - this.textGroup_ = dom.createSvgElement( + this.textGroup = dom.createSvgElement( Svg.G, { 'class': 'blocklyEditableText', }, @@ -210,9 +210,11 @@ export class FieldMultilineInput extends FieldTextInput { * @param newValue The value to be saved. The default validator guarantees * that this is a string. */ - protected override doValueUpdate_(newValue: AnyDuringMigration) { + protected override doValueUpdate_(newValue: string) { super.doValueUpdate_(newValue); - this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_; + if (this.value_ !== null) { + this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_; + } } /** Updates the text of the textElement. */ @@ -223,8 +225,9 @@ export class FieldMultilineInput extends FieldTextInput { } // Remove all text group children. let currentChild; - while (currentChild = this.textGroup_.firstChild) { - this.textGroup_.removeChild(currentChild); + const textGroup = this.textGroup; + while (currentChild = textGroup!.firstChild) { + textGroup!.removeChild(currentChild); } // Add in text elements into the group. @@ -240,7 +243,7 @@ export class FieldMultilineInput extends FieldTextInput { 'y': y + this.getConstants()!.FIELD_BORDER_RECT_Y_PADDING, 'dy': this.getConstants()!.FIELD_TEXT_BASELINE, }, - this.textGroup_); + textGroup); span.appendChild(document.createTextNode(lines[i])); y += lineHeight; } @@ -278,7 +281,7 @@ export class FieldMultilineInput extends FieldTextInput { /** Updates the size of the field based on the text. */ protected override updateSize_() { - const nodes = this.textGroup_.childNodes; + const nodes = (this.textGroup as SVGElement).childNodes; const fontSize = this.getConstants()!.FIELD_TEXT_FONTSIZE; const fontWeight = this.getConstants()!.FIELD_TEXT_FONTWEIGHT; const fontFamily = this.getConstants()!.FIELD_TEXT_FONTFAMILY; @@ -300,7 +303,7 @@ export class FieldMultilineInput extends FieldTextInput { // absolute longest line, even if it would be truncated after editing. // Otherwise we would get wrong editor width when there are more // lines than this.maxLines_. - const actualEditorLines = this.value_.split('\n'); + const actualEditorLines = String(this.value_).split('\n'); const dummyTextElement = dom.createSvgElement( Svg.TEXT, {'class': 'blocklyText blocklyMultilineText'}); @@ -324,13 +327,8 @@ export class FieldMultilineInput extends FieldTextInput { if (this.borderRect_) { totalHeight += this.getConstants()!.FIELD_BORDER_RECT_Y_PADDING * 2; totalWidth += this.getConstants()!.FIELD_BORDER_RECT_X_PADDING * 2; - // AnyDuringMigration because: Argument of type 'number' is not - // assignable to parameter of type 'string'. - this.borderRect_.setAttribute('width', totalWidth as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not - // assignable to parameter of type 'string'. - this.borderRect_.setAttribute( - 'height', totalHeight as AnyDuringMigration); + this.borderRect_.setAttribute('width', `${totalWidth}`); + this.borderRect_.setAttribute('height', `${totalHeight}`); } this.size_.width = totalWidth; this.size_.height = totalHeight; @@ -343,13 +341,13 @@ export class FieldMultilineInput extends FieldTextInput { * Overrides the default behaviour to force rerender in order to * correct block size, based on editor text. * - * @param _opt_e Optional mouse event that triggered the field to open, or + * @param e Optional mouse event that triggered the field to open, or * undefined if triggered programmatically. - * @param opt_quietInput True if editor should be created without focus. + * @param quietInput True if editor should be created without focus. * Defaults to false. */ - override showEditor_(_opt_e?: Event, opt_quietInput?: boolean) { - super.showEditor_(_opt_e, opt_quietInput); + override showEditor_(e?: Event, quietInput?: boolean) { + super.showEditor_(e, quietInput); this.forceRerender(); } @@ -364,10 +362,7 @@ export class FieldMultilineInput extends FieldTextInput { const htmlInput = (document.createElement('textarea')); htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput'; - // AnyDuringMigration because: Argument of type 'boolean' is not assignable - // to parameter of type 'string'. - htmlInput.setAttribute( - 'spellcheck', this.spellcheck_ as AnyDuringMigration); + htmlInput.setAttribute('spellcheck', String(this.spellcheck_)); const fontSize = this.getConstants()!.FIELD_TEXT_FONTSIZE * scale + 'pt'; div!.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; @@ -385,7 +380,7 @@ export class FieldMultilineInput extends FieldTextInput { div!.appendChild(htmlInput); htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_); - htmlInput.setAttribute('data-untyped-default-value', this.value_); + htmlInput.setAttribute('data-untyped-default-value', String(this.value_)); htmlInput.setAttribute('data-old-value', ''); if (userAgent.GECKO) { // In FF, ensure the browser reflows before resizing to avoid issue #2777. @@ -428,10 +423,8 @@ export class FieldMultilineInput extends FieldTextInput { * * @param e Keyboard event. */ - protected override onHtmlInputKeyDown_(e: Event) { - // AnyDuringMigration because: Property 'keyCode' does not exist on type - // 'Event'. - if ((e as AnyDuringMigration).keyCode !== KeyCodes.ENTER) { + protected override onHtmlInputKeyDown_(e: KeyboardEvent) { + if (e.key !== 'Enter') { super.onHtmlInputKeyDown_(e); } } @@ -454,7 +447,12 @@ export class FieldMultilineInput extends FieldTextInput { } } -/** CSS for multiline field. See css.js for use. */ +fieldRegistry.register('field_multilinetext', FieldMultilineInput); + + +/** + * CSS for multiline field. + */ Css.register(` .blocklyHtmlTextAreaInput { font-family: monospace; @@ -469,8 +467,6 @@ Css.register(` } `); -fieldRegistry.register('field_multilinetext', FieldMultilineInput); - /** * Config options for the multiline input field. */ @@ -485,3 +481,20 @@ export interface FieldMultilineInputFromJsonConfig extends FieldMultilineInputConfig { text?: string; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldMultilineInputValidator = FieldTextInputValidator; diff --git a/core/field_number.ts b/core/field_number.ts index a891f1c58..72f383d01 100644 --- a/core/field_number.ts +++ b/core/field_number.ts @@ -16,14 +16,9 @@ import {Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import {FieldInput, FieldInputConfig, FieldInputValidator} from './field_input.js'; import * as aria from './utils/aria.js'; -import type {Sentinel} from './utils/sentinel.js'; - -export type FieldNumberValidator = FieldInputValidator; /** * Class for an editable number field. - * - * @alias Blockly.FieldNumber */ export class FieldNumber extends FieldInput { /** The minimum value this number field can contain. */ @@ -41,53 +36,44 @@ export class FieldNumber extends FieldInput { */ private decimalPlaces_: number|null = null; - /** - * Serializable fields are saved by the serializer, non-serializable fields - * are not. Editable fields should also be serializable. - */ - override SERIALIZABLE = true; - /** Don't spellcheck numbers. Our validator does a better job. */ protected override spellcheck_ = false; /** - * @param opt_value The initial value of the field. Should cast to a number. + * @param value The initial value of the field. Should cast to a number. * Defaults to 0. Also accepts Field.SKIP_SETUP if you wish to skip setup * (only used by subclasses that want to handle configuration and setting * the field value after their own constructors have run). - * @param opt_min Minimum value. Will only be used if opt_config is not + * @param min Minimum value. Will only be used if config is not * provided. - * @param opt_max Maximum value. Will only be used if opt_config is not + * @param max Maximum value. Will only be used if config is not * provided. - * @param opt_precision Precision for value. Will only be used if opt_config + * @param precision Precision for value. Will only be used if config * is not provided. - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a number & returns a validated number, or null * to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/number#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|number|Sentinel, opt_min?: string|number|null, - opt_max?: string|number|null, opt_precision?: string|number|null, - opt_validator?: FieldNumberValidator|null, - opt_config?: FieldNumberConfig) { + value?: string|number|typeof Field.SKIP_SETUP, min?: string|number|null, + max?: string|number|null, precision?: string|number|null, + validator?: FieldNumberValidator|null, config?: FieldNumberConfig) { // Pass SENTINEL so that we can define properties before value validation. super(Field.SKIP_SETUP); - if (opt_value === Field.SKIP_SETUP) { - return; - } - if (opt_config) { - this.configure_(opt_config); + if (value === Field.SKIP_SETUP) return; + if (config) { + this.configure_(config); } else { - this.setConstraints(opt_min, opt_max, opt_precision); + this.setConstraints(min, max, precision); } - this.setValue(opt_value); - if (opt_validator) { - this.setValidator(opt_validator); + this.setValue(value); + if (validator) { + this.setValidator(validator); } } @@ -252,16 +238,17 @@ export class FieldNumber extends FieldInput { * Ensure that the input value is a valid number (must fulfill the * constraints placed on the field). * - * @param opt_newValue The input value. + * @param newValue The input value. * @returns A valid number, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - number|null { - if (opt_newValue === null) { + protected override doClassValidation_(newValue?: AnyDuringMigration): number + |null { + if (newValue === null) { return null; } + // Clean up text. - let newValue = String(opt_newValue); + newValue = `${newValue}`; // TODO: Handle cases like 'ten', '1.203,14', etc. // 'O' is sometimes mistaken for '0' by inexperienced users. newValue = newValue.replace(/O/ig, '0'); @@ -294,14 +281,17 @@ export class FieldNumber extends FieldInput { * * @returns The newly created number input editor. */ - protected override widgetCreate_(): HTMLElement { - const htmlInput = super.widgetCreate_(); + protected override widgetCreate_(): HTMLInputElement { + const htmlInput = super.widgetCreate_() as HTMLInputElement; + htmlInput.type = 'number'; // Set the accessibility state if (this.min_ > -Infinity) { + htmlInput.min = `${this.min_}`; aria.setState(htmlInput, aria.State.VALUEMIN, this.min_); } if (this.max_ < Infinity) { + htmlInput.max = `${this.max_}`; aria.setState(htmlInput, aria.State.VALUEMAX, this.max_); } return htmlInput; @@ -342,3 +332,20 @@ export interface FieldNumberConfig extends FieldInputConfig { export interface FieldNumberFromJsonConfig extends FieldNumberConfig { value?: number; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldNumberValidator = FieldInputValidator; diff --git a/core/field_registry.ts b/core/field_registry.ts index 172e1d8ae..25364d448 100644 --- a/core/field_registry.ts +++ b/core/field_registry.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Fields can be created based on a JSON definition. This file - * contains methods for registering those JSON definitions, and building the - * fields based on JSON. - * - * @namespace Blockly.fieldRegistry - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.fieldRegistry'); @@ -32,7 +25,6 @@ interface RegistryOptions { * construct an instance of the field. * @throws {Error} if the type name is empty, the field is already registered, * or the fieldClass is not an object containing a fromJson function. - * @alias Blockly.fieldRegistry.register */ export function register(type: string, fieldClass: FieldProto) { registry.register(registry.Type.FIELD, type, fieldClass); @@ -42,7 +34,6 @@ export function register(type: string, fieldClass: FieldProto) { * Unregisters the field registered with the given type. * * @param type The field type name as used in the JSON definition. - * @alias Blockly.fieldRegistry.unregister */ export function unregister(type: string) { registry.unregister(registry.Type.FIELD, type); @@ -57,7 +48,6 @@ export function unregister(type: string) { * type. * @returns The new field instance or null if a field wasn't found with the * given type name - * @alias Blockly.fieldRegistry.fromJson * @internal */ export function fromJson(options: RegistryOptions): Field|null { diff --git a/core/field_textinput.ts b/core/field_textinput.ts index 2a2f1c6db..600e14cb1 100644 --- a/core/field_textinput.ts +++ b/core/field_textinput.ts @@ -15,32 +15,47 @@ goog.declareModuleId('Blockly.FieldTextInput'); // Unused import preserved for side-effects. Remove if unneeded. import './events/events_block_change.js'; +import {Field} from './field.js'; import {FieldInput, FieldInputConfig, FieldInputValidator} from './field_input.js'; import * as fieldRegistry from './field_registry.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; - -export type FieldTextInputValidator = FieldInputValidator; +/** + * Class for an editable text field. + */ export class FieldTextInput extends FieldInput { /** - * @param opt_value The initial value of the field. Should cast to a string. + * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses * that want to handle configuration and setting the field value after * their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a string & returns a validated string, or null * to abort the change. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/text-input#creation} * for a list of properties this parameter supports. */ constructor( - opt_value?: string|Sentinel, opt_validator?: FieldTextInputValidator|null, - opt_config?: FieldInputConfig) { - super(opt_value, opt_validator, opt_config); + value?: string|typeof Field.SKIP_SETUP, + validator?: FieldTextInputValidator|null, config?: FieldTextInputConfig) { + super(value, validator, config); + } + + /** + * Ensure that the input value casts to a valid string. + * + * @param newValue The input value. + * @returns A valid string, or null if invalid. + */ + protected override doClassValidation_(newValue?: AnyDuringMigration): string + |null { + if (newValue === undefined) { + return null; + } + return `${newValue}`; } /** @@ -64,11 +79,31 @@ fieldRegistry.register('field_input', FieldTextInput); FieldTextInput.prototype.DEFAULT_VALUE = ''; +/** + * Config options for the text input field. + */ +export type FieldTextInputConfig = FieldInputConfig; + /** * fromJson config options for the text input field. */ -export interface FieldTextInputFromJsonConfig extends FieldInputConfig { +export interface FieldTextInputFromJsonConfig extends FieldTextInputConfig { text?: string; } -export {FieldInputConfig as FieldTextInputConfig}; +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldTextInputValidator = FieldInputValidator; diff --git a/core/field_variable.ts b/core/field_variable.ts index e3b98f4fe..5bde39de1 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -24,18 +24,13 @@ import type {Menu} from './menu.js'; import type {MenuItem} from './menuitem.js'; import {Msg} from './msg.js'; import * as parsing from './utils/parsing.js'; -import type {Sentinel} from './utils/sentinel.js'; import {Size} from './utils/size.js'; import {VariableModel} from './variable_model.js'; import * as Variables from './variables.js'; import * as Xml from './xml.js'; -export type FieldVariableValidator = FieldDropdownValidator; - /** * Class for a variable's dropdown field. - * - * @alias Blockly.FieldVariable */ export class FieldVariable extends FieldDropdown { protected override menuGenerator_: MenuGenerator|undefined; @@ -66,23 +61,23 @@ export class FieldVariable extends FieldDropdown { * Also accepts Field.SKIP_SETUP if you wish to skip setup (only used by * subclasses that want to handle configuration and setting the field value * after their own constructors have run). - * @param opt_validator A function that is called to validate changes to the + * @param validator A function that is called to validate changes to the * field's value. Takes in a variable ID & returns a validated variable * ID, or null to abort the change. - * @param opt_variableTypes A list of the types of variables to include in the - * dropdown. Will only be used if opt_config is not provided. - * @param opt_defaultType The type of variable to create if this field's value - * is not explicitly set. Defaults to ''. Will only be used if opt_config + * @param variableTypes A list of the types of variables to include in the + * dropdown. Will only be used if config is not provided. + * @param defaultType The type of variable to create if this field's value + * is not explicitly set. Defaults to ''. Will only be used if config * is not provided. - * @param opt_config A map of options used to configure the field. + * @param config A map of options used to configure the field. * See the [field creation documentation]{@link * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation} * for a list of properties this parameter supports. */ constructor( - varName: string|null|Sentinel, opt_validator?: FieldVariableValidator, - opt_variableTypes?: string[], opt_defaultType?: string, - opt_config?: FieldVariableConfig) { + varName: string|null|typeof Field.SKIP_SETUP, + validator?: FieldVariableValidator, variableTypes?: string[], + defaultType?: string, config?: FieldVariableConfig) { super(Field.SKIP_SETUP); /** @@ -101,17 +96,15 @@ export class FieldVariable extends FieldDropdown { /** The size of the area rendered by the field. */ this.size_ = new Size(0, 0); - if (varName === Field.SKIP_SETUP) { - return; - } + if (varName === Field.SKIP_SETUP) return; - if (opt_config) { - this.configure_(opt_config); + if (config) { + this.configure_(config); } else { - this.setTypes_(opt_variableTypes, opt_defaultType); + this.setTypes_(variableTypes, defaultType); } - if (opt_validator) { - this.setValidator(opt_validator); + if (validator) { + this.setValidator(validator); } } @@ -306,7 +299,7 @@ export class FieldVariable extends FieldDropdown { * * @returns Validation function, or null. */ - override getValidator(): Function|null { + override getValidator(): FieldVariableValidator|null { // Validators shouldn't operate on the initial setValue call. // Normally this is achieved by calling setValidator after setValue, but // this is not a possibility with variable fields. @@ -319,19 +312,19 @@ export class FieldVariable extends FieldDropdown { /** * Ensure that the ID belongs to a valid variable of an allowed type. * - * @param opt_newValue The ID of the new variable to set. + * @param newValue The ID of the new variable to set. * @returns The validated ID, or null if invalid. */ - protected override doClassValidation_(opt_newValue?: AnyDuringMigration): - string|null { - if (opt_newValue === null) { + protected override doClassValidation_(newValue?: AnyDuringMigration): string + |null { + if (newValue === null) { return null; } const block = this.getSourceBlock(); if (!block) { throw new UnattachedFieldError(); } - const newId = opt_newValue as string; + const newId = newValue as string; const variable = Variables.getVariable(block.workspace, newId); if (!variable) { console.warn( @@ -357,7 +350,7 @@ export class FieldVariable extends FieldDropdown { * * @param newId The value to be saved. */ - protected override doValueUpdate_(newId: AnyDuringMigration) { + protected override doValueUpdate_(newId: string) { const block = this.getSourceBlock(); if (!block) { throw new UnattachedFieldError(); @@ -414,23 +407,19 @@ export class FieldVariable extends FieldDropdown { * Parse the optional arguments representing the allowed variable types and * the default variable type. * - * @param opt_variableTypes A list of the types of variables to include in the + * @param variableTypes A list of the types of variables to include in the * dropdown. If null or undefined, variables of all types will be * displayed in the dropdown. - * @param opt_defaultType The type of the variable to create if this field's + * @param defaultType The type of the variable to create if this field's * value is not explicitly set. Defaults to ''. */ - private setTypes_(opt_variableTypes?: string[], opt_defaultType?: string) { + private setTypes_(variableTypes: string[]|null = null, defaultType = '') { // If you expected that the default type would be the same as the only entry // in the variable types array, tell the Blockly team by commenting on // #1499. - const defaultType = opt_defaultType || ''; - let variableTypes; // Set the allowable variable types. Null means all types on the workspace. - if (opt_variableTypes === null || opt_variableTypes === undefined) { - variableTypes = null; - } else if (Array.isArray(opt_variableTypes)) { - variableTypes = opt_variableTypes; + if (Array.isArray(variableTypes)) { + variableTypes = variableTypes; // Make sure the default type is valid. let isInArray = false; for (let i = 0; i < variableTypes.length; i++) { @@ -443,7 +432,7 @@ export class FieldVariable extends FieldDropdown { 'Invalid default type \'' + defaultType + '\' in ' + 'the definition of a FieldVariable'); } - } else { + } else if (variableTypes !== null) { throw Error( '\'variableTypes\' was not an array in the definition of ' + 'a FieldVariable'); @@ -581,3 +570,20 @@ export interface FieldVariableConfig extends FieldConfig { export interface FieldVariableFromJsonConfig extends FieldVariableConfig { variable?: string; } + +/** + * A function that is called to validate changes to the field's value before + * they are set. + * + * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} + * @param newValue The value to be validated. + * @returns One of three instructions for setting the new value: `T`, `null`, + * or `undefined`. + * + * - `T` to set this function's returned value instead of `newValue`. + * + * - `null` to invoke `doValueInvalid_` and not set a value. + * + * - `undefined` to set `newValue` as is. + */ +export type FieldVariableValidator = FieldDropdownValidator; diff --git a/core/flyout_base.ts b/core/flyout_base.ts index be6b5da4b..a517eebe7 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -33,6 +33,7 @@ import {Svg} from './utils/svg.js'; import * as toolbox from './utils/toolbox.js'; import * as Variables from './variables.js'; import {WorkspaceSvg} from './workspace_svg.js'; +import * as utilsXml from './utils/xml.js'; import * as Xml from './xml.js'; @@ -43,8 +44,6 @@ enum FlyoutItemType { /** * Class for a flyout. - * - * @alias Blockly.Flyout */ export abstract class Flyout extends DeleteArea implements IFlyout { /** @@ -75,8 +74,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { /** * Lay out the blocks in the flyout. * - * @param contents The blocks and buttons to lay - * out. + * @param contents The blocks and buttons to lay out. * @param gaps The visible gaps between blocks. */ protected abstract layout_(contents: FlyoutItem[], gaps: number[]): void; @@ -129,9 +127,11 @@ export abstract class Flyout extends DeleteArea implements IFlyout { protected toolboxPosition_: number; /** - * Opaque data that can be passed to Blockly.unbindEvent_. + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. */ - private eventWrappers_: browserEvents.Data = []; + private boundEvents: browserEvents.Data[] = []; /** * Function that will be registered as a change listener on the workspace @@ -358,21 +358,17 @@ export abstract class Flyout extends DeleteArea implements IFlyout { this.hide(); - Array.prototype.push.apply( - this.eventWrappers_, - browserEvents.conditionalBind( - (this.svgGroup_ as SVGGElement), 'wheel', this, this.wheel_)); + this.boundEvents.push(browserEvents.conditionalBind( + (this.svgGroup_ as SVGGElement), 'wheel', this, this.wheel_)); if (!this.autoClose) { this.filterWrapper_ = this.filterForCapacity_.bind(this); this.targetWorkspace.addChangeListener(this.filterWrapper_); } // Dragging the flyout up and down. - Array.prototype.push.apply( - this.eventWrappers_, - browserEvents.conditionalBind( - (this.svgBackground_ as SVGPathElement), 'pointerdown', this, - this.onMouseDown_)); + this.boundEvents.push(browserEvents.conditionalBind( + (this.svgBackground_ as SVGPathElement), 'pointerdown', this, + this.onMouseDown_)); // A flyout connected to a workspace doesn't have its own current gesture. this.workspace_.getGesture = @@ -402,7 +398,10 @@ export abstract class Flyout extends DeleteArea implements IFlyout { dispose() { this.hide(); this.workspace_.getComponentManager().removeComponent(this.id); - browserEvents.unbind(this.eventWrappers_); + for (const event of this.boundEvents) { + browserEvents.unbind(event); + } + this.boundEvents.length = 0; if (this.filterWrapper_) { this.targetWorkspace.removeChangeListener(this.filterWrapper_); this.filterWrapper_ = null; @@ -526,18 +525,13 @@ export abstract class Flyout extends DeleteArea implements IFlyout { * @param y The computed y origin of the flyout's SVG group. */ protected positionAt_(width: number, height: number, x: number, y: number) { - this.svgGroup_?.setAttribute('width', width.toString()); - this.svgGroup_?.setAttribute('height', height.toString()); + this.svgGroup_?.setAttribute('width', `${width}`); + this.svgGroup_?.setAttribute('height', `${height}`); this.workspace_.setCachedParentSvgSize(width, height); - if (this.svgGroup_?.tagName === 'svg') { + if (this.svgGroup_) { const transform = 'translate(' + x + 'px,' + y + 'px)'; dom.setCssTransform(this.svgGroup_, transform); - } else { - // IE and Edge don't support CSS transforms on SVG elements so - // it's important to set the transform on the SVG element itself - const transform = 'translate(' + x + ',' + y + ')'; - this.svgGroup_?.setAttribute('transform', transform); } // Update the scrollbar (if one exists). @@ -568,7 +562,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { } this.setVisible(false); // Delete all the event listeners. - for (let i = 0, listen; listen = this.listeners_[i]; i++) { + for (const listen of this.listeners_) { browserEvents.unbind(listen); } this.listeners_.length = 0; @@ -576,9 +570,9 @@ export abstract class Flyout extends DeleteArea implements IFlyout { this.workspace_.removeChangeListener(this.reflowWrapper_); this.reflowWrapper_ = null; } + // Do NOT delete the blocks here. Wait until Flyout.show. + // https://neil.fraser.name/news/2014/08/09/ } - // Do NOT delete the blocks here. Wait until Flyout.show. - // https://neil.fraser.name/news/2014/08/09/ /** * Show and populate the flyout. @@ -604,19 +598,6 @@ export abstract class Flyout extends DeleteArea implements IFlyout { this.layout_(flyoutInfo.contents, flyoutInfo.gaps); - // IE 11 is an incompetent browser that fails to fire mouseout events. - // When the mouse is over the background, deselect all blocks. - function deselectAll(this: Flyout) { - const topBlocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; block = topBlocks[i]; i++) { - block.removeSelect(); - } - } - - this.listeners_.push(browserEvents.conditionalBind( - (this.svgBackground_ as SVGPathElement), 'pointerover', this, - deselectAll)); - if (this.horizontalLayout) { this.height_ = 0; } else { @@ -649,34 +630,34 @@ export abstract class Flyout extends DeleteArea implements IFlyout { const gaps: number[] = []; this.permanentlyDisabled_.length = 0; const defaultGap = this.horizontalLayout ? this.GAP_X : this.GAP_Y; - for (let i = 0, contentInfo; contentInfo = parsedContent[i]; i++) { - if ('custom' in contentInfo) { - const customInfo = (contentInfo as toolbox.DynamicCategoryInfo); + for (const info of parsedContent) { + if ('custom' in info) { + const customInfo = (info as toolbox.DynamicCategoryInfo); const categoryName = customInfo['custom']; const flyoutDef = this.getDynamicCategoryContents_(categoryName); const parsedDynamicContent = toolbox.convertFlyoutDefToJsonArray(flyoutDef); - // Replace the element at i with the dynamic content it represents. - parsedContent.splice.apply( - parsedContent, [i, 1, ...parsedDynamicContent]); - contentInfo = parsedContent[i]; + const {contents: dynamicContents, gaps: dynamicGaps} = + this.createFlyoutInfo_(parsedDynamicContent); + contents.push(...dynamicContents); + gaps.push(...dynamicGaps); } - switch (contentInfo['kind'].toUpperCase()) { + switch (info['kind'].toUpperCase()) { case 'BLOCK': { - const blockInfo = (contentInfo as toolbox.BlockInfo); + const blockInfo = (info as toolbox.BlockInfo); const block = this.createFlyoutBlock_(blockInfo); contents.push({type: FlyoutItemType.BLOCK, block: block}); this.addBlockGap_(blockInfo, gaps, defaultGap); break; } case 'SEP': { - const sepInfo = (contentInfo as toolbox.SeparatorInfo); + const sepInfo = (info as toolbox.SeparatorInfo); this.addSeparatorGap_(sepInfo, gaps, defaultGap); break; } case 'LABEL': { - const labelInfo = (contentInfo as toolbox.LabelInfo); + const labelInfo = (info as toolbox.LabelInfo); // A label is a button with different styling. const label = this.createButton_(labelInfo, /** isLabel */ true); contents.push({type: FlyoutItemType.BUTTON, button: label}); @@ -684,7 +665,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { break; } case 'BUTTON': { - const buttonInfo = (contentInfo as toolbox.ButtonInfo); + const buttonInfo = (info as toolbox.ButtonInfo); const button = this.createButton_(buttonInfo, /** isLabel */ false); contents.push({type: FlyoutItemType.BUTTON, button: button}); gaps.push(defaultGap); @@ -692,6 +673,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { } } } + return {contents: contents, gaps: gaps}; } @@ -744,7 +726,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { let block; if (blockInfo['blockxml']) { const xml = (typeof blockInfo['blockxml'] === 'string' ? - Xml.textToDom(blockInfo['blockxml']) : + utilsXml.textToDom(blockInfo['blockxml']) : blockInfo['blockxml']) as Element; block = this.getRecycledBlock_(xml.getAttribute('type')!); if (!block) { @@ -800,10 +782,10 @@ export abstract class Flyout extends DeleteArea implements IFlyout { blockInfo: toolbox.BlockInfo, gaps: number[], defaultGap: number) { let gap; if (blockInfo['gap']) { - gap = parseInt(blockInfo['gap'].toString()); + gap = parseInt(String(blockInfo['gap'])); } else if (blockInfo['blockxml']) { const xml = (typeof blockInfo['blockxml'] === 'string' ? - Xml.textToDom(blockInfo['blockxml']) : + utilsXml.textToDom(blockInfo['blockxml']) : blockInfo['blockxml']) as Element; gap = parseInt(xml.getAttribute('gap')!); } @@ -825,7 +807,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { // // The default gap is 24, can be set larger or smaller. // This overwrites the gap attribute on the previous element. - const newGap = parseInt(sepInfo['gap']!.toString()); + const newGap = parseInt(String(sepInfo['gap'])); // Ignore gaps before the first block. if (!isNaN(newGap) && gaps.length > 0) { gaps[gaps.length - 1] = newGap; @@ -1075,13 +1057,13 @@ export abstract class Flyout extends DeleteArea implements IFlyout { */ protected moveRectToBlock_(rect: SVGElement, block: BlockSvg) { const blockHW = block.getHeightWidth(); - rect.setAttribute('width', blockHW.width.toString()); - rect.setAttribute('height', blockHW.height.toString()); + rect.setAttribute('width', String(blockHW.width)); + rect.setAttribute('height', String(blockHW.height)); const blockXY = block.getRelativeToSurfaceXY(); - rect.setAttribute('y', blockXY.y.toString()); + rect.setAttribute('y', String(blockXY.y)); rect.setAttribute( - 'x', (this.RTL ? blockXY.x - blockHW.width : blockXY.x).toString()); + 'x', String(this.RTL ? blockXY.x - blockHW.width : blockXY.x)); } /** diff --git a/core/flyout_button.ts b/core/flyout_button.ts index 9faa5671e..8a91d1c63 100644 --- a/core/flyout_button.ts +++ b/core/flyout_button.ts @@ -25,8 +25,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a button or label in the flyout. - * - * @alias Blockly.FlyoutButton */ export class FlyoutButton { /** The horizontal margin around the text in the button. */ @@ -34,6 +32,10 @@ export class FlyoutButton { /** The vertical margin around the text in the button. */ static TEXT_MARGIN_Y = 2; + + /** The radius of the flyout button's borders. */ + static BORDER_RADIUS = 4; + private readonly text_: string; private readonly position_: Coordinate; private readonly callbackKey_: string; @@ -104,8 +106,8 @@ export class FlyoutButton { shadow = dom.createSvgElement( Svg.RECT, { 'class': 'blocklyFlyoutButtonShadow', - 'rx': 4, - 'ry': 4, + 'rx': FlyoutButton.BORDER_RADIUS, + 'ry': FlyoutButton.BORDER_RADIUS, 'x': 1, 'y': 1, }, @@ -116,8 +118,8 @@ export class FlyoutButton { Svg.RECT, { 'class': this.isLabel_ ? 'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground', - 'rx': 4, - 'ry': 4, + 'rx': FlyoutButton.BORDER_RADIUS, + 'ry': FlyoutButton.BORDER_RADIUS, }, this.svgGroup_!); @@ -153,17 +155,17 @@ export class FlyoutButton { if (!this.isLabel_) { this.width += 2 * FlyoutButton.TEXT_MARGIN_X; this.height += 2 * FlyoutButton.TEXT_MARGIN_Y; - shadow?.setAttribute('width', this.width.toString()); - shadow?.setAttribute('height', this.height.toString()); + shadow?.setAttribute('width', String(this.width)); + shadow?.setAttribute('height', String(this.height)); } - rect.setAttribute('width', this.width.toString()); - rect.setAttribute('height', this.height.toString()); + rect.setAttribute('width', String(this.width)); + rect.setAttribute('height', String(this.height)); - svgText.setAttribute('x', (this.width / 2).toString()); + svgText.setAttribute('x', String(this.width / 2)); svgText.setAttribute( 'y', - (this.height / 2 - fontMetrics.height / 2 + fontMetrics.baseline) - .toString()); + String( + this.height / 2 - fontMetrics.height / 2 + fontMetrics.baseline)); this.updateTransform_(); diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index 634fd41a4..5a0c96f84 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -27,8 +27,6 @@ import * as WidgetDiv from './widgetdiv.js'; /** * Class for a flyout. - * - * @alias Blockly.HorizontalFlyout */ export class HorizontalFlyout extends Flyout { override horizontalLayout = true; diff --git a/core/flyout_metrics_manager.ts b/core/flyout_metrics_manager.ts index e8f4e0401..48ca9379a 100644 --- a/core/flyout_metrics_manager.ts +++ b/core/flyout_metrics_manager.ts @@ -20,8 +20,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Calculates metrics for a flyout's workspace. * The metrics are mainly used to size scrollbars for the flyout. - * - * @alias Blockly.FlyoutMetricsManager */ export class FlyoutMetricsManager extends MetricsManager { /** The flyout that owns the workspace to calculate metrics for. */ diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index fa9d1ad39..b6c1ae7c2 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -27,8 +27,6 @@ import * as WidgetDiv from './widgetdiv.js'; /** * Class for a flyout. - * - * @alias Blockly.VerticalFlyout */ export class VerticalFlyout extends Flyout { /** The name of the vertical flyout in the registry. */ diff --git a/core/generator.ts b/core/generator.ts index e78bd4b41..e3261dfa5 100644 --- a/core/generator.ts +++ b/core/generator.ts @@ -24,7 +24,6 @@ import type {Workspace} from './workspace.js'; * Class for a code generator that translates the blocks into a language. * * @unrestricted - * @alias Blockly.CodeGenerator */ export class CodeGenerator { name_: string; @@ -278,7 +277,10 @@ export class CodeGenerator { // Value blocks must return code and order of operations info. // Statement blocks must only return code. if (!Array.isArray(tuple)) { - throw TypeError('Expecting tuple from value block: ' + targetBlock.type); + throw TypeError( + `Expecting tuple from value block: ${targetBlock.type} See ` + + `developers.google.com/blockly/guides/create-custom-blocks/generating-code ` + + `for more information`); } let code = tuple[0]; const innerOrder = tuple[1]; diff --git a/core/gesture.ts b/core/gesture.ts index 935aa37d8..279d3527c 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -51,8 +51,6 @@ const ZOOM_OUT_MULTIPLIER = 6; /** * Class for one gesture. - * - * @alias Blockly.Gesture */ export class Gesture { /** @@ -104,16 +102,11 @@ export class Gesture { private hasExceededDragRadius_ = false; /** - * A handle to use to unbind a pointermove listener at the end of a drag. - * Opaque data returned from Blockly.bindEventWithChecks_. + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. */ - protected onMoveWrapper_: browserEvents.Data|null = null; - - /** - * A handle to use to unbind a pointerup listener at the end of a drag. - * Opaque data returned from Blockly.bindEventWithChecks_. - */ - protected onUpWrapper_: browserEvents.Data|null = null; + private boundEvents: browserEvents.Data[] = []; /** The object tracking a bubble drag, or null if none is in progress. */ private bubbleDragger_: BubbleDragger|null = null; @@ -160,13 +153,6 @@ export class Gesture { /** The starting distance between two touch points. */ private startDistance_ = 0; - /** - * A handle to use to unbind the second pointerdown listener - * at the end of a drag. - * Opaque data returned from Blockly.bindEventWithChecks_. - */ - private onStartWrapper_: browserEvents.Data|null = null; - /** Boolean for whether or not the workspace supports pinch-zoom. */ private isPinchZoomEnabled_: boolean|null = null; @@ -211,12 +197,10 @@ export class Gesture { // Clear the owner's reference to this gesture. this.creatorWorkspace.clearGesture(); - if (this.onMoveWrapper_) { - browserEvents.unbind(this.onMoveWrapper_); - } - if (this.onUpWrapper_) { - browserEvents.unbind(this.onUpWrapper_); + for (const event of this.boundEvents) { + browserEvents.unbind(event); } + this.boundEvents.length = 0; if (this.blockDragger_) { this.blockDragger_.dispose(); @@ -224,10 +208,6 @@ export class Gesture { if (this.workspaceDragger_) { this.workspaceDragger_.dispose(); } - - if (this.onStartWrapper_) { - browserEvents.unbind(this.onStartWrapper_); - } } /** @@ -513,15 +493,15 @@ export class Gesture { * @internal */ bindMouseEvents(e: PointerEvent) { - this.onStartWrapper_ = browserEvents.conditionalBind( + this.boundEvents.push(browserEvents.conditionalBind( document, 'pointerdown', null, this.handleStart.bind(this), - /* opt_noCaptureIdentifier */ true); - this.onMoveWrapper_ = browserEvents.conditionalBind( + /* opt_noCaptureIdentifier */ true)); + this.boundEvents.push(browserEvents.conditionalBind( document, 'pointermove', null, this.handleMove.bind(this), - /* opt_noCaptureIdentifier */ true); - this.onUpWrapper_ = browserEvents.conditionalBind( + /* opt_noCaptureIdentifier */ true)); + this.boundEvents.push(browserEvents.conditionalBind( document, 'pointerup', null, this.handleUp.bind(this), - /* opt_noCaptureIdentifier */ true); + /* opt_noCaptureIdentifier */ true)); e.preventDefault(); e.stopPropagation(); @@ -969,14 +949,14 @@ export class Gesture { * @param field The field the gesture started on. * @internal */ - setStartField(field: Field) { + setStartField(field: Field) { if (this.hasStarted_) { throw Error( 'Tried to call gesture.setStartField, ' + 'but the gesture had already been started.'); } if (!this.startField_) { - this.startField_ = field; + this.startField_ = field as Field; } } diff --git a/core/grid.ts b/core/grid.ts index 6a939322b..079ae5d19 100644 --- a/core/grid.ts +++ b/core/grid.ts @@ -20,8 +20,6 @@ import {GridOptions} from './options.js'; /** * Class for a workspace's grid. - * - * @alias Blockly.Grid */ export class Grid { private readonly spacing: number; @@ -91,11 +89,10 @@ export class Grid { * @internal */ update(scale: number) { - // MSIE freaks if it sees a 0x0 pattern, so set empty patterns to 100x100. - const safeSpacing = this.spacing * scale || 100; + const safeSpacing = this.spacing * scale; - this.pattern.setAttribute('width', safeSpacing.toString()); - this.pattern.setAttribute('height', safeSpacing.toString()); + this.pattern.setAttribute('width', `${safeSpacing}`); + this.pattern.setAttribute('height', `${safeSpacing}`); let half = Math.floor(this.spacing / 2) + 0.5; let start = half - this.length / 2; @@ -124,11 +121,11 @@ export class Grid { line: SVGElement, width: number, x1: number, x2: number, y1: number, y2: number) { if (line) { - line.setAttribute('stroke-width', width.toString()); - line.setAttribute('x1', x1.toString()); - line.setAttribute('y1', y1.toString()); - line.setAttribute('x2', x2.toString()); - line.setAttribute('y2', y2.toString()); + line.setAttribute('stroke-width', `${width}`); + line.setAttribute('x1', `${x1}`); + line.setAttribute('y1', `${y1}`); + line.setAttribute('x2', `${x2}`); + line.setAttribute('y2', `${y2}`); } } @@ -141,8 +138,8 @@ export class Grid { * @internal */ moveTo(x: number, y: number) { - this.pattern.setAttribute('x', x.toString()); - this.pattern.setAttribute('y', y.toString()); + this.pattern.setAttribute('x', `${x}`); + this.pattern.setAttribute('y', `${y}`); } /** diff --git a/core/icon.ts b/core/icon.ts index 83051610a..5d8002165 100644 --- a/core/icon.ts +++ b/core/icon.ts @@ -25,8 +25,6 @@ import * as deprecation from './utils/deprecation.js'; /** * Class for an icon. - * - * @alias Blockly.Icon */ export abstract class Icon { protected block_: BlockSvg|null; @@ -81,8 +79,10 @@ export abstract class Icon { /** Dispose of this icon. */ dispose() { - dom.removeNode(this.iconGroup_); // Dispose of and unlink the icon. - this.setVisible(false); // Dispose of and unlink the bubble. + if (!this.getBlock().isDeadOrDying()) { + dom.removeNode(this.iconGroup_); + } + this.setVisible(false); // Dispose of and unlink the bubble. } /** Add or remove the UI indicating if this icon may be clicked or not. */ diff --git a/core/inject.ts b/core/inject.ts index 71a359edb..a02ee52b3 100644 --- a/core/inject.ts +++ b/core/inject.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Functions for injecting Blockly into a web page. - * - * @namespace Blockly.inject - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.inject'); @@ -41,7 +36,6 @@ import {WorkspaceSvg} from './workspace_svg.js'; * @param container Containing element, or its ID, or a CSS selector. * @param opt_options Optional dictionary of options. * @returns Newly created main workspace. - * @alias Blockly.inject */ export function inject( container: Element|string, opt_options?: BlocklyOptions): WorkspaceSvg { @@ -104,7 +98,7 @@ export function inject( * @param options Dictionary of options. * @returns Newly created SVG image. */ -function createDom(container: Element, options: Options): Element { +function createDom(container: Element, options: Options): SVGElement { // Sadly browsers (Chrome vs Firefox) are currently inconsistent in laying // out content in RTL mode. Therefore Blockly forces the use of LTR, // then manually positions content in RTL as needed. @@ -159,7 +153,7 @@ function createDom(container: Element, options: Options): Element { * @returns Newly created main workspace. */ function createMainWorkspace( - svg: Element, options: Options, blockDragSurface: BlockDragSurfaceSvg, + svg: SVGElement, options: Options, blockDragSurface: BlockDragSurfaceSvg, workspaceDragSurface: WorkspaceDragSurfaceSvg): WorkspaceSvg { options.parentWorkspace = null; const mainWorkspace = diff --git a/core/input.ts b/core/input.ts index 5b69e566a..09a8a2dc6 100644 --- a/core/input.ts +++ b/core/input.ts @@ -26,8 +26,6 @@ import type {RenderedConnection} from './rendered_connection.js'; /** * Class for an input with an optional field. - * - * @alias Blockly.Input */ export class Input { private sourceBlock: Block; @@ -128,7 +126,7 @@ export class Input { } if (this.sourceBlock.rendered) { - (this.sourceBlock as BlockSvg).render(); + (this.sourceBlock as BlockSvg).queueRender(); // Adding a field will cause the block to change shape. this.sourceBlock.bumpNeighbours(); } @@ -150,7 +148,7 @@ export class Input { field.dispose(); this.fieldRow.splice(i, 1); if (this.sourceBlock.rendered) { - (this.sourceBlock as BlockSvg).render(); + (this.sourceBlock as BlockSvg).queueRender(); // Removing a field will cause the block to change shape. this.sourceBlock.bumpNeighbours(); } @@ -246,7 +244,7 @@ export class Input { this.align = align; if (this.sourceBlock.rendered) { const sourceBlock = this.sourceBlock as BlockSvg; - sourceBlock.render(); + sourceBlock.queueRender(); } return this; } @@ -306,7 +304,6 @@ export namespace Input { /** * Enum for alignment of inputs. * - * @alias Blockly.Input.Align */ export enum Align { LEFT = -1, diff --git a/core/input_types.ts b/core/input_types.ts index 0ea695e89..8f50346ad 100644 --- a/core/input_types.ts +++ b/core/input_types.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An enum for the possible types of inputs. - * - * @namespace Blockly.inputTypes - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.inputTypes'); @@ -17,8 +12,6 @@ import {ConnectionType} from './connection_type.js'; /** * Enum for the type of a connection or input. - * - * @alias Blockly.inputTypes */ export enum inputTypes { // A right-facing value input. E.g. 'set item to' or 'return'. diff --git a/core/insertion_marker_manager.ts b/core/insertion_marker_manager.ts index 278809a7d..7f53caa0d 100644 --- a/core/insertion_marker_manager.ts +++ b/core/insertion_marker_manager.ts @@ -17,7 +17,6 @@ import type {BlockSvg} from './block_svg.js'; import * as common from './common.js'; import {ComponentManager} from './component_manager.js'; import {config} from './config.js'; -import {ConnectionType} from './connection_type.js'; import * as constants from './constants.js'; import * as eventUtils from './events/utils.js'; import type {IDeleteArea} from './interfaces/i_delete_area.js'; @@ -56,8 +55,6 @@ const DUPLICATE_BLOCK_ERROR = 'The insertion marker ' + * Class that controls updates to connections during drags. It is primarily * responsible for finding the closest eligible connection and highlighting or * unhighlighting it as needed during a drag. - * - * @alias Blockly.InsertionMarkerManager */ export class InsertionMarkerManager { /** @@ -135,6 +132,11 @@ export class InsertionMarkerManager { this.firstMarker = this.createMarkerBlock(this.topBlock); this.availableConnections = this.initAvailableConnections(); + + if (this.lastOnStack) { + this.lastMarker = + this.createMarkerBlock(this.lastOnStack.getSourceBlock()); + } } /** @@ -144,18 +146,8 @@ export class InsertionMarkerManager { */ dispose() { this.availableConnections.length = 0; - - eventUtils.disable(); - try { - if (this.firstMarker) { - this.firstMarker.dispose(); - } - if (this.lastMarker) { - this.lastMarker.dispose(); - } - } finally { - eventUtils.enable(); - } + this.disposeInsertionMarker(this.firstMarker); + this.disposeInsertionMarker(this.lastMarker); } /** @@ -187,21 +179,22 @@ export class InsertionMarkerManager { */ applyConnections() { if (!this.activeCandidate) return; - // Don't fire events for insertion markers. + const {local, closest} = this.activeCandidate; + local.connect(closest); eventUtils.disable(); this.hidePreview(); eventUtils.enable(); - const {local, closest} = this.activeCandidate; - // Connect two blocks together. - local.connect(closest); if (this.topBlock.rendered) { - // Trigger a connection animation. - // Determine which connection is inferior (lower in the source stack). const inferiorConnection = local.isSuperior() ? closest : local; blockAnimations.connectionUiEffect(inferiorConnection.getSourceBlock()); - // Bring the just-edited stack to the front. const rootBlock = this.topBlock.getRootBlock(); - rootBlock.bringToFront(); + + // bringToFront is incredibly expensive. Delay by at least a frame. + requestAnimationFrame(() => { + setTimeout(() => { + rootBlock.bringToFront(); + }, 0); + }); } } @@ -289,10 +282,8 @@ export class InsertionMarkerManager { } /** - * Populate the list of available connections on this block stack. This - * should only be called once, at the beginning of a drag. If the stack has - * more than one block, this function will populate lastOnStack and create - * the corresponding insertion marker. + * Populate the list of available connections on this block stack. If the + * stack has more than one block, this function will also update lastOnStack. * * @returns A list of available connections. */ @@ -303,15 +294,6 @@ export class InsertionMarkerManager { if (lastOnStack && lastOnStack !== this.topBlock.nextConnection) { available.push(lastOnStack); this.lastOnStack = lastOnStack; - if (this.lastMarker) { - eventUtils.disable(); - try { - this.lastMarker.dispose(); - } finally { - eventUtils.enable(); - } - } - this.lastMarker = this.createMarkerBlock(lastOnStack.getSourceBlock()); } return available; } @@ -561,8 +543,17 @@ export class InsertionMarkerManager { // probably recreate the marker block (e.g. in getCandidate_), which is // called more often during the drag, but creating a block that often // might be too slow, so we only do it if necessary. - this.firstMarker = this.createMarkerBlock(this.topBlock); - insertionMarker = isLastInStack ? this.lastMarker : this.firstMarker; + if (isLastInStack && this.lastOnStack) { + this.disposeInsertionMarker(this.lastMarker); + this.lastMarker = + this.createMarkerBlock(this.lastOnStack.getSourceBlock()); + insertionMarker = this.lastMarker; + } else { + this.disposeInsertionMarker(this.firstMarker); + this.firstMarker = this.createMarkerBlock(this.topBlock); + insertionMarker = this.firstMarker; + } + if (!insertionMarker) { throw new Error( 'Cannot show the insertion marker because there is no insertion ' + @@ -611,38 +602,16 @@ export class InsertionMarkerManager { const markerConn = this.markerConnection; const imBlock = markerConn.getSourceBlock(); - const markerNext = imBlock.nextConnection; const markerPrev = imBlock.previousConnection; const markerOutput = imBlock.outputConnection; - const isNext = markerConn === markerNext; - - const isFirstInStatementStack = - isNext && !(markerPrev && markerPrev.targetConnection); - - const isFirstInOutputStack = - markerConn.type === ConnectionType.INPUT_VALUE && - !(markerOutput && markerOutput.targetConnection); - // The insertion marker is the first block in a stack. Unplug won't do - // anything in that case. Instead, unplug the following block. - if (isFirstInStatementStack || isFirstInOutputStack) { - markerConn.targetBlock()!.unplug(false); - } else if (markerConn.type === ConnectionType.NEXT_STATEMENT && !isNext) { - // Inside of a C-block, first statement connection. - const innerConnection = markerConn.targetConnection; - if (innerConnection) { - innerConnection.getSourceBlock().unplug(false); - } - - const previousBlockNextConnection = - markerPrev ? markerPrev.targetConnection : null; - - imBlock.unplug(true); - if (previousBlockNextConnection && innerConnection) { - previousBlockNextConnection.connect(innerConnection); - } + if (!markerPrev?.targetConnection && !markerOutput?.targetConnection) { + // If we are the top block, unplugging doesn't do anything. + // The marker connection may not have a target block if we are hiding + // as part of applying connections. + markerConn.targetBlock()?.unplug(false); } else { - imBlock.unplug(/* healStack */ true); + imBlock.unplug(true); } if (markerConn.targetConnection) { @@ -728,6 +697,20 @@ export class InsertionMarkerManager { } return result; } + + /** + * Safely disposes of an insertion marker. + */ + private disposeInsertionMarker(marker: BlockSvg|null) { + if (marker) { + eventUtils.disable(); + try { + marker.dispose(); + } finally { + eventUtils.enable(); + } + } + } } export namespace InsertionMarkerManager { diff --git a/core/interfaces/i_ast_node_location.ts b/core/interfaces/i_ast_node_location.ts index 814873852..36c5e7eec 100644 --- a/core/interfaces/i_ast_node_location.ts +++ b/core/interfaces/i_ast_node_location.ts @@ -4,18 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an AST node location. - * - * @namespace Blockly.IASTNodeLocation - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IASTNodeLocation'); /** * An AST node location interface. - * - * @alias Blockly.IASTNodeLocation */ export interface IASTNodeLocation {} diff --git a/core/interfaces/i_ast_node_location_svg.ts b/core/interfaces/i_ast_node_location_svg.ts index 8bc51ec26..0617b5d8e 100644 --- a/core/interfaces/i_ast_node_location_svg.ts +++ b/core/interfaces/i_ast_node_location_svg.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an AST node location SVG. - * - * @namespace Blockly.IASTNodeLocationSvg - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IASTNodeLocationSvg'); @@ -17,8 +12,6 @@ import type {IASTNodeLocation} from './i_ast_node_location.js'; /** * An AST node location SVG interface. - * - * @alias Blockly.IASTNodeLocationSvg */ export interface IASTNodeLocationSvg extends IASTNodeLocation { /** diff --git a/core/interfaces/i_ast_node_location_with_block.ts b/core/interfaces/i_ast_node_location_with_block.ts index cf54ddc41..56e12b3ee 100644 --- a/core/interfaces/i_ast_node_location_with_block.ts +++ b/core/interfaces/i_ast_node_location_with_block.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an AST node location that has an associated - * block. - * - * @namespace Blockly.IASTNodeLocationWithBlock - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IASTNodeLocationWithBlock'); @@ -19,8 +13,6 @@ import type {Block} from '../block.js'; /** * An AST node location that has an associated block. - * - * @alias Blockly.IASTNodeLocationWithBlock */ export interface IASTNodeLocationWithBlock extends IASTNodeLocation { /** diff --git a/core/interfaces/i_autohideable.ts b/core/interfaces/i_autohideable.ts index 542e3edf7..d7abcad1e 100644 --- a/core/interfaces/i_autohideable.ts +++ b/core/interfaces/i_autohideable.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a component that is automatically hidden - * when WorkspaceSvg.hideChaff is called. - * - * @namespace Blockly.IAutoHideable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IAutoHideable'); @@ -18,8 +12,6 @@ import type {IComponent} from './i_component.js'; /** * Interface for a component that can be automatically hidden. - * - * @alias Blockly.IAutoHideable */ export interface IAutoHideable extends IComponent { /** diff --git a/core/interfaces/i_block_dragger.ts b/core/interfaces/i_block_dragger.ts index 8fa4b9dda..d0418224f 100644 --- a/core/interfaces/i_block_dragger.ts +++ b/core/interfaces/i_block_dragger.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a block dragger. - * - * @namespace Blockly.IBlockDragger - */ import * as goog from '../../closure/goog/goog.js'; import type {Coordinate} from '../utils/coordinate.js'; import type {BlockSvg} from '../block_svg.js'; @@ -16,8 +11,6 @@ goog.declareModuleId('Blockly.IBlockDragger'); /** * A block dragger interface. - * - * @alias Blockly.IBlockDragger */ export interface IBlockDragger { /** diff --git a/core/interfaces/i_bounded_element.ts b/core/interfaces/i_bounded_element.ts index 8aae86285..870d7b1e8 100644 --- a/core/interfaces/i_bounded_element.ts +++ b/core/interfaces/i_bounded_element.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a bounded element. - * - * @namespace Blockly.IBoundedElement - */ import * as goog from '../../closure/goog/goog.js'; import type {Rect} from '../utils/rect.js'; goog.declareModuleId('Blockly.IBoundedElement'); /** * A bounded element interface. - * - * @alias Blockly.IBoundedElement */ export interface IBoundedElement { /** diff --git a/core/interfaces/i_bubble.ts b/core/interfaces/i_bubble.ts index f424af334..d8a1b686a 100644 --- a/core/interfaces/i_bubble.ts +++ b/core/interfaces/i_bubble.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a bubble. - * - * @namespace Blockly.IBubble - */ import * as goog from '../../closure/goog/goog.js'; import type {Coordinate} from '../utils/coordinate.js'; import type {BlockDragSurfaceSvg} from '../block_drag_surface.js'; @@ -20,8 +15,6 @@ import type {IDraggable} from './i_draggable.js'; /** * A bubble interface. - * - * @alias Blockly.IBubble */ export interface IBubble extends IDraggable, IContextMenu { /** diff --git a/core/interfaces/i_collapsible_toolbox_item.ts b/core/interfaces/i_collapsible_toolbox_item.ts index a7d8e9153..8e499e276 100644 --- a/core/interfaces/i_collapsible_toolbox_item.ts +++ b/core/interfaces/i_collapsible_toolbox_item.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a collapsible toolbox item. - * - * @namespace Blockly.ICollapsibleToolboxItem - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.ICollapsibleToolboxItem'); @@ -18,8 +13,6 @@ import type {IToolboxItem} from './i_toolbox_item.js'; /** * Interface for an item in the toolbox that can be collapsed. - * - * @alias Blockly.ICollapsibleToolboxItem */ export interface ICollapsibleToolboxItem extends ISelectableToolboxItem { /** diff --git a/core/interfaces/i_component.ts b/core/interfaces/i_component.ts index f75a6b014..3a55702fd 100644 --- a/core/interfaces/i_component.ts +++ b/core/interfaces/i_component.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Interface for a workspace component that can be registered with - * the ComponentManager. - * - * @namespace Blockly.IComponent - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IComponent'); @@ -17,8 +11,6 @@ goog.declareModuleId('Blockly.IComponent'); /** * The interface for a workspace component that can be registered with the * ComponentManager. - * - * @alias Blockly.IComponent */ export interface IComponent { /** diff --git a/core/interfaces/i_connection_checker.ts b/core/interfaces/i_connection_checker.ts index deb3c59fa..4384511cc 100644 --- a/core/interfaces/i_connection_checker.ts +++ b/core/interfaces/i_connection_checker.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that encapsulates logic for - * checking whether a potential connection is safe and valid. - * - * @namespace Blockly.IConnectionChecker - */ import * as goog from '../../closure/goog/goog.js'; import type {Connection} from '../connection.js'; import type {RenderedConnection} from '../rendered_connection.js'; @@ -17,8 +11,6 @@ goog.declareModuleId('Blockly.IConnectionChecker'); /** * Class for connection type checking logic. - * - * @alias Blockly.IConnectionChecker */ export interface IConnectionChecker { /** diff --git a/core/interfaces/i_contextmenu.ts b/core/interfaces/i_contextmenu.ts index b0a28630e..f205e9e2e 100644 --- a/core/interfaces/i_contextmenu.ts +++ b/core/interfaces/i_contextmenu.ts @@ -4,16 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that supports a right-click. - * - * @namespace Blockly.IContextMenu - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IContextMenu'); -/** @alias Blockly.IContextMenu */ export interface IContextMenu { /** * Show the context menu for this object. diff --git a/core/interfaces/i_copyable.ts b/core/interfaces/i_copyable.ts index 9c780a317..cd3fe3678 100644 --- a/core/interfaces/i_copyable.ts +++ b/core/interfaces/i_copyable.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that is copyable. - * - * @namespace Blockly.ICopyable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.ICopyable'); @@ -16,7 +11,6 @@ import type {WorkspaceSvg} from '../workspace_svg.js'; import type {ISelectable} from './i_selectable.js'; -/** @alias Blockly.ICopyable */ export interface ICopyable extends ISelectable { /** * Encode for copying. @@ -31,7 +25,7 @@ export namespace ICopyable { export interface CopyData { saveInfo: Object|Element; source: WorkspaceSvg; - typeCounts: Object|null; + typeCounts: {[key: string]: number}|null; } } diff --git a/core/interfaces/i_deletable.ts b/core/interfaces/i_deletable.ts index 4a1683574..3593dd878 100644 --- a/core/interfaces/i_deletable.ts +++ b/core/interfaces/i_deletable.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that is deletable. - * - * @namespace Blockly.IDeletable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IDeletable'); /** * The interface for an object that can be deleted. - * - * @alias Blockly.IDeletable */ export interface IDeletable { /** diff --git a/core/interfaces/i_delete_area.ts b/core/interfaces/i_delete_area.ts index 1d9752b05..9a72ec779 100644 --- a/core/interfaces/i_delete_area.ts +++ b/core/interfaces/i_delete_area.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a component that can delete a block or bubble - * that is dropped on top of it. - * - * @namespace Blockly.IDeleteArea - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IDeleteArea'); @@ -20,8 +14,6 @@ import type {IDraggable} from './i_draggable.js'; /** * Interface for a component that can delete a block or bubble that is dropped * on top of it. - * - * @alias Blockly.IDeleteArea */ export interface IDeleteArea extends IDragTarget { /** diff --git a/core/interfaces/i_drag_target.ts b/core/interfaces/i_drag_target.ts index f1e1b3c97..5d2ba2bb8 100644 --- a/core/interfaces/i_drag_target.ts +++ b/core/interfaces/i_drag_target.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a component that has a handler for when a - * block is dropped on top of it. - * - * @namespace Blockly.IDragTarget - */ import * as goog from '../../closure/goog/goog.js'; import {Rect} from '../utils/rect.js'; @@ -23,8 +17,6 @@ import type {IComponent} from './i_component.js'; /** * Interface for a component with custom behaviour when a block or bubble is * dragged over or dropped on top of it. - * - * @alias Blockly.IDragTarget */ export interface IDragTarget extends IComponent { /** diff --git a/core/interfaces/i_draggable.ts b/core/interfaces/i_draggable.ts index 313525d5e..49e6976ca 100644 --- a/core/interfaces/i_draggable.ts +++ b/core/interfaces/i_draggable.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that is draggable. - * - * @namespace Blockly.IDraggable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IDraggable'); @@ -17,7 +12,5 @@ import type {IDeletable} from './i_deletable.js'; /** * The interface for an object that can be dragged. - * - * @alias Blockly.IDraggable */ export interface IDraggable extends IDeletable {} diff --git a/core/interfaces/i_flyout.ts b/core/interfaces/i_flyout.ts index 825660686..5f8503161 100644 --- a/core/interfaces/i_flyout.ts +++ b/core/interfaces/i_flyout.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a flyout. - * - * @namespace Blockly.IFlyout - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IFlyout'); @@ -22,8 +17,6 @@ import type {IRegistrable} from './i_registrable.js'; /** * Interface for a flyout. - * - * @alias Blockly.IFlyout */ export interface IFlyout extends IRegistrable { /** Whether the flyout is laid out horizontally or not. */ diff --git a/core/interfaces/i_keyboard_accessible.ts b/core/interfaces/i_keyboard_accessible.ts index d60fb0224..aa00c4420 100644 --- a/core/interfaces/i_keyboard_accessible.ts +++ b/core/interfaces/i_keyboard_accessible.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for objects that handle keyboard shortcuts. - * - * @namespace Blockly.IKeyboardAccessible - */ import * as goog from '../../closure/goog/goog.js'; import {KeyboardShortcut} from '../shortcut_registry.js'; goog.declareModuleId('Blockly.IKeyboardAccessible'); /** * An interface for an object that handles keyboard shortcuts. - * - * @alias Blockly.IKeyboardAccessible */ export interface IKeyboardAccessible { /** diff --git a/core/interfaces/i_legacy_procedure_blocks.ts b/core/interfaces/i_legacy_procedure_blocks.ts new file mode 100644 index 000000000..410048e4e --- /dev/null +++ b/core/interfaces/i_legacy_procedure_blocks.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + + +/** + * Legacy means of representing a procedure signature. The elements are + * respectively: name, parameter names, and whether it has a return value. + */ +export type ProcedureTuple = [string, string[], boolean]; + +/** + * Procedure block type. + * + * @internal + */ +export interface ProcedureBlock { + getProcedureCall: () => string; + renameProcedure: (p1: string, p2: string) => void; + getProcedureDef: () => ProcedureTuple; +} + +/** @internal */ +export interface LegacyProcedureDefBlock { + getProcedureDef: () => ProcedureTuple +} + +/** @internal */ +export function isLegacyProcedureDefBlock(block: Object): + block is LegacyProcedureDefBlock { + return (block as any).getProcedureDef !== undefined; +} + +/** @internal */ +export interface LegacyProcedureCallBlock { + getProcedureCall: () => string; + renameProcedure: (p1: string, p2: string) => void; +} + +/** @internal */ +export function isLegacyProcedureCallBlock(block: Object): + block is LegacyProcedureCallBlock { + return (block as any).getProcedureCall !== undefined && + (block as any).renameProcedure !== undefined; +} diff --git a/core/interfaces/i_metrics_manager.ts b/core/interfaces/i_metrics_manager.ts index 923ad8035..a3d28d0fa 100644 --- a/core/interfaces/i_metrics_manager.ts +++ b/core/interfaces/i_metrics_manager.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a metrics manager. - * - * @namespace Blockly.IMetricsManager - */ import * as goog from '../../closure/goog/goog.js'; import type {ContainerRegion, ToolboxMetrics, AbsoluteMetrics, UiMetrics} from '../metrics_manager.js'; import type {Size} from '../utils/size.js'; @@ -17,8 +12,6 @@ goog.declareModuleId('Blockly.IMetricsManager'); /** * Interface for a metrics manager. - * - * @alias Blockly.IMetricsManager */ export interface IMetricsManager { /** @@ -47,11 +40,14 @@ export interface IMetricsManager { opt_contentMetrics?: ContainerRegion): ContainerRegion; /** - * Gets the width and the height of the flyout on the workspace in pixel - * coordinates. Returns 0 for the width and height if the workspace has a - * category toolbox instead of a simple toolbox. + * Gets the width and the height of the flyout in pixel + * coordinates. By default, will get metrics for either a simple flyout (owned + * directly by the workspace) or for the flyout owned by the toolbox. If you + * pass `opt_own` as `true` then only metrics for the simple flyout will be + * returned, and it will return 0 for the width and height if the workspace + * has a category toolbox instead of a simple toolbox. * - * @param opt_own Whether to only return the workspace's own flyout. + * @param opt_own Whether to only return the workspace's own flyout metrics. * @returns The width and height of the flyout. */ getFlyoutMetrics(opt_own?: boolean): ToolboxMetrics; @@ -60,8 +56,7 @@ export interface IMetricsManager { * Gets the width, height and position of the toolbox on the workspace in * pixel coordinates. Returns 0 for the width and height if the workspace has * a simple toolbox instead of a category toolbox. To get the width and height - * of a - * simple toolbox @see {@link IMetricsManager#getFlyoutMetrics}. + * of a simple toolbox, see {@link IMetricsManager#getFlyoutMetrics}. * * @returns The object with the width, height and position of the toolbox. */ diff --git a/core/interfaces/i_movable.ts b/core/interfaces/i_movable.ts index eed624de9..2c249273a 100644 --- a/core/interfaces/i_movable.ts +++ b/core/interfaces/i_movable.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that is movable. - * - * @namespace Blockly.IMovable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IMovable'); /** * The interface for an object that is movable. - * - * @alias Blockly.IMovable */ export interface IMovable { /** diff --git a/core/interfaces/i_positionable.ts b/core/interfaces/i_positionable.ts index 7edf0c694..52ad96f90 100644 --- a/core/interfaces/i_positionable.ts +++ b/core/interfaces/i_positionable.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a positionable UI element. - * - * @namespace Blockly.IPositionable - */ import * as goog from '../../closure/goog/goog.js'; import type {Rect} from '../utils/rect.js'; import type {UiMetrics} from '../metrics_manager.js'; @@ -19,8 +14,6 @@ import type {IComponent} from './i_component.js'; /** * Interface for a component that is positioned on top of the workspace. - * - * @alias Blockly.IPositionable */ export interface IPositionable extends IComponent { /** diff --git a/core/interfaces/i_procedure_block.ts b/core/interfaces/i_procedure_block.ts index 57318ba85..133441013 100644 --- a/core/interfaces/i_procedure_block.ts +++ b/core/interfaces/i_procedure_block.ts @@ -5,15 +5,22 @@ */ import type {Block} from '../block.js'; +import {IProcedureModel} from './i_procedure_model.js'; +import * as goog from '../../closure/goog/goog.js'; +goog.declareModuleId('Blockly.procedures.IProcedureBlock'); /** The interface for a block which models a procedure. */ export interface IProcedureBlock { + getProcedureModel(): IProcedureModel; doProcedureUpdate(): void; + isProcedureDef(): boolean; } /** A type guard which checks if the given block is a procedure block. */ export function isProcedureBlock(block: Block| IProcedureBlock): block is IProcedureBlock { - return (block as IProcedureBlock).doProcedureUpdate !== undefined; + return (block as IProcedureBlock).getProcedureModel !== undefined && + (block as IProcedureBlock).doProcedureUpdate !== undefined && + (block as IProcedureBlock).isProcedureDef !== undefined; } diff --git a/core/interfaces/i_procedure_model.ts b/core/interfaces/i_procedure_model.ts index 1950fff76..dffdc984e 100644 --- a/core/interfaces/i_procedure_model.ts +++ b/core/interfaces/i_procedure_model.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for the data model of a procedure. - * - * @namespace Blockly.IProcedureModel - */ import {IParameterModel} from './i_parameter_model.js'; diff --git a/core/interfaces/i_registrable.ts b/core/interfaces/i_registrable.ts index 9faa55e9a..f95e3c559 100644 --- a/core/interfaces/i_registrable.ts +++ b/core/interfaces/i_registrable.ts @@ -4,19 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a Blockly component that can be registered. - * (Ex. Toolbox, Fields, Renderers) - * - * @namespace Blockly.IRegistrable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IRegistrable'); /** * The interface for a Blockly component that can be registered. - * - * @alias Blockly.IRegistrable */ export interface IRegistrable {} diff --git a/core/interfaces/i_selectable.ts b/core/interfaces/i_selectable.ts index a29bdb9cb..0e99a5847 100644 --- a/core/interfaces/i_selectable.ts +++ b/core/interfaces/i_selectable.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that is selectable. - * - * @namespace Blockly.ISelectable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.ISelectable'); @@ -18,8 +13,6 @@ import type {IMovable} from './i_movable.js'; /** * The interface for an object that is selectable. - * - * @alias Blockly.ISelectable */ export interface ISelectable extends IDeletable, IMovable { id: string; diff --git a/core/interfaces/i_selectable_toolbox_item.ts b/core/interfaces/i_selectable_toolbox_item.ts index e7fe06f86..8f454372b 100644 --- a/core/interfaces/i_selectable_toolbox_item.ts +++ b/core/interfaces/i_selectable_toolbox_item.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a selectable toolbox item. - * - * @namespace Blockly.ISelectableToolboxItem - */ import * as goog from '../../closure/goog/goog.js'; import type {FlyoutItemInfoArray} from '../utils/toolbox'; goog.declareModuleId('Blockly.ISelectableToolboxItem'); @@ -18,8 +13,6 @@ import type {IToolboxItem} from './i_toolbox_item.js'; /** * Interface for an item in the toolbox that can be selected. - * - * @alias Blockly.ISelectableToolboxItem */ export interface ISelectableToolboxItem extends IToolboxItem { /** @@ -61,3 +54,11 @@ export interface ISelectableToolboxItem extends IToolboxItem { */ onClick(_e: Event): void; } + +/** + * Type guard that checks whether an IToolboxItem is an ISelectableToolboxItem. + */ +export function isSelectableToolboxItem(toolboxItem: IToolboxItem): + toolboxItem is ISelectableToolboxItem { + return toolboxItem.isSelectable(); +} diff --git a/core/interfaces/i_serializer.ts b/core/interfaces/i_serializer.ts index 3bf99fe4c..37efa4626 100644 --- a/core/interfaces/i_serializer.ts +++ b/core/interfaces/i_serializer.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The record type for an object containing functions for - * serializing part of the workspace. - * - * @namespace Blockly.serialization.ISerializer - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.serialization.ISerializer'); @@ -18,8 +12,6 @@ import type {Workspace} from '../workspace.js'; /** * Serializes and deserializes a plugin or system. - * - * @alias Blockly.serialization.ISerializer.ISerializer */ export interface ISerializer { /** diff --git a/core/interfaces/i_styleable.ts b/core/interfaces/i_styleable.ts index 7e98a6dc7..86d9f2c00 100644 --- a/core/interfaces/i_styleable.ts +++ b/core/interfaces/i_styleable.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that a style can be added to. - * - * @namespace Blockly.IStyleable - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IStyleable'); /** * Interface for an object that a style can be added to. - * - * @alias Blockly.IStyleable */ export interface IStyleable { /** diff --git a/core/interfaces/i_toolbox.ts b/core/interfaces/i_toolbox.ts index fdc021f5a..cb4eeceb4 100644 --- a/core/interfaces/i_toolbox.ts +++ b/core/interfaces/i_toolbox.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a toolbox. - * - * @namespace Blockly.IToolbox - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IToolbox'); @@ -21,8 +16,6 @@ import type {WorkspaceSvg} from '../workspace_svg.js'; /** * Interface for a toolbox. - * - * @alias Blockly.IToolbox */ export interface IToolbox extends IRegistrable { /** Initializes the toolbox. */ diff --git a/core/interfaces/i_toolbox_item.ts b/core/interfaces/i_toolbox_item.ts index a478cae5c..f7398acec 100644 --- a/core/interfaces/i_toolbox_item.ts +++ b/core/interfaces/i_toolbox_item.ts @@ -4,19 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for a toolbox item. - * - * @namespace Blockly.IToolboxItem - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.IToolboxItem'); /** * Interface for an item in the toolbox. - * - * @alias Blockly.IToolboxItem */ export interface IToolboxItem { /** diff --git a/core/interfaces/i_variable_backed_parameter_model.ts b/core/interfaces/i_variable_backed_parameter_model.ts new file mode 100644 index 000000000..39530b81e --- /dev/null +++ b/core/interfaces/i_variable_backed_parameter_model.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {VariableModel} from '../variable_model.js'; +import {IParameterModel} from './i_parameter_model.js'; + + +/** Interface for a parameter model that holds a variable model. */ +export interface IVariableBackedParameterModel extends IParameterModel { + /** Returns the variable model held by this type. */ + getVariableModel(): VariableModel; +} + +/** + * Returns whether the given object is a variable holder or not. + */ +export function isVariableBackedParameterModel(param: IParameterModel): + param is IVariableBackedParameterModel { + return (param as any).getVariableModel !== undefined; +} diff --git a/core/internal_constants.ts b/core/internal_constants.ts index d1bd27b48..5d6a0340d 100644 --- a/core/internal_constants.ts +++ b/core/internal_constants.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Module that provides constants for use inside Blockly. Do not - * use these constants outside of the core library. - * - * @namespace Blockly.internalConstants - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.internalConstants'); @@ -19,7 +13,6 @@ import {ConnectionType} from './connection_type.js'; /** * Number of characters to truncate a collapsed block to. * - * @alias Blockly.internalConstants.COLLAPSE_CHARS * @internal */ export const COLLAPSE_CHARS = 30; @@ -28,7 +21,6 @@ export const COLLAPSE_CHARS = 30; * When dragging a block out of a stack, split the stack in two (true), or drag * out the block healing the stack (false). * - * @alias Blockly.internalConstants.DRAG_STACK * @internal */ export const DRAG_STACK = true; @@ -36,7 +28,6 @@ export const DRAG_STACK = true; /** * Lookup table for determining the opposite type of a connection. * - * @alias Blockly.internalConstants.OPPOSITE_TYPE * @internal */ export const OPPOSITE_TYPE: number[] = []; @@ -52,7 +43,6 @@ OPPOSITE_TYPE[ConnectionType.PREVIOUS_STATEMENT] = * This string indicates that this option in the dropdown is 'Rename * variable...' and if selected, should trigger the prompt to rename a variable. * - * @alias Blockly.internalConstants.RENAME_VARIABLE_ID * @internal */ export const RENAME_VARIABLE_ID = 'RENAME_VARIABLE_ID'; @@ -62,7 +52,6 @@ export const RENAME_VARIABLE_ID = 'RENAME_VARIABLE_ID'; * This string indicates that this option in the dropdown is 'Delete the "%1" * variable' and if selected, should trigger the prompt to delete a variable. * - * @alias Blockly.internalConstants.DELETE_VARIABLE_ID * @internal */ export const DELETE_VARIABLE_ID = 'DELETE_VARIABLE_ID'; diff --git a/core/keyboard_nav/ast_node.ts b/core/keyboard_nav/ast_node.ts index 27d0a4554..624dc6a45 100644 --- a/core/keyboard_nav/ast_node.ts +++ b/core/keyboard_nav/ast_node.ts @@ -28,8 +28,6 @@ import type {Workspace} from '../workspace.js'; * Class for an AST node. * It is recommended that you use one of the createNode methods instead of * creating a node directly. - * - * @alias Blockly.ASTNode */ export class ASTNode { /** @@ -56,7 +54,6 @@ export class ASTNode { * Must be in ASTNode.types. * @param location The position in the AST. * @param opt_params Optional dictionary of options. - * @alias Blockly.ASTNode */ constructor(type: string, location: IASTNodeLocation, opt_params?: Params) { if (!location) { @@ -180,7 +177,7 @@ export class ASTNode { throw new Error( 'The current AST location is not associated with a block'); } - const curIdx = block.inputList.indexOf((input)); + const curIdx = block.inputList.indexOf(input); let fieldIdx = input.fieldRow.indexOf(location) + 1; for (let i = curIdx; i < block.inputList.length; i++) { const newInput = block.inputList[i]; @@ -243,7 +240,7 @@ export class ASTNode { throw new Error( 'The current AST location is not associated with a block'); } - const curIdx = block.inputList.indexOf((parentInput)); + const curIdx = block.inputList.indexOf(parentInput); let fieldIdx = parentInput.fieldRow.indexOf(location) - 1; for (let i = curIdx; i >= 0; i--) { const input = block.inputList[i]; @@ -422,6 +419,7 @@ export class ASTNode { case ASTNode.types.BLOCK: { const block = this.location_ as Block; const nextConnection = block.nextConnection; + if (!nextConnection) return null; return ASTNode.createConnectionNode(nextConnection); } case ASTNode.types.PREVIOUS: { @@ -496,6 +494,7 @@ export class ASTNode { case ASTNode.types.BLOCK: { const block = this.location_ as Block; const topConnection = getParentConnection(block); + if (!topConnection) return null; return ASTNode.createConnectionNode(topConnection); } case ASTNode.types.PREVIOUS: { @@ -746,7 +745,7 @@ export type Params = ASTNode.Params; * @param block The block to find the parent connection on. * @returns The connection connecting to the parent of the block. */ -function getParentConnection(block: Block): Connection { +function getParentConnection(block: Block): Connection|null { let topConnection = block.outputConnection; if (!topConnection || block.previousConnection && block.previousConnection.isConnected()) { diff --git a/core/keyboard_nav/basic_cursor.ts b/core/keyboard_nav/basic_cursor.ts index 648158fc6..5f0b4dfa4 100644 --- a/core/keyboard_nav/basic_cursor.ts +++ b/core/keyboard_nav/basic_cursor.ts @@ -23,14 +23,11 @@ import {Cursor} from './cursor.js'; * Class for a basic cursor. * This will allow the user to get to all nodes in the AST by hitting next or * previous. - * - * @alias Blockly.BasicCursor */ export class BasicCursor extends Cursor { /** Name used for registering a basic cursor. */ static readonly registrationName = 'basicCursor'; - /** @alias Blockly.BasicCursor */ constructor() { super(); } diff --git a/core/keyboard_nav/cursor.ts b/core/keyboard_nav/cursor.ts index 7fcf603e5..31ca083d6 100644 --- a/core/keyboard_nav/cursor.ts +++ b/core/keyboard_nav/cursor.ts @@ -22,13 +22,10 @@ import {Marker} from './marker.js'; /** * Class for a cursor. * A cursor controls how a user navigates the Blockly AST. - * - * @alias Blockly.Cursor */ export class Cursor extends Marker { override type = 'cursor'; - /** @alias Blockly.Cursor */ constructor() { super(); } diff --git a/core/keyboard_nav/marker.ts b/core/keyboard_nav/marker.ts index 725bc26e3..d569f3637 100644 --- a/core/keyboard_nav/marker.ts +++ b/core/keyboard_nav/marker.ts @@ -22,8 +22,6 @@ import type {ASTNode} from './ast_node.js'; /** * Class for a marker. * This is used in keyboard navigation to save a location in the Blockly AST. - * - * @alias Blockly.Marker */ export class Marker { /** The colour of the marker. */ diff --git a/core/keyboard_nav/tab_navigate_cursor.ts b/core/keyboard_nav/tab_navigate_cursor.ts index 588ddede5..eb4395969 100644 --- a/core/keyboard_nav/tab_navigate_cursor.ts +++ b/core/keyboard_nav/tab_navigate_cursor.ts @@ -21,8 +21,6 @@ import {BasicCursor} from './basic_cursor.js'; /** * A cursor for navigating between tab navigable fields. - * - * @alias Blockly.TabNavigateCursor */ export class TabNavigateCursor extends BasicCursor { /** diff --git a/core/main.js b/core/main.js index 4d6f85376..015157ab0 100644 --- a/core/main.js +++ b/core/main.js @@ -45,13 +45,14 @@ Object.defineProperties(Blockly, { */ alert: { set: function(newAlert) { - deprecation.warn('Blockly.alert', 'December 2021', 'December 2022'); + deprecation.warn( + 'Blockly.alert', 'version 9', 'version 10', + 'Blockly.dialog.setAlert'); dialog.setAlert(newAlert); }, get: function() { deprecation.warn( - 'Blockly.alert', 'December 2021', 'December 2022', - 'Blockly.dialog.alert()'); + 'Blockly.alert', 'version 9', 'version 10', 'Blockly.dialog.alert'); return dialog.alert; }, }, @@ -66,13 +67,15 @@ Object.defineProperties(Blockly, { */ confirm: { set: function(newConfirm) { - deprecation.warn('Blockly.confirm', 'December 2021', 'December 2022'); + deprecation.warn( + 'Blockly.confirm', 'version 9', 'version 10', + 'Blockly.dialog.setConfirm'); dialog.setConfirm(newConfirm); }, get: function() { deprecation.warn( - 'Blockly.confirm', 'December 2021', 'December 2022', - 'Blockly.dialog.confirm()'); + 'Blockly.confirm', 'version 9', 'version 10', + 'Blockly.dialog.confirm'); return dialog.confirm; }, }, @@ -111,13 +114,14 @@ Object.defineProperties(Blockly, { */ prompt: { set: function(newPrompt) { - deprecation.warn('Blockly.prompt', 'December 2021', 'December 2022'); + deprecation.warn( + 'Blockly.prompt', 'version 9', 'version 10', + 'Blockly.dialog.setPrompt'); dialog.setPrompt(newPrompt); }, get: function() { deprecation.warn( - 'Blockly.prompt', 'December 2021', 'December 2022', - 'Blockly.dialog.prompt()'); + 'Blockly.prompt', 'version 9', 'version 10', 'Blockly.dialog.prompt'); return dialog.prompt; }, }, diff --git a/core/marker_manager.ts b/core/marker_manager.ts index 6bc928c1b..653e220a9 100644 --- a/core/marker_manager.ts +++ b/core/marker_manager.ts @@ -19,8 +19,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class to manage the multiple markers and the cursor on a workspace. - * - * @alias Blockly.MarkerManager */ export class MarkerManager { /** The name of the local marker. */ diff --git a/core/menu.ts b/core/menu.ts index 85b8070cf..d2ff7d53c 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -17,15 +17,12 @@ import type {MenuItem} from './menuitem.js'; import * as aria from './utils/aria.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; -import {KeyCodes} from './utils/keycodes.js'; import type {Size} from './utils/size.js'; import * as style from './utils/style.js'; /** * A basic menu class. - * - * @alias Blockly.Menu */ export class Menu { /** @@ -107,7 +104,7 @@ export class Menu { this.mouseOverHandler = browserEvents.conditionalBind( element, 'pointerover', this, this.handleMouseOver, true); this.clickHandler = browserEvents.conditionalBind( - element, 'pointerdown', this, this.handleClick, true); + element, 'pointerup', this, this.handleClick, true); this.mouseEnterHandler = browserEvents.conditionalBind( element, 'pointerenter', this, this.handleMouseEnter, true); this.mouseLeaveHandler = browserEvents.conditionalBind( @@ -394,29 +391,29 @@ export class Menu { } const highlighted = this.highlightedItem; - switch (keyboardEvent.keyCode) { - case KeyCodes.ENTER: - case KeyCodes.SPACE: + switch (keyboardEvent.key) { + case 'Enter': + case ' ': if (highlighted) { highlighted.performAction(); } break; - case KeyCodes.UP: + case 'ArrowUp': this.highlightPrevious(); break; - case KeyCodes.DOWN: + case 'ArrowDown': this.highlightNext(); break; - case KeyCodes.PAGE_UP: - case KeyCodes.HOME: + case 'PageUp': + case 'Home': this.highlightFirst(); break; - case KeyCodes.PAGE_DOWN: - case KeyCodes.END: + case 'PageDown': + case 'End': this.highlightLast(); break; diff --git a/core/menuitem.ts b/core/menuitem.ts index ee9b2ad0c..55c623ff8 100644 --- a/core/menuitem.ts +++ b/core/menuitem.ts @@ -19,8 +19,6 @@ import * as idGenerator from './utils/idgenerator.js'; /** * Class representing an item in a menu. - * - * @alias Blockly.MenuItem */ export class MenuItem { /** Is the menu item clickable, as opposed to greyed-out. */ diff --git a/core/metrics_manager.ts b/core/metrics_manager.ts index 7d8ba5cf9..615d19385 100644 --- a/core/metrics_manager.ts +++ b/core/metrics_manager.ts @@ -24,8 +24,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * The manager for all workspace metrics calculations. - * - * @alias Blockly.MetricsManager */ export class MetricsManager implements IMetricsManager { /** The workspace to calculate metrics for. */ @@ -55,11 +53,14 @@ export class MetricsManager implements IMetricsManager { } /** - * Gets the width and the height of the flyout on the workspace in pixel - * coordinates. Returns 0 for the width and height if the workspace has a - * category toolbox instead of a simple toolbox. + * Gets the width and the height of the flyout in pixel + * coordinates. By default, will get metrics for either a simple flyout (owned + * directly by the workspace) or for the flyout owned by the toolbox. If you + * pass `opt_own` as `true` then only metrics for the simple flyout will be + * returned, and it will return 0 for the width and height if the workspace + * has a category toolbox instead of a simple toolbox. * - * @param opt_own Whether to only return the workspace's own flyout. + * @param opt_own Whether to only return the workspace's own flyout metrics. * @returns The width and height of the flyout. */ getFlyoutMetrics(opt_own?: boolean): ToolboxMetrics { @@ -76,8 +77,7 @@ export class MetricsManager implements IMetricsManager { * Gets the width, height and position of the toolbox on the workspace in * pixel coordinates. Returns 0 for the width and height if the workspace has * a simple toolbox instead of a category toolbox. To get the width and height - * of a - * simple toolbox @see {@link MetricsManager#getFlyoutMetrics}. + * of a simple toolbox, see {@link MetricsManager#getFlyoutMetrics}. * * @returns The object with the width, height and position of the toolbox. */ diff --git a/core/msg.ts b/core/msg.ts index 39d05b0c5..50fdf3a8f 100644 --- a/core/msg.ts +++ b/core/msg.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Empty name space for the Message singleton. - * - * @namespace Blockly.Msg - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Msg'); diff --git a/core/mutator.ts b/core/mutator.ts index 6153009b0..d5a051f52 100644 --- a/core/mutator.ts +++ b/core/mutator.ts @@ -38,8 +38,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a mutator dialog. - * - * @alias Blockly.Mutator */ export class Mutator extends Icon { private quarkNames: string[]; @@ -317,8 +315,6 @@ export class Mutator extends Icon { return; } const block = this.getBlock(); - eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))( - block, visible, 'mutator')); if (visible) { // Create the bubble. this.bubble_ = new Bubble( @@ -371,7 +367,9 @@ export class Mutator extends Icon { } this.resizeBubble(); // When the mutator's workspace changes, update the source block. - ws.addChangeListener(this.workspaceChanged.bind(this)); + const boundListener = this.workspaceChanged.bind(this); + ws.addChangeListener(boundListener); + if (flyout) flyout.getWorkspace().addChangeListener(boundListener); // Update the source block immediately after the bubble becomes visible. this.updateWorkspace(); this.applyColour(); @@ -390,6 +388,8 @@ export class Mutator extends Icon { this.sourceListener = null; } } + eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))( + block, visible, 'mutator')); } /** diff --git a/core/names.ts b/core/names.ts index b6b026fd3..0a7ca3888 100644 --- a/core/names.ts +++ b/core/names.ts @@ -21,8 +21,6 @@ import type {Workspace} from './workspace.js'; /** * Class for a database of entity names (variables, procedures, etc). - * - * @alias Blockly.Names */ export class Names { static DEVELOPER_VARIABLE_TYPE: NameType; @@ -186,15 +184,13 @@ export class Names { */ getDistinctName(name: string, type: NameType|string): string { let safeName = this.safeName_(name); - let i = ''; - while (this.dbReverse.has(safeName + i) || - this.reservedWords.has(safeName + i)) { + let i: number|null = null; + while (this.dbReverse.has(safeName + (i ?? '')) || + this.reservedWords.has(safeName + (i ?? ''))) { // Collision with existing name. Create a unique name. - // AnyDuringMigration because: Type 'string | 2' is not assignable to - // type 'string'. - i = (i ? i + 1 : 2) as AnyDuringMigration; + i = i ? i + 1 : 2; } - safeName += i; + safeName += (i ?? ''); this.dbReverse.add(safeName); const isVar = type === NameType.VARIABLE || type === NameType.DEVELOPER_VARIABLE; @@ -251,7 +247,6 @@ export namespace Names { * getName('foo', 'VARIABLE') = 'foo' * getName('foo', 'PROCEDURE') = 'foo2' * - * @alias Blockly.Names.NameType */ export enum NameType { DEVELOPER_VARIABLE = 'DEVELOPER_VARIABLE', diff --git a/core/procedures/observable_procedure_map.ts b/core/observable_procedure_map.ts similarity index 58% rename from core/procedures/observable_procedure_map.ts rename to core/observable_procedure_map.ts index 2f0b0f0a6..8105c905e 100644 --- a/core/procedures/observable_procedure_map.ts +++ b/core/observable_procedure_map.ts @@ -4,17 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as eventUtils from '../events/utils.js'; -import {IProcedureMap} from '../interfaces/i_procedure_map.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {isObservable} from '../interfaces/i_observable.js'; -import {triggerProceduresUpdate} from './update_procedures.js'; -import type {Workspace} from '../workspace.js'; +import {IProcedureMap} from './interfaces/i_procedure_map.js'; +import type {IProcedureModel} from './interfaces/i_procedure_model.js'; +import {isObservable} from './interfaces/i_observable.js'; export class ObservableProcedureMap extends Map implements IProcedureMap { - constructor(private readonly workspace: Workspace) { + /** @internal */ + constructor() { super(); } @@ -24,8 +22,6 @@ export class ObservableProcedureMap extends override set(id: string, proc: IProcedureModel): this { if (this.get(id) === proc) return this; super.set(id, proc); - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_CREATE))( - this.workspace, proc)); if (isObservable(proc)) proc.startPublishing(); return this; } @@ -38,9 +34,6 @@ export class ObservableProcedureMap extends const proc = this.get(id); const existed = super.delete(id); if (!existed) return existed; - triggerProceduresUpdate(this.workspace); - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_DELETE))( - this.workspace, proc)); if (isObservable(proc)) proc.stopPublishing(); return existed; } @@ -51,12 +44,8 @@ export class ObservableProcedureMap extends override clear() { if (!this.size) return; for (const id of this.keys()) { - const proc = this.get(id); - super.delete(id); - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_DELETE))( - this.workspace, proc)); + this.delete(id); } - triggerProceduresUpdate(this.workspace); } /** @@ -64,7 +53,6 @@ export class ObservableProcedureMap extends * blocks can find it. */ add(proc: IProcedureModel): this { - // TODO(#6526): See if this method is actually useful. return this.set(proc.getId(), proc); } diff --git a/core/options.ts b/core/options.ts index 92fd7182e..4f66582bb 100644 --- a/core/options.ts +++ b/core/options.ts @@ -26,8 +26,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Parse the user-specified options, using reasonable defaults where behaviour * is unspecified. - * - * @alias Blockly.Options */ export class Options { RTL: boolean; diff --git a/core/positionable_helpers.ts b/core/positionable_helpers.ts index 035ba91cd..b0967c48d 100644 --- a/core/positionable_helpers.ts +++ b/core/positionable_helpers.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility functions for positioning UI elements. - * - * @namespace Blockly.uiPosition - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.uiPosition'); @@ -23,7 +18,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Enum for vertical positioning. * - * @alias Blockly.uiPosition.verticalPosition * @internal */ export enum verticalPosition { @@ -34,7 +28,6 @@ export enum verticalPosition { /** * Enum for horizontal positioning. * - * @alias Blockly.uiPosition.horizontalPosition * @internal */ export enum horizontalPosition { @@ -45,7 +38,6 @@ export enum horizontalPosition { /** * An object defining a horizontal and vertical positioning. * - * @alias Blockly.uiPosition.Position * @internal */ export interface Position { @@ -56,7 +48,6 @@ export interface Position { /** * Enum for bump rules to use for dealing with collisions. * - * @alias Blockly.uiPosition.bumpDirection * @internal */ export enum bumpDirection { @@ -77,7 +68,6 @@ export enum bumpDirection { * @param metrics The workspace UI metrics. * @param workspace The workspace. * @returns The suggested start position. - * @alias Blockly.uiPosition.getStartPositionRect * @internal */ export function getStartPositionRect( @@ -124,7 +114,6 @@ export function getStartPositionRect( * @param workspace The workspace. * @param metrics The workspace metrics. * @returns The suggested corner position. - * @alias Blockly.uiPosition.getCornerOppositeToolbox * @internal */ export function getCornerOppositeToolbox( @@ -151,7 +140,6 @@ export function getCornerOppositeToolbox( * @param savedPositions List of rectangles that represent the positions of UI * elements already placed. * @returns The suggested position rectangle. - * @alias Blockly.uiPosition.bumpPositionRect * @internal */ export function bumpPositionRect( diff --git a/core/procedures.ts b/core/procedures.ts index e31d77d31..1bc1d9d80 100644 --- a/core/procedures.ts +++ b/core/procedures.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility functions for handling procedures. - * - * @namespace Blockly.Procedures - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Procedures'); @@ -25,14 +20,16 @@ import * as eventUtils from './events/utils.js'; import {Field, UnattachedFieldError} from './field.js'; import {Msg} from './msg.js'; import {Names} from './names.js'; -import {ObservableProcedureMap} from './procedures/observable_procedure_map.js'; -import {ObservableProcedureModel} from './procedures/observable_procedure_model.js'; -import {ObservableParameterModel} from './procedures/observable_parameter_model.js'; +import {IParameterModel} from './interfaces/i_parameter_model.js'; +import {IProcedureMap} from './interfaces/i_procedure_map.js'; +import {IProcedureModel} from './interfaces/i_procedure_model.js'; +import {IProcedureBlock, isProcedureBlock} from './interfaces/i_procedure_block.js'; +import {isLegacyProcedureCallBlock, isLegacyProcedureDefBlock, ProcedureBlock, ProcedureTuple} from './interfaces/i_legacy_procedure_blocks.js'; +import {ObservableProcedureMap} from './observable_procedure_map.js'; import * as utilsXml from './utils/xml.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -import * as Xml from './xml.js'; /** @@ -41,31 +38,14 @@ import * as Xml from './xml.js'; * procedure blocks. * See also Blockly.Variables.CATEGORY_NAME and * Blockly.VariablesDynamic.CATEGORY_NAME. - * - * @alias Blockly.Procedures.CATEGORY_NAME */ export const CATEGORY_NAME = 'PROCEDURE'; /** * The default argument for a procedures_mutatorarg block. - * - * @alias Blockly.Procedures.DEFAULT_ARG */ export const DEFAULT_ARG = 'x'; -export type ProcedureTuple = [string, string[], boolean]; - -/** - * Procedure block type. - * - * @alias Blockly.Procedures.ProcedureBlock - */ -export interface ProcedureBlock { - getProcedureCall: () => string; - renameProcedure: (p1: string, p2: string) => void; - getProcedureDef: () => ProcedureTuple; -} - /** * Find all user-created procedure definitions in a workspace. * @@ -73,19 +53,40 @@ export interface ProcedureBlock { * @returns Pair of arrays, the first contains procedures without return * variables, the second with. Each procedure is defined by a three-element * list of name, parameter list, and return value boolean. - * @alias Blockly.Procedures.allProcedures */ export function allProcedures(root: Workspace): [ProcedureTuple[], ProcedureTuple[]] { - const proceduresNoReturn = - root.getBlocksByType('procedures_defnoreturn', false) - .map(function(block) { - return (block as unknown as ProcedureBlock).getProcedureDef(); - }); - const proceduresReturn = - root.getBlocksByType('procedures_defreturn', false).map(function(block) { - return (block as unknown as ProcedureBlock).getProcedureDef(); - }); + const proceduresNoReturn: ProcedureTuple[] = + root.getProcedureMap() + .getProcedures() + .filter((p) => !p.getReturnTypes()) + .map( + (p) => + [p.getName(), + p.getParameters().map((pa) => pa.getName()), + false, + ]); + root.getBlocksByType('procedures_defnoreturn', false).forEach((b) => { + if (!isProcedureBlock(b) && isLegacyProcedureDefBlock(b)) { + proceduresNoReturn.push(b.getProcedureDef()); + } + }); + + const proceduresReturn: ProcedureTuple[] = + root.getProcedureMap() + .getProcedures() + .filter((p) => !!p.getReturnTypes()) + .map( + (p) => + [p.getName(), + p.getParameters().map((pa) => pa.getName()), + true, + ]); + root.getBlocksByType('procedures_defreturn', false).forEach((b) => { + if (!isProcedureBlock(b) && isLegacyProcedureDefBlock(b)) { + proceduresReturn.push(b.getProcedureDef()); + } + }); proceduresNoReturn.sort(procTupleComparator); proceduresReturn.sort(procTupleComparator); return [proceduresNoReturn, proceduresReturn]; @@ -111,7 +112,6 @@ function procTupleComparator(ta: ProcedureTuple, tb: ProcedureTuple): number { * @param name Proposed procedure name. * @param block Block to disambiguate. * @returns Non-colliding name. - * @alias Blockly.Procedures.findLegalName */ export function findLegalName(name: string, block: Block): string { if (block.isInFlyout) { @@ -153,25 +153,25 @@ function isLegalName( * @param opt_exclude Optional block to exclude from comparisons (one doesn't * want to collide with oneself). * @returns True if the name is used, otherwise return false. - * @alias Blockly.Procedures.isNameUsed */ export function isNameUsed( name: string, workspace: Workspace, opt_exclude?: Block): boolean { - const blocks = workspace.getAllBlocks(false); - // Iterate through every block and check the name. - for (let i = 0; i < blocks.length; i++) { - if (blocks[i] === opt_exclude) { - continue; - } - // Assume it is a procedure block so we can check. - const procedureBlock = blocks[i] as unknown as ProcedureBlock; - if (procedureBlock.getProcedureDef) { - const procName = procedureBlock.getProcedureDef(); - if (Names.equals(procName[0], name)) { - return true; - } + for (const block of workspace.getAllBlocks(false)) { + if (block === opt_exclude) continue; + + if (isLegacyProcedureDefBlock(block) && + Names.equals(block.getProcedureDef()[0], name)) { + return true; } } + + const excludeModel = opt_exclude && isProcedureBlock(opt_exclude) ? + opt_exclude?.getProcedureModel() : + undefined; + for (const model of workspace.getProcedureMap().getProcedures()) { + if (model === excludeModel) continue; + if (Names.equals(model.getName(), name)) return true; + } return false; } @@ -180,7 +180,6 @@ export function isNameUsed( * * @param name The proposed new name. * @returns The accepted name. - * @alias Blockly.Procedures.rename */ export function rename(this: Field, name: string): string { const block = this.getSourceBlock(); @@ -192,6 +191,9 @@ export function rename(this: Field, name: string): string { name = name.trim(); const legalName = findLegalName(name, block); + if (isProcedureBlock(block) && !block.isInsertionMarker()) { + block.getProcedureModel().setName(legalName); + } const oldName = this.getValue(); if (oldName !== name && oldName !== legalName) { // Rename any callers. @@ -212,7 +214,6 @@ export function rename(this: Field, name: string): string { * * @param workspace The workspace containing procedures. * @returns Array of XML block elements. - * @alias Blockly.Procedures.flyoutCategory */ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { const xmlList = []; @@ -329,7 +330,6 @@ function updateMutatorFlyout(workspace: WorkspaceSvg) { * update and adds a mutator change listener to the mutator workspace. * * @param e The event that triggered this listener. - * @alias Blockly.Procedures.mutatorOpenListener * @internal */ export function mutatorOpenListener(e: Abstract) { @@ -375,24 +375,23 @@ function mutatorChangeListener(e: Abstract) { * @param name Name of procedure. * @param workspace The workspace to find callers in. * @returns Array of caller blocks. - * @alias Blockly.Procedures.getCallers */ export function getCallers(name: string, workspace: Workspace): Block[] { - const callers = []; - const blocks = workspace.getAllBlocks(false); - // Iterate through every block and check the name. - for (let i = 0; i < blocks.length; i++) { - // Assume it is a procedure block so we can check. - const procedureBlock = blocks[i] as unknown as ProcedureBlock; - if (procedureBlock.getProcedureCall) { - const procName = procedureBlock.getProcedureCall(); - // Procedure name may be null if the block is only half-built. - if (procName && Names.equals(procName, name)) { - callers.push(blocks[i]); - } - } - } - return callers; + return workspace.getAllBlocks(false).filter((block) => { + return blockIsModernCallerFor(block, name) || + (isLegacyProcedureCallBlock(block) && + Names.equals(block.getProcedureCall(), name)); + }); +} + +/** + * @returns True if the given block is a modern-style caller block of the given + * procedure name. + */ +function blockIsModernCallerFor(block: Block, procName: string): boolean { + return isProcedureBlock(block) && !block.isProcedureDef() && + block.getProcedureModel() && + Names.equals(block.getProcedureModel().getName(), procName); } /** @@ -400,7 +399,6 @@ export function getCallers(name: string, workspace: Workspace): Block[] { * callers. * * @param defBlock Procedure definition block. - * @alias Blockly.Procedures.mutateCallers */ export function mutateCallers(defBlock: Block) { const oldRecordUndo = eventUtils.getRecordUndo(); @@ -410,12 +408,12 @@ export function mutateCallers(defBlock: Block) { const callers = getCallers(name, defBlock.workspace); for (let i = 0, caller; caller = callers[i]; i++) { const oldMutationDom = caller.mutationToDom!(); - const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom); + const oldMutation = oldMutationDom && utilsXml.domToText(oldMutationDom); if (caller.domToMutation) { caller.domToMutation(xmlElement); } const newMutationDom = caller.mutationToDom!(); - const newMutation = newMutationDom && Xml.domToText(newMutationDom); + const newMutation = newMutationDom && utilsXml.domToText(newMutationDom); if (oldMutation !== newMutation) { // Fire a mutation on every caller block. But don't record this as an // undo action since it is deterministically tied to the procedure's @@ -434,21 +432,19 @@ export function mutateCallers(defBlock: Block) { * @param name Name of procedure. * @param workspace The workspace to search. * @returns The procedure definition block, or null not found. - * @alias Blockly.Procedures.getDefinition */ export function getDefinition(name: string, workspace: Workspace): Block|null { // Do not assume procedure is a top block. Some languages allow nested // procedures. Also do not assume it is one of the built-in blocks. Only - // rely on getProcedureDef. - const blocks = workspace.getAllBlocks(false); - for (let i = 0; i < blocks.length; i++) { - // Assume it is a procedure block so we can check. - const procedureBlock = blocks[i] as unknown as ProcedureBlock; - if (procedureBlock.getProcedureDef) { - const tuple = procedureBlock.getProcedureDef(); - if (tuple && Names.equals(tuple[0], name)) { - return blocks[i]; // Can't use procedureBlock var due to type check. - } + // rely on isProcedureDef and getProcedureDef. + for (const block of workspace.getAllBlocks(false)) { + if (isProcedureBlock(block) && block.isProcedureDef() && + Names.equals(block.getProcedureModel().getName(), name)) { + return block; + } + if (isLegacyProcedureDefBlock(block) && + Names.equals(block.getProcedureDef()[0], name)) { + return block; } } return null; @@ -456,6 +452,10 @@ export function getDefinition(name: string, workspace: Workspace): Block|null { export { ObservableProcedureMap, - ObservableProcedureModel, - ObservableParameterModel, + IParameterModel, + IProcedureBlock, + isProcedureBlock, + IProcedureMap, + IProcedureModel, + ProcedureTuple, }; diff --git a/core/procedures/observable_parameter_model.ts b/core/procedures/observable_parameter_model.ts deleted file mode 100644 index 95261d748..000000000 --- a/core/procedures/observable_parameter_model.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as eventUtils from '../events/utils.js'; -import {genUid} from '../utils/idgenerator.js'; -import type {IParameterModel} from '../interfaces/i_parameter_model.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model'; -import {triggerProceduresUpdate} from './update_procedures.js'; -import type {VariableModel} from '../variable_model.js'; -import type {Workspace} from '../workspace.js'; - - -export class ObservableParameterModel implements IParameterModel { - private id: string; - private variable: VariableModel; - private shouldFireEvents = false; - private procedureModel: IProcedureModel|null = null; - - constructor( - private readonly workspace: Workspace, name: string, id?: string) { - this.id = id ?? genUid(); - this.variable = - this.workspace.getVariable(name) ?? workspace.createVariable(name); - } - - /** - * Sets the name of this parameter to the given name. - */ - setName(name: string): this { - if (name === this.variable.name) return this; - const oldName = this.variable.name; - this.variable = - this.workspace.getVariable(name) ?? this.workspace.createVariable(name); - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - eventUtils.fire( - new (eventUtils.get(eventUtils.PROCEDURE_PARAMETER_RENAME))( - this.workspace, this.procedureModel, this, oldName)); - } - return this; - } - - /** - * Unimplemented. The built-in ParameterModel does not support typing. - * If you want your procedure blocks to have typed parameters, you need to - * implement your own ParameterModel. - * - * @throws Throws for the ObservableParameterModel specifically because this - * method is unimplemented. - */ - setTypes(_types: string[]): this { - throw new Error( - 'The built-in ParameterModel does not support typing. You need to ' + - 'implement your own custom ParameterModel.'); - } - - /** - * Returns the name of this parameter. - */ - getName(): string { - return this.variable.name; - } - - /** - * Returns the types of this parameter. - */ - getTypes(): string[] { - return []; - } - - /** - * Returns the unique language-neutral ID for the parameter. - * - * This represents the identify of the variable model which does not change - * over time. - */ - getId(): string { - return this.id; - } - - /** Returns the variable model associated with the parameter model. */ - getVariableModel(): VariableModel { - return this.variable; - } - - /** - * Tells the parameter model it should fire events. - * - * @internal - */ - startPublishing() { - this.shouldFireEvents = true; - } - - /** - * Tells the parameter model it should not fire events. - * - * @internal - */ - stopPublishing() { - this.shouldFireEvents = false; - } - - /** Sets the procedure model this parameter is a part of. */ - setProcedureModel(model: IProcedureModel): this { - // TODO: Not sure if we want to do this, or accept it via the constructor. - // That means it could be non-null, but it would also break the fluent - // API. - this.procedureModel = model; - return this; - } -} diff --git a/core/procedures/observable_procedure_model.ts b/core/procedures/observable_procedure_model.ts deleted file mode 100644 index 9b44496ea..000000000 --- a/core/procedures/observable_procedure_model.ts +++ /dev/null @@ -1,194 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as eventUtils from '../events/utils.js'; -import {genUid} from '../utils/idgenerator.js'; -import type {IParameterModel} from '../interfaces/i_parameter_model.js'; -import type {IProcedureModel} from '../interfaces/i_procedure_model.js'; -import {isObservable} from '../interfaces/i_observable.js'; -import {triggerProceduresUpdate} from './update_procedures.js'; -import type {Workspace} from '../workspace.js'; - - -export class ObservableProcedureModel implements IProcedureModel { - private id: string; - private name: string; - private parameters: IParameterModel[] = []; - private returnTypes: string[]|null = null; - private enabled = true; - private shouldFireEvents = false; - - constructor( - private readonly workspace: Workspace, name: string, id?: string) { - this.id = id ?? genUid(); - this.name = name; - } - - /** Sets the human-readable name of the procedure. */ - setName(name: string): this { - if (name === this.name) return this; - const prevName = this.name; - this.name = name; - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_RENAME))( - this.workspace, this, prevName)); - } - return this; - } - - /** - * Inserts a parameter into the list of parameters. - * - * To move a parameter, first delete it, and then re-insert. - */ - insertParameter(parameterModel: IParameterModel, index: number): this { - if (this.parameters[index] && - this.parameters[index].getId() === parameterModel.getId()) { - return this; - } - - this.parameters.splice(index, 0, parameterModel); - parameterModel.setProcedureModel(this); - if (isObservable(parameterModel)) { - if (this.shouldFireEvents) { - parameterModel.startPublishing(); - } else { - parameterModel.stopPublishing(); - } - } - - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - eventUtils.fire( - new (eventUtils.get(eventUtils.PROCEDURE_PARAMETER_CREATE))( - this.workspace, this, parameterModel, index)); - } - return this; - } - - /** Removes the parameter at the given index from the parameter list. */ - deleteParameter(index: number): this { - if (!this.parameters[index]) return this; - const oldParam = this.parameters[index]; - - this.parameters.splice(index, 1); - triggerProceduresUpdate(this.workspace); - if (isObservable(oldParam)) { - oldParam.stopPublishing(); - } - - if (this.shouldFireEvents) { - eventUtils.fire( - new (eventUtils.get(eventUtils.PROCEDURE_PARAMETER_DELETE))( - this.workspace, this, oldParam, index)); - } - return this; - } - - /** - * Sets whether the procedure has a return value (empty array) or no return - * value (null). - * - * The built-in procedure model does not support procedures that have actual - * return types (i.e. non-empty arrays, e.g. ['number']). If you want your - * procedure block to have return types, you need to implement your own - * procedure model. - */ - setReturnTypes(types: string[]|null): this { - if (types && types.length) { - throw new Error( - 'The built-in ProcedureModel does not support typing. You need to ' + - 'implement your own custom ProcedureModel.'); - } - // Either they're both an empty array, or both null. Noop either way. - if (!!types === !!this.returnTypes) return this; - const oldReturnTypes = this.returnTypes; - this.returnTypes = types; - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_CHANGE_RETURN))( - this.workspace, this, oldReturnTypes)); - } - return this; - } - - /** - * Sets whether this procedure is enabled/disabled. If a procedure is disabled - * all procedure caller blocks should be disabled as well. - */ - setEnabled(enabled: boolean): this { - if (enabled === this.enabled) return this; - this.enabled = enabled; - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - eventUtils.fire(new (eventUtils.get(eventUtils.PROCEDURE_ENABLE))( - this.workspace, this)); - } - return this; - } - - /** Returns the unique language-neutral ID for the procedure. */ - getId(): string { - return this.id; - } - - /** Returns the human-readable name of the procedure. */ - getName(): string { - return this.name; - } - - /** Returns the parameter at the given index in the parameter list. */ - getParameter(index: number): IParameterModel { - return this.parameters[index]; - } - - /** Returns an array of all of the parameters in the parameter list. */ - getParameters(): IParameterModel[] { - return [...this.parameters]; - } - - /** - * Returns the return type of the procedure. - * - * Null represents a procedure that does not return a value. - */ - getReturnTypes(): string[]|null { - return this.returnTypes; - } - - /** - * Returns whether the procedure is enabled/disabled. If a procedure is - * disabled, all procedure caller blocks should be disabled as well. - */ - getEnabled(): boolean { - return this.enabled; - } - - /** - * Tells the procedure model it should fire events. - * - * @internal - */ - startPublishing() { - this.shouldFireEvents = true; - for (const param of this.parameters) { - if (isObservable(param)) param.startPublishing(); - } - } - - /** - * Tells the procedure model it should not fire events. - * - * @internal - */ - stopPublishing() { - this.shouldFireEvents = false; - for (const param of this.parameters) { - if (isObservable(param)) param.stopPublishing(); - } - } -} diff --git a/core/procedures/update_procedures.ts b/core/procedures/update_procedures.ts deleted file mode 100644 index 53d06caa5..000000000 --- a/core/procedures/update_procedures.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {isProcedureBlock} from '../interfaces/i_procedure_block.js'; -import {Workspace} from '../workspace.js'; - - -/** - * Calls the `doProcedureUpdate` method on all blocks which implement it. - * - * @internal - */ -export function triggerProceduresUpdate(workspace: Workspace) { - for (const block of workspace.getAllBlocks(false)) { - if (isProcedureBlock(block)) { - block.doProcedureUpdate(); - } - } -} diff --git a/core/registry.ts b/core/registry.ts index f032fe362..32abc14d7 100644 --- a/core/registry.ts +++ b/core/registry.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * This file is a universal registry that provides generic methods - * for registering and unregistering different types of classes. - * - * @namespace Blockly.registry - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.registry'); @@ -48,15 +42,11 @@ const nameMap: {[key: string]: {[key: string]: string}} = Object.create(null); /** * The string used to register the default class for a type of plugin. - * - * @alias Blockly.registry.DEFAULT */ export const DEFAULT = 'default'; /** * A name with the type of the element stored in the generic. - * - * @alias Blockly.registry.Type */ export class Type<_T> { /** @param name The name of the registry type. */ @@ -112,7 +102,6 @@ export class Type<_T> { * @throws {Error} if the type or name is empty, a name with the given type has * already been registered, or if the given class or object is not valid for * its type. - * @alias Blockly.registry.register */ export function register( type: string|Type, name: string, @@ -120,12 +109,12 @@ export function register( AnyDuringMigration, opt_allowOverrides?: boolean): void { if (!(type instanceof Type) && typeof type !== 'string' || - String(type).trim() === '') { + `${type}`.trim() === '') { throw Error( 'Invalid type "' + type + '". The type must be a' + ' non-empty string or a Blockly.registry.Type.'); } - type = String(type).toLowerCase(); + type = `${type}`.toLowerCase(); if (typeof name !== 'string' || name.trim() === '') { throw Error( @@ -181,10 +170,9 @@ function validate(type: string, registryItem: Function|AnyDuringMigration) { * @param type The type of the plugin. * (e.g. Field, Renderer) * @param name The plugin's name. (Ex. field_angle, geras) - * @alias Blockly.registry.unregister */ export function unregister(type: string|Type, name: string) { - type = String(type).toLowerCase(); + type = `${type}`.toLowerCase(); name = name.toLowerCase(); const typeRegistry = typeMap[type]; if (!typeRegistry || !typeRegistry[name]) { @@ -212,7 +200,7 @@ export function unregister(type: string|Type, name: string) { function getItem( type: string|Type, name: string, opt_throwIfMissing?: boolean): (new (...p1: AnyDuringMigration[]) => T)|null|AnyDuringMigration { - type = String(type).toLowerCase(); + type = `${type}`.toLowerCase(); name = name.toLowerCase(); const typeRegistry = typeMap[type]; if (!typeRegistry || !typeRegistry[name]) { @@ -237,10 +225,9 @@ function getItem( * @param name The plugin's name. (Ex. field_angle, geras) * @returns True if the registry has an item with the given type and name, false * otherwise. - * @alias Blockly.registry.hasItem */ export function hasItem(type: string|Type, name: string): boolean { - type = String(type).toLowerCase(); + type = `${type}`.toLowerCase(); name = name.toLowerCase(); const typeRegistry = typeMap[type]; if (!typeRegistry) { @@ -258,7 +245,6 @@ export function hasItem(type: string|Type, name: string): boolean { * @param opt_throwIfMissing Whether or not to throw an error if we are unable * to find the plugin. * @returns The class with the given name and type or null if none exists. - * @alias Blockly.registry.getClass */ export function getClass( type: string|Type, name: string, opt_throwIfMissing?: boolean): @@ -277,7 +263,6 @@ export function getClass( * @param opt_throwIfMissing Whether or not to throw an error if we are unable * to find the object. * @returns The object with the given name and type or null if none exists. - * @alias Blockly.registry.getObject */ export function getObject( type: string|Type, name: string, opt_throwIfMissing?: boolean): T|null { @@ -293,12 +278,11 @@ export function getObject( * @param opt_throwIfMissing Whether or not to throw an error if we are unable * to find the object. False by default. * @returns A map of objects with the given type, or null if none exists. - * @alias Blockly.registry.getAllItems */ export function getAllItems( type: string|Type, opt_cased?: boolean, opt_throwIfMissing?: boolean): {[key: string]: T|null|(new (...p1: AnyDuringMigration[]) => T)}|null { - type = String(type).toLowerCase(); + type = `${type}`.toLowerCase(); const typeRegistry = typeMap[type]; if (!typeRegistry) { const msg = `Unable to find [${type}] in the registry.`; @@ -314,9 +298,7 @@ export function getAllItems( } const nameRegistry = nameMap[type]; const casedRegistry = Object.create(null); - const keys = Object.keys(typeRegistry); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; + for (const key of Object.keys(typeRegistry)) { casedRegistry[nameRegistry[key]] = typeRegistry[key]; } return casedRegistry; @@ -331,13 +313,11 @@ export function getAllItems( * @param opt_throwIfMissing Whether or not to throw an error if we are unable * to find the plugin. * @returns The class for the plugin. - * @alias Blockly.registry.getClassFromOptions */ export function getClassFromOptions( type: Type, options: Options, opt_throwIfMissing?: boolean): (new (...p1: AnyDuringMigration[]) => T)|null { - const typeName = type.toString(); - const plugin = options.plugins[typeName] || DEFAULT; + const plugin = options.plugins[String(type)] || DEFAULT; // If the user passed in a plugin class instead of a registered plugin name. if (typeof plugin === 'function') { diff --git a/core/render_management.ts b/core/render_management.ts new file mode 100644 index 000000000..658f0b1d8 --- /dev/null +++ b/core/render_management.ts @@ -0,0 +1,100 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {BlockSvg} from './block_svg.js'; +import {Coordinate} from './utils/coordinate.js'; + + +const rootBlocks = new Set(); +let dirtyBlocks = new WeakSet(); +let pid = 0; + +/** + * Registers that the given block and all of its parents need to be rerendered, + * and registers a callback to do so after a delay, to allowf or batching. + * + * @param block The block to rerender. + * @internal + */ +export function queueRender(block: BlockSvg) { + queueBlock(block); + if (!pid) pid = window.requestAnimationFrame(doRenders); +} + +/** + * Adds the given block and its parents to the render queue. Adds the root block + * to the list of root blocks. + * + * @param block The block to queue. + */ +function queueBlock(block: BlockSvg) { + dirtyBlocks.add(block); + const parent = block.getParent(); + if (parent) { + queueBlock(parent); + } else { + rootBlocks.add(block); + } +} + +/** + * Rerenders all of the blocks in the queue. + */ +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; + + renderBlock(block); + updateConnectionLocations(block, block.getRelativeToSurfaceXY()); + } + for (const workspace of workspaces) { + workspace.resizeContents(); + } + + rootBlocks.clear(); + dirtyBlocks = new Set(); + pid = 0; +} + +/** + * Recursively renders all of the dirty children of the given block, and + * then renders the block. + * + * @param block The block to rerender. + */ +function renderBlock(block: BlockSvg) { + if (!dirtyBlocks.has(block)) return; + for (const child of block.getChildren(false)) { + renderBlock(child); + } + 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)); + } + } +} diff --git a/core/rendered_connection.ts b/core/rendered_connection.ts index 82af1b1b1..c472867db 100644 --- a/core/rendered_connection.ts +++ b/core/rendered_connection.ts @@ -43,8 +43,6 @@ const BUMP_RANDOMNESS = 10; /** * Class for a connection between blocks that may be rendered on screen. - * - * @alias Blockly.RenderedConnection */ export class RenderedConnection extends Connection { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -185,17 +183,31 @@ export class RenderedConnection extends Connection { * * @param x New absolute x coordinate, in workspace coordinates. * @param y New absolute y coordinate, in workspace coordinates. + * @return True if the position of the connection in the connection db + * was updated. */ - moveTo(x: number, y: number) { + moveTo(x: number, y: number): boolean { + // TODO(#6922): Readd this optimization. + // const moved = this.x !== x || this.y !== y; + const moved = true; + let updated = false; + if (this.trackedState_ === RenderedConnection.TrackedState.WILL_TRACK) { this.db_.addConnection(this, y); this.trackedState_ = RenderedConnection.TrackedState.TRACKED; - } else if (this.trackedState_ === RenderedConnection.TrackedState.TRACKED) { + updated = true; + } else if ( + this.trackedState_ === RenderedConnection.TrackedState.TRACKED && + moved) { this.db_.removeConnection(this, this.y); this.db_.addConnection(this, y); + updated = true; } + this.x = x; this.y = y; + + return updated; } /** @@ -203,9 +215,11 @@ export class RenderedConnection extends Connection { * * @param dx Change to x coordinate, in workspace units. * @param dy Change to y coordinate, in workspace units. + * @return True if the position of the connection in the connection db + * was updated. */ - moveBy(dx: number, dy: number) { - this.moveTo(this.x + dx, this.y + dy); + moveBy(dx: number, dy: number): boolean { + return this.moveTo(this.x + dx, this.y + dy); } /** @@ -214,9 +228,11 @@ export class RenderedConnection extends Connection { * * @param blockTL The location of the top left corner of the block, in * workspace coordinates. + * @return True if the position of the connection in the connection db + * was updated. */ - moveToOffset(blockTL: Coordinate) { - this.moveTo( + moveToOffset(blockTL: Coordinate): boolean { + return this.moveTo( blockTL.x + this.offsetInBlock_.x, blockTL.y + this.offsetInBlock_.y); } @@ -257,12 +273,26 @@ export class RenderedConnection extends Connection { } // Workspace coordinates. const xy = svgMath.getRelativeXY(svgRoot); - block!.getSvgRoot().setAttribute( - 'transform', 'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')'); + 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. + * + * @internal + */ + tightenEfficiently() { + const target = this.targetConnection; + const block = this.targetBlock(); + if (!target || !block) return; + const offset = + Coordinate.difference(this.offsetInBlock_, target.offsetInBlock_); + block.translate(offset.x, offset.y); + } + /** * Find the closest compatible connection to this connection. * All parameters are in workspace units. @@ -304,14 +334,12 @@ export class RenderedConnection extends Connection { (shape as unknown as PathLeftShape).pathLeft + svgPaths.lineOnAxis('h', xLen); } - const xy = this.sourceBlock_.getRelativeToSurfaceXY(); - const x = this.x - xy.x; - const y = this.y - xy.y; + const offset = this.offsetInBlock_; this.highlightPath = dom.createSvgElement( Svg.PATH, { 'class': 'blocklyHighlightedConnectionPath', 'd': steps, - 'transform': 'translate(' + x + ',' + y + ')' + + 'transform': `translate(${offset.x}, ${offset.y})` + (this.sourceBlock_.RTL ? ' scale(-1 1)' : ''), }, this.sourceBlock_.getSvgRoot()); @@ -426,7 +454,7 @@ export class RenderedConnection extends Connection { } /** - * Behavior after a connection attempt fails. + * Behaviour after a connection attempt fails. * Bumps this connection away from the other connection. Called when an * attempted connection fails. * @@ -451,23 +479,27 @@ export class RenderedConnection extends Connection { /** * Disconnect two blocks that are connected by this connection. * - * @param parentBlock The superior block. - * @param childBlock The inferior block. + * @param setParent Whether to set the parent of the disconnected block or + * not, defaults to true. + * If you do not set the parent, ensure that a subsequent action does, + * otherwise the view and model will be out of sync. */ - protected override disconnectInternal_( - parentBlock: Block, childBlock: Block) { - super.disconnectInternal_(parentBlock, childBlock); - const renderedParent = parentBlock as BlockSvg; - const renderedChild = childBlock as BlockSvg; + override disconnectInternal(setParent = true) { + const {parentConnection, childConnection} = + this.getParentAndChildConnections(); + if (!parentConnection || !childConnection) return; + const parent = parentConnection.getSourceBlock() as BlockSvg; + const child = childConnection.getSourceBlock() as BlockSvg; + super.disconnectInternal(setParent); // Rerender the parent so that it may reflow. - if (renderedParent.rendered) { - renderedParent.render(); + if (parent.rendered) { + parent.queueRender(); } - if (renderedChild.rendered) { - renderedChild.updateDisabled(); - renderedChild.render(); + if (child.rendered) { + child.updateDisabled(); + child.queueRender(); // Reset visibility, since the child is now a top block. - renderedChild.getSvgRoot().style.display = 'block'; + child.getSvgRoot().style.display = 'block'; } } @@ -486,7 +518,7 @@ export class RenderedConnection extends Connection { const parentBlock = this.getSourceBlock(); if (parentBlock.rendered) { - parentBlock.render(); + parentBlock.queueRender(); } } @@ -530,11 +562,11 @@ export class RenderedConnection extends Connection { this.type === ConnectionType.PREVIOUS_STATEMENT) { // Child block may need to square off its corners if it is in a stack. // Rendering a child will render its parent. - childBlock.render(); + childBlock.queueRender(); } else { // Child block does not change shape. Rendering the parent node will // move its connected children into position. - parentBlock.render(); + parentBlock.queueRender(); } } diff --git a/core/renderers/common/block_rendering.ts b/core/renderers/common/block_rendering.ts index 3700bfa91..34d39e4c3 100644 --- a/core/renderers/common/block_rendering.ts +++ b/core/renderers/common/block_rendering.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Namespace for block rendering functionality. - * - * @namespace Blockly.blockRendering - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering'); @@ -63,7 +58,6 @@ export function register(name: string, rendererClass: Function) { * Unregisters the renderer registered with the given name. * * @param name The name of the renderer. - * @alias Blockly.blockRendering.unregister */ export function unregister(name: string) { registry.unregister(registry.Type.RENDERER, name); @@ -72,7 +66,6 @@ export function unregister(name: string) { /** * Turn off the blocks debugger. * - * @alias Blockly.blockRendering.stopDebugger * @deprecated Use the debug renderer in **\@blockly/dev-tools** (See {@link * https://www.npmjs.com/package/@blockly/dev-tools}.) * @internal @@ -93,7 +86,6 @@ export function stopDebugger() { * @param opt_rendererOverrides Rendering constant overrides. * @returns The new instance of a renderer. * Already initialized. - * @alias Blockly.blockRendering.init * @internal */ export function init( diff --git a/core/renderers/common/constants.ts b/core/renderers/common/constants.ts index 82854abb4..1408ccf1b 100644 --- a/core/renderers/common/constants.ts +++ b/core/renderers/common/constants.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that provides constants for rendering blocks. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.ConstantProvider'); @@ -105,8 +100,6 @@ export function isDynamicShape(shape: Shape): shape is DynamicShape { /** * An object that provides constants for rendering blocks. - * - * @alias Blockly.blockRendering.ConstantProvider */ export class ConstantProvider { /** The size of an empty spacer. */ @@ -239,8 +232,6 @@ export class ConstantProvider { /** * The backing colour of a field's border rect. - * - * @internal */ FIELD_BORDER_RECT_COLOUR = '#fff'; FIELD_TEXT_BASELINE_CENTER: boolean; @@ -282,7 +273,6 @@ export class ConstantProvider { FIELD_COLOUR_DEFAULT_WIDTH = 26; FIELD_COLOUR_DEFAULT_HEIGHT: number; FIELD_CHECKBOX_X_OFFSET: number; - /** @internal */ randomIdentifier: string; /** @@ -293,8 +283,6 @@ export class ConstantProvider { /** * The ID of the emboss filter, or the empty string if no filter is set. - * - * @internal */ embossFilterId = ''; @@ -303,8 +291,6 @@ export class ConstantProvider { /** * The ID of the disabled pattern, or the empty string if no pattern is set. - * - * @internal */ disabledPatternId = ''; @@ -328,72 +314,52 @@ export class ConstantProvider { /** * Cursor colour. - * - * @internal */ CURSOR_COLOUR = '#cc0a0a'; /** * Immovable marker colour. - * - * @internal */ MARKER_COLOUR = '#4286f4'; /** * Width of the horizontal cursor. - * - * @internal */ CURSOR_WS_WIDTH = 100; /** * Height of the horizontal cursor. - * - * @internal */ WS_CURSOR_HEIGHT = 5; /** * Padding around a stack. - * - * @internal */ CURSOR_STACK_PADDING = 10; /** * Padding around a block. - * - * @internal */ CURSOR_BLOCK_PADDING = 2; /** * Stroke of the cursor. - * - * @internal */ CURSOR_STROKE_WIDTH = 4; /** * Whether text input and colour fields fill up the entire source block. - * - * @internal */ FULL_BLOCK_FIELDS = false; /** * The main colour of insertion markers, in hex. The block is rendered a * transparent grey by changing the fill opacity in CSS. - * - * @internal */ INSERTION_MARKER_COLOUR = '#000000'; /** * The insertion marker opacity. - * - * @internal */ INSERTION_MARKER_OPACITY = 0.2; @@ -411,10 +377,9 @@ export class ConstantProvider { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. OUTSIDE_CORNERS!: OutsideCorners; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - /** @internal */ + blockStyles!: {[key: string]: BlockStyle}; - /** @internal */ constructor() { /** * Offset from the top of the row for placing fields on inline input rows @@ -495,16 +460,12 @@ export class ConstantProvider { /** * A random identifier used to ensure a unique ID is used for each * filter/pattern for the case of multiple Blockly instances on a page. - * - * @internal */ this.randomIdentifier = String(Math.random()).substring(2); } /** * Initialize shape objects based on the constants set in the constructor. - * - * @internal */ init() { /** @@ -539,7 +500,6 @@ export class ConstantProvider { * Refresh constants properties that depend on the theme. * * @param theme The current workspace theme. - * @internal */ setTheme(theme: Theme) { /** The block styles map. */ @@ -617,7 +577,6 @@ export class ConstantProvider { * @param colour #RRGGBB colour string. * @returns An object containing the style and an autogenerated name for that * style. - * @internal */ getBlockStyleForColour(colour: string): {style: BlockStyle, name: string} { const name = 'auto_' + colour; @@ -702,8 +661,6 @@ export class ConstantProvider { /** * Dispose of this constants provider. * Delete all DOM elements that this provider created. - * - * @internal */ dispose() { if (this.embossFilter_) { @@ -721,9 +678,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about collapsed * block indicators. - * @internal */ - makeJaggedTeeth(): JaggedTeeth { + protected makeJaggedTeeth(): JaggedTeeth { const height = this.JAGGED_TEETH_HEIGHT; const width = this.JAGGED_TEETH_WIDTH; @@ -737,9 +693,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about start hats. - * @internal */ - makeStartHat(): StartHat { + protected makeStartHat(): StartHat { const height = this.START_HAT_HEIGHT; const width = this.START_HAT_WIDTH; @@ -754,9 +709,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about puzzle * tabs. - * @internal */ - makePuzzleTab(): PuzzleTab { + protected makePuzzleTab(): PuzzleTab { const width = this.TAB_WIDTH; const height = this.TAB_HEIGHT; @@ -811,9 +765,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about notches. - * @internal */ - makeNotch(): Notch { + protected makeNotch(): Notch { const width = this.NOTCH_WIDTH; const height = this.NOTCH_HEIGHT; const innerWidth = 3; @@ -848,9 +801,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about inside * corners. - * @internal */ - makeInsideCorners(): InsideCorners { + protected makeInsideCorners(): InsideCorners { const radius = this.CORNER_RADIUS; const innerTopLeftCorner = @@ -870,9 +822,8 @@ export class ConstantProvider { /** * @returns An object containing sizing and path information about outside * corners. - * @internal */ - makeOutsideCorners(): OutsideCorners { + protected makeOutsideCorners(): OutsideCorners { const radius = this.CORNER_RADIUS; /** SVG path for drawing the rounded top-left corner. */ const topLeft = svgPaths.moveBy(0, radius) + @@ -905,7 +856,6 @@ export class ConstantProvider { * * @param connection The connection to find a shape object for * @returns The shape object for the connection. - * @internal */ shapeFor(connection: RenderedConnection): Shape { switch (connection.type) { @@ -928,7 +878,6 @@ export class ConstantProvider { * @param selector The CSS selector to use. * @suppress {strictModuleDepCheck} Debug renderer only included in * playground. - * @internal */ createDom(svg: SVGElement, tagName: string, selector: string) { this.injectCSS_(tagName, selector); diff --git a/core/renderers/common/debug.ts b/core/renderers/common/debug.ts index d54a2866e..fed30a2b5 100644 --- a/core/renderers/common/debug.ts +++ b/core/renderers/common/debug.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Block rendering debugging functionality. - * - * @namespace Blockly.blockRendering.debug - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.debug'); @@ -21,7 +16,6 @@ let useDebugger = false; * Returns whether the debugger is turned on. * * @returns Whether the debugger is turned on. - * @alias Blockly.blockRendering.debug.isDebuggerEnabled * @internal */ export function isDebuggerEnabled(): boolean { @@ -31,7 +25,6 @@ export function isDebuggerEnabled(): boolean { /** * Turn on the blocks debugger. * - * @alias Blockly.blockRendering.debug.startDebugger * @deprecated March 2022. Use the rendering debugger in @blockly/dev-tools. * See https://www.npmjs.com/package/@blockly/dev-tools for more information. * @internal @@ -46,7 +39,6 @@ export function startDebugger() { /** * Turn off the blocks debugger. * - * @alias Blockly.blockRendering.debug.stopDebugger * @deprecated March 2022. Use the rendering debugger in @blockly/dev-tools. * See https://www.npmjs.com/package/@blockly/dev-tools for more information. * @internal diff --git a/core/renderers/common/debugger.ts b/core/renderers/common/debugger.ts index 4ec0e2ab6..0490c7bce 100644 --- a/core/renderers/common/debugger.ts +++ b/core/renderers/common/debugger.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for rendering debug graphics. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Debug'); @@ -32,8 +27,6 @@ import type {RenderInfo} from './info.js'; /** * An object that renders rectangles and dots for debugging rendering code. - * - * @alias Blockly.blockRendering.Debug */ export class Debug { /** @@ -64,16 +57,13 @@ export class Debug { /** * @param constants The renderer's constants. - * @internal */ constructor(private readonly constants: ConstantProvider) {} /** * Remove all elements the this object created on the last pass. - * - * @internal */ - clearElems() { + protected clearElems() { for (let i = 0; i < this.debugElements_.length; i++) { const elem = this.debugElements_[i]; dom.removeNode(elem); @@ -88,9 +78,8 @@ export class Debug { * @param row The row to render. * @param cursorY The y position of the top of the row. * @param isRtl Whether the block is rendered RTL. - * @internal */ - drawSpacerRow(row: Row, cursorY: number, isRtl: boolean) { + protected drawSpacerRow(row: Row, cursorY: number, isRtl: boolean) { if (!Debug.config.rowSpacers) { return; } @@ -122,9 +111,9 @@ export class Debug { * @param elem The spacer to render. * @param rowHeight The height of the container row. * @param isRtl Whether the block is rendered RTL. - * @internal */ - drawSpacerElem(elem: InRowSpacer, rowHeight: number, isRtl: boolean) { + protected drawSpacerElem( + elem: InRowSpacer, rowHeight: number, isRtl: boolean) { if (!Debug.config.elemSpacers) { return; } @@ -156,9 +145,8 @@ export class Debug { * * @param elem The element to render. * @param isRtl Whether the block is rendered RTL. - * @internal */ - drawRenderedElem(elem: Measurable, isRtl: boolean) { + protected drawRenderedElem(elem: Measurable, isRtl: boolean) { if (Debug.config.elems) { let xPos = elem.xPos; if (isRtl) { @@ -210,9 +198,8 @@ export class Debug { * @param conn The connection to circle. * @suppress {visibility} Suppress visibility of conn.offsetInBlock_ since * this is a debug module. - * @internal */ - drawConnection(conn: RenderedConnection) { + protected drawConnection(conn: RenderedConnection) { if (!Debug.config.connections) { return; } @@ -255,9 +242,8 @@ export class Debug { * @param row The non-empty row to render. * @param cursorY The y position of the top of the row. * @param isRtl Whether the block is rendered RTL. - * @internal */ - drawRenderedRow(row: Row, cursorY: number, isRtl: boolean) { + protected drawRenderedRow(row: Row, cursorY: number, isRtl: boolean) { if (!Debug.config.rows) { return; } @@ -301,9 +287,8 @@ export class Debug { * @param row The non-empty row to render. * @param cursorY The y position of the top of the row. * @param isRtl Whether the block is rendered RTL. - * @internal */ - drawRowWithElements(row: Row, cursorY: number, isRtl: boolean) { + protected drawRowWithElements(row: Row, cursorY: number, isRtl: boolean) { for (let i = 0; i < row.elements.length; i++) { const elem = row.elements[i]; if (!elem) { @@ -323,9 +308,8 @@ export class Debug { * Draw a debug rectangle around the entire block. * * @param info Rendering information about the block to debug. - * @internal */ - drawBoundingBox(info: RenderInfo) { + protected drawBoundingBox(info: RenderInfo) { if (!Debug.config.blockBounds) { return; } @@ -370,7 +354,6 @@ export class Debug { * * @param block The block to draw debug information for. * @param info Rendering information about the block to debug. - * @internal */ drawDebug(block: BlockSvg, info: RenderInfo) { this.clearElems(); @@ -417,9 +400,8 @@ export class Debug { * Show a debug filter to highlight that a block has been rendered. * * @param svgPath The block's SVG path. - * @internal */ - drawRender(svgPath: SVGElement) { + protected drawRender(svgPath: SVGElement) { if (!Debug.config.render) { return; } diff --git a/core/renderers/common/drawer.ts b/core/renderers/common/drawer.ts index 8751252da..fa81e7eb1 100644 --- a/core/renderers/common/drawer.ts +++ b/core/renderers/common/drawer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for graphically rendering a block as SVG. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Drawer'); @@ -32,8 +27,6 @@ import type {RenderInfo} from './info.js'; /** * An object that draws a block based on the given rendering information. - * - * @alias Blockly.blockRendering.Drawer */ export class Drawer { block_: BlockSvg; @@ -47,7 +40,6 @@ export class Drawer { * @param block The block to render. * @param info An object containing all information needed to render this * block. - * @internal */ constructor(block: BlockSvg, info: RenderInfo) { this.block_ = block; @@ -66,8 +58,6 @@ export class Drawer { * joined with spaces and set directly on the block. This guarantees that * the steps are separated by spaces for improved readability, but isn't * required. - * - * @internal */ draw() { this.hideHiddenIcons_(); diff --git a/core/renderers/common/i_path_object.ts b/core/renderers/common/i_path_object.ts index 0d49835ec..68608910e 100644 --- a/core/renderers/common/i_path_object.ts +++ b/core/renderers/common/i_path_object.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The interface for an object that owns a block's rendering SVG - * elements. - * - * @namespace Blockly.blockRendering.IPathObject - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.IPathObject'); @@ -24,13 +18,10 @@ import {RenderedConnection} from '../../rendered_connection.js'; * * @param _root The root SVG element. * @param _constants The renderer's constants. - * @alias Blockly.blockRendering.IPathObject */ export interface IPathObject { /** * The primary path of the block. - * - * @internal */ svgPath: SVGElement; @@ -56,7 +47,6 @@ export interface IPathObject { * Set the path generated by the renderer onto the respective SVG element. * * @param pathString The path. - * @internal */ setPath(pathString: string): void; @@ -65,7 +55,6 @@ export interface IPathObject { * the paths belong to a shadow block. * * @param block The source block. - * @internal */ applyColour(block: BlockSvg): void; @@ -73,14 +62,11 @@ export interface IPathObject { * Update the style. * * @param blockStyle The block style to use. - * @internal */ setStyle(blockStyle: BlockStyle): void; /** * Flip the SVG paths in RTL. - * - * @internal */ flipRTL(): void; @@ -89,7 +75,6 @@ export interface IPathObject { * * @param cursorSvg The SVG root of the cursor to be added to the block SVG * group. - * @internal */ setCursorSvg(cursorSvg: SVGElement): void; @@ -98,7 +83,6 @@ export interface IPathObject { * * @param markerSvg The SVG root of the marker to be added to the block SVG * group. - * @internal */ setMarkerSvg(markerSvg: SVGElement): void; @@ -107,7 +91,6 @@ export interface IPathObject { * often used to visually mark blocks currently being executed. * * @param highlighted True if highlighted. - * @internal */ updateHighlighted(highlighted: boolean): void; @@ -115,7 +98,6 @@ export interface IPathObject { * Add or remove styling showing that a block is selected. * * @param enable True if selection is enabled, false otherwise. - * @internal */ updateSelected(enabled: boolean): void; @@ -124,7 +106,6 @@ export interface IPathObject { * * @param enable True if the block is being dragged over a delete area, false * otherwise. - * @internal */ updateDraggingDelete(enabled: boolean): void; @@ -132,7 +113,6 @@ export interface IPathObject { * Add or remove styling showing that a block is an insertion marker. * * @param enable True if the block is an insertion marker, false otherwise. - * @internal */ updateInsertionMarker(enabled: boolean): void; @@ -140,7 +120,6 @@ export interface IPathObject { * Add or remove styling showing that a block is movable. * * @param enable True if the block is movable, false otherwise. - * @internal */ updateMovable(enabled: boolean): void; @@ -150,7 +129,6 @@ export interface IPathObject { * Otherwise it will bump. * * @param enable True if styling should be added. - * @internal */ updateReplacementFade(enabled: boolean): void; @@ -160,7 +138,6 @@ export interface IPathObject { * * @param conn The connection on the input to highlight. * @param enable True if styling should be added. - * @internal */ updateShapeForInputHighlight(conn: RenderedConnection, enable: boolean): void; } diff --git a/core/renderers/common/info.ts b/core/renderers/common/info.ts index 1d0a9e0e7..1a162a676 100644 --- a/core/renderers/common/info.ts +++ b/core/renderers/common/info.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for graphically rendering a block as SVG. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.RenderInfo'); @@ -47,8 +42,6 @@ import type {Renderer} from './renderer.js'; * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @alias Blockly.blockRendering.RenderInfo */ export class RenderInfo { block_: BlockSvg; @@ -94,7 +87,6 @@ export class RenderInfo { /** * @param renderer The renderer in use. * @param block The block to measure. - * @internal */ constructor(renderer: Renderer, block: BlockSvg) { this.renderer_ = renderer; @@ -145,7 +137,6 @@ export class RenderInfo { * Get the block renderer in use. * * @returns The block renderer in use. - * @internal */ getRenderer(): Renderer { return this.renderer_; @@ -158,8 +149,6 @@ export class RenderInfo { * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @internal */ measure() { this.createRows_(); @@ -227,10 +216,8 @@ export class RenderInfo { /** * Create all non-spacer elements that belong on the top row. - * - * @internal */ - populateTopRow_() { + protected populateTopRow_() { const hasPrevious = !!this.block_.previousConnection; const hasHat = (this.block_.hat ? this.block_.hat === 'cap' : this.constants_.ADD_START_HATS) && @@ -272,10 +259,8 @@ export class RenderInfo { /** * Create all non-spacer elements that belong on the bottom row. - * - * @internal */ - populateBottomRow_() { + protected populateBottomRow_() { this.bottomRow.hasNextConnection = !!this.block_.nextConnection; const followsStatement = this.block_.inputList.length && diff --git a/core/renderers/common/marker_svg.ts b/core/renderers/common/marker_svg.ts index 67e4fdb8a..503df4565 100644 --- a/core/renderers/common/marker_svg.ts +++ b/core/renderers/common/marker_svg.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for graphically rendering a marker as SVG. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.MarkerSvg'); @@ -45,9 +40,8 @@ const MARKER_CLASS = 'blocklyMarker'; const HEIGHT_MULTIPLIER = 3 / 4; /** - * Class for a marker. - * - * @alias Blockly.blockRendering.MarkerSvg + * Class for a marker, containing methods for graphically rendering a marker as + * SVG. */ export class MarkerSvg { /** @@ -123,7 +117,6 @@ export class MarkerSvg { * Create the DOM element for the marker. * * @returns The marker controls SVG group. - * @internal */ createDom(): SVGElement { const className = this.isCursor() ? CURSOR_CLASS : MARKER_CLASS; diff --git a/core/renderers/common/path_object.ts b/core/renderers/common/path_object.ts index c28a629e4..a262fef99 100644 --- a/core/renderers/common/path_object.ts +++ b/core/renderers/common/path_object.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that owns a block's rendering SVG elements. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.PathObject'); @@ -25,40 +20,30 @@ import type {IPathObject} from './i_path_object.js'; /** * An object that handles creating and setting each of the SVG elements * used by the renderer. - * - * @alias Blockly.blockRendering.PathObject */ export class PathObject implements IPathObject { svgRoot: SVGElement; - /** @internal */ svgPath: SVGElement; /** * Holds the cursors svg element when the cursor is attached to the block. * This is null if there is no cursor on the block. - * - * @internal */ cursorSvg: SVGElement|null = null; /** * Holds the markers svg element when the marker is attached to the block. * This is null if there is no marker on the block. - * - * @internal */ markerSvg: SVGElement|null = null; - /** @internal */ constants: ConstantProvider; - /** @internal */ style: BlockStyle; /** * @param root The root SVG element. * @param style The style object to use for colouring. * @param constants The renderer's constants. - * @internal */ constructor( root: SVGElement, style: BlockStyle, constants: ConstantProvider) { @@ -75,7 +60,6 @@ export class PathObject implements IPathObject { * Set the path generated by the renderer onto the respective SVG element. * * @param pathString The path. - * @internal */ setPath(pathString: string) { this.svgPath.setAttribute('d', pathString); @@ -83,8 +67,6 @@ export class PathObject implements IPathObject { /** * Flip the SVG paths in RTL. - * - * @internal */ flipRTL() { // Mirror the block's path. @@ -96,7 +78,6 @@ export class PathObject implements IPathObject { * * @param cursorSvg The SVG root of the cursor to be added to the block SVG * group. - * @internal */ setCursorSvg(cursorSvg: SVGElement) { if (!cursorSvg) { @@ -113,7 +94,6 @@ export class PathObject implements IPathObject { * * @param markerSvg The SVG root of the marker to be added to the block SVG * group. - * @internal */ setMarkerSvg(markerSvg: SVGElement) { if (!markerSvg) { @@ -134,7 +114,6 @@ export class PathObject implements IPathObject { * the paths belong to a shadow block. * * @param block The source block. - * @internal */ applyColour(block: BlockSvg) { this.svgPath.setAttribute('stroke', this.style.colourTertiary); @@ -148,7 +127,6 @@ export class PathObject implements IPathObject { * Set the style. * * @param blockStyle The block style to use. - * @internal */ setStyle(blockStyle: BlockStyle) { this.style = blockStyle; @@ -177,7 +155,6 @@ export class PathObject implements IPathObject { * often used to visually mark blocks currently being executed. * * @param enable True if highlighted. - * @internal */ updateHighlighted(enable: boolean) { if (enable) { @@ -217,7 +194,6 @@ export class PathObject implements IPathObject { * Add or remove styling showing that a block is selected. * * @param enable True if selection is enabled, false otherwise. - * @internal */ updateSelected(enable: boolean) { this.setClass_('blocklySelected', enable); @@ -228,7 +204,6 @@ export class PathObject implements IPathObject { * * @param enable True if the block is being dragged over a delete area, false * otherwise. - * @internal */ updateDraggingDelete(enable: boolean) { this.setClass_('blocklyDraggingDelete', enable); @@ -238,7 +213,6 @@ export class PathObject implements IPathObject { * Add or remove styling showing that a block is an insertion marker. * * @param enable True if the block is an insertion marker, false otherwise. - * @internal */ updateInsertionMarker(enable: boolean) { this.setClass_('blocklyInsertionMarker', enable); @@ -248,7 +222,6 @@ export class PathObject implements IPathObject { * Add or remove styling showing that a block is movable. * * @param enable True if the block is movable, false otherwise. - * @internal */ updateMovable(enable: boolean) { this.setClass_('blocklyDraggable', enable); @@ -260,7 +233,6 @@ export class PathObject implements IPathObject { * Otherwise it will bump. * * @param enable True if styling should be added. - * @internal */ updateReplacementFade(enable: boolean) { this.setClass_('blocklyReplaceable', enable); @@ -272,7 +244,6 @@ export class PathObject implements IPathObject { * * @param _conn The connection on the input to highlight. * @param _enable True if styling should be added. - * @internal */ updateShapeForInputHighlight(_conn: Connection, _enable: boolean) { // NOOP diff --git a/core/renderers/common/renderer.ts b/core/renderers/common/renderer.ts index ef2ab2146..3b99d23ba 100644 --- a/core/renderers/common/renderer.ts +++ b/core/renderers/common/renderer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Base renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Renderer'); @@ -35,26 +30,20 @@ import {PathObject} from './path_object.js'; /** * The base class for a block renderer. - * - * @alias Blockly.blockRendering.Renderer */ export class Renderer implements IRegistrable { /** The renderer's constant provider. */ protected constants_!: ConstantProvider; - /** @internal */ - name: string; + protected name: string; /** * Rendering constant overrides, passed in through options. - * - * @internal */ - overrides: object|null = null; + protected overrides: object|null = null; /** * @param name The renderer name. - * @internal */ constructor(name: string) { this.name = name; @@ -64,7 +53,6 @@ export class Renderer implements IRegistrable { * Gets the class name that identifies this renderer. * * @returns The CSS class name. - * @internal */ getClassName(): string { return this.name + '-renderer'; @@ -75,7 +63,6 @@ export class Renderer implements IRegistrable { * * @param theme The workspace theme object. * @param opt_rendererOverrides Rendering constant overrides. - * @internal */ init( theme: Theme, opt_rendererOverrides?: {[rendererConstant: string]: any}) { @@ -90,6 +77,8 @@ export class Renderer implements IRegistrable { /** * Create any DOM elements that this renderer needs. + * If you need to create additional DOM elements, override the + * {@link ConstantProvider#createDom} method instead. * * @param svg The root of the workspace's SVG. * @param theme The workspace theme object. @@ -106,7 +95,6 @@ export class Renderer implements IRegistrable { * * @param svg The root of the workspace's SVG. * @param theme The workspace theme object. - * @internal */ refreshDom(svg: SVGElement, theme: Theme) { const previousConstants = this.getConstants(); @@ -125,8 +113,6 @@ export class Renderer implements IRegistrable { /** * Dispose of this renderer. * Delete all DOM elements that this renderer and its constants created. - * - * @internal */ dispose() { if (this.constants_) { @@ -182,7 +168,6 @@ export class Renderer implements IRegistrable { * @param workspace The workspace the marker belongs to. * @param marker The marker. * @returns The object in charge of drawing the marker. - * @internal */ makeMarkerDrawer(workspace: WorkspaceSvg, marker: Marker): MarkerSvg { return new MarkerSvg(workspace, this.getConstants(), marker); @@ -194,7 +179,6 @@ export class Renderer implements IRegistrable { * @param root The root SVG element. * @param style The style object to use for colouring. * @returns The renderer path object. - * @internal */ makePathObject(root: SVGElement, style: BlockStyle): IPathObject { return new PathObject(root, style, (this.constants_)); @@ -205,7 +189,6 @@ export class Renderer implements IRegistrable { * called, the renderer has already been initialized. * * @returns The constant provider. - * @internal */ getConstants(): ConstantProvider { return this.constants_; @@ -216,7 +199,6 @@ export class Renderer implements IRegistrable { * * @param _conn The connection to determine whether or not to highlight. * @returns True if we should highlight the connection. - * @internal */ shouldHighlightConnection(_conn: Connection): boolean { return true; @@ -233,9 +215,8 @@ export class Renderer implements IRegistrable { * @param orphanBlock The orphan block that wants to find a home. * @param localType The type of the connection being dragged. * @returns Whether there is a home for the orphan or not. - * @internal */ - orphanCanConnectAtEnd( + protected orphanCanConnectAtEnd( topBlock: BlockSvg, orphanBlock: BlockSvg, localType: number): boolean { const orphanConnection = localType === ConnectionType.OUTPUT_VALUE ? orphanBlock.outputConnection : @@ -252,7 +233,6 @@ export class Renderer implements IRegistrable { * @param local The connection currently being dragged. * @param topBlock The block currently being dragged. * @returns The preview type to display. - * @internal */ getConnectionPreviewMethod( closest: RenderedConnection, local: RenderedConnection, diff --git a/core/renderers/geras/constants.ts b/core/renderers/geras/constants.ts index 7eb829d94..c7d0c498a 100644 --- a/core/renderers/geras/constants.ts +++ b/core/renderers/geras/constants.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that provides constants for rendering blocks in Geras - * mode. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.ConstantProvider'); @@ -18,8 +12,6 @@ import {ConstantProvider as BaseConstantProvider} from '../common/constants.js'; /** * An object that provides constants for rendering blocks in Geras mode. - * - * @alias Blockly.geras.ConstantProvider */ export class ConstantProvider extends BaseConstantProvider { override FIELD_TEXT_BASELINE_CENTER = false; @@ -35,9 +27,6 @@ export class ConstantProvider extends BaseConstantProvider { MAX_BOTTOM_WIDTH = 30; override STATEMENT_BOTTOM_SPACER = -this.NOTCH_HEIGHT / 2; - /** - * @internal - */ constructor() { super(); } diff --git a/core/renderers/geras/drawer.ts b/core/renderers/geras/drawer.ts index b0469e259..0ccff67bc 100644 --- a/core/renderers/geras/drawer.ts +++ b/core/renderers/geras/drawer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Renderer that preserves the look and feel of Blockly pre-2019. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.Drawer'); @@ -26,9 +21,8 @@ import type {PathObject} from './path_object.js'; /** - * An object that draws a block based on the given rendering information. - * - * @alias Blockly.geras.Drawer + * An object that draws a block based on the given rendering information, + * customized for the geras renderer. */ export class Drawer extends BaseDrawer { highlighter_: Highlighter; @@ -39,7 +33,6 @@ export class Drawer extends BaseDrawer { * @param block The block to render. * @param info An object containing all information needed to render this * block. - * @internal */ constructor(block: BlockSvg, info: RenderInfo) { super(block, info); diff --git a/core/renderers/geras/geras.ts b/core/renderers/geras/geras.ts index 9fec7d134..6aa960a8c 100644 --- a/core/renderers/geras/geras.ts +++ b/core/renderers/geras/geras.ts @@ -6,11 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Re-exports of Blockly.geras.* modules. - * - * @namespace Blockly.geras - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras'); diff --git a/core/renderers/geras/highlight_constants.ts b/core/renderers/geras/highlight_constants.ts index fab2ec9b9..736e914ee 100644 --- a/core/renderers/geras/highlight_constants.ts +++ b/core/renderers/geras/highlight_constants.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects for rendering highlights on blocks. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.HighlightConstantProvider'); @@ -64,8 +59,6 @@ export interface JaggedTeeth { * Some highlights are simple offsets of the parent paths and can be generated * programmatically. Others, especially on curves, are just made out of piles * of constants and are hard to tweak. - * - * @alias Blockly.geras.HighlightConstantProvider */ export class HighlightConstantProvider { constantProvider: ConstantProvider; @@ -88,7 +81,6 @@ export class HighlightConstantProvider { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { /** The renderer's constant provider. */ @@ -96,16 +88,12 @@ export class HighlightConstantProvider { /** * The start point, which is offset in both X and Y, as an SVG path chunk. - * - * @internal */ this.START_POINT = svgPaths.moveBy(this.OFFSET, this.OFFSET); } /** * Initialize shape objects based on the constants set in the constructor. - * - * @internal */ init() { /** @@ -147,9 +135,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about inside * corner highlights. - * @internal */ - makeInsideCorner(): InsideCorner { + protected makeInsideCorner(): InsideCorner { const radius = this.constantProvider.CORNER_RADIUS; const offset = this.OFFSET; @@ -191,9 +178,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about outside * corner highlights. - * @internal */ - makeOutsideCorner(): OutsideCorner { + protected makeOutsideCorner(): OutsideCorner { const radius = this.constantProvider.CORNER_RADIUS; const offset = this.OFFSET; @@ -240,9 +226,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about puzzle tab * highlights. - * @internal */ - makePuzzleTab(): PuzzleTab { + protected makePuzzleTab(): PuzzleTab { const width = this.constantProvider.TAB_WIDTH; const height = this.constantProvider.TAB_HEIGHT; @@ -290,9 +275,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about notch * highlights. - * @internal */ - makeNotch(): Notch { + protected makeNotch(): Notch { // This is only for the previous connection. const pathLeft = svgPaths.lineOnAxis('h', this.OFFSET) + this.constantProvider.NOTCH.pathLeft; @@ -302,9 +286,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about collapsed * block edge highlights. - * @internal */ - makeJaggedTeeth(): JaggedTeeth { + protected makeJaggedTeeth(): JaggedTeeth { const pathLeft = svgPaths.lineTo(5.1, 2.6) + svgPaths.moveBy(-10.2, 6.8) + svgPaths.lineTo(5.1, 2.6); return {pathLeft, height: 12, width: 10.2}; @@ -313,9 +296,8 @@ export class HighlightConstantProvider { /** * @returns An object containing sizing and path information about start * highlights. - * @internal */ - makeStartHat(): StartHat { + protected makeStartHat(): StartHat { const hatHeight = this.constantProvider.START_HAT.height; const pathRtl = svgPaths.moveBy(25, -8.7) + svgPaths.curve('c', [ svgPaths.point(29.7, -6.2), diff --git a/core/renderers/geras/highlighter.ts b/core/renderers/geras/highlighter.ts index 8a619fa34..cb2c7e2c5 100644 --- a/core/renderers/geras/highlighter.ts +++ b/core/renderers/geras/highlighter.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for adding highlights on block, for rendering in - * compatibility mode. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.Highlighter'); @@ -36,8 +30,6 @@ import type {InlineInput} from './measurables/inline_input.js'; * position of each part of the block. The resulting paths are not continuous * or closed paths. The highlights for tabs and notches are loosely based on * tab and notch shapes, but are not exactly the same. - * - * @alias Blockly.geras.Highlighter */ export class Highlighter { info_: RenderInfo; @@ -57,7 +49,6 @@ export class Highlighter { /** * @param info An object containing all information needed to render this * block. - * @internal */ constructor(info: RenderInfo) { this.info_ = info; @@ -85,7 +76,6 @@ export class Highlighter { * Get the steps for the highlight path. * * @returns The steps for the highlight path. - * @internal */ getPath(): string { return this.steps_ + '\n' + this.inlineSteps_; @@ -95,7 +85,6 @@ export class Highlighter { * Add a highlight to the top corner of a block. * * @param row The top row of the block. - * @internal */ drawTopCorner(row: TopRow) { this.steps_ += svgPaths.moveBy(row.xPos, this.info_.startY); @@ -126,7 +115,6 @@ export class Highlighter { * Add a highlight on a jagged edge for a collapsed block. * * @param row The row to highlight. - * @internal */ drawJaggedEdge_(row: Row) { if (this.info_.RTL) { @@ -141,7 +129,6 @@ export class Highlighter { * Add a highlight on a value input. * * @param row The row the input belongs to. - * @internal */ drawValueInput(row: Row) { const input = row.getLastInput() as InlineInput; @@ -163,7 +150,6 @@ export class Highlighter { * Add a highlight on a statement input. * * @param row The row to highlight. - * @internal */ drawStatementInput(row: Row) { const input = row.getLastInput(); @@ -188,7 +174,6 @@ export class Highlighter { * Add a highlight on the right side of a row. * * @param row The row to highlight. - * @internal */ drawRightSideRow(row: Row) { const rightEdge = row.xPos + row.width - this.highlightOffset_; @@ -208,7 +193,6 @@ export class Highlighter { * Add a highlight to the bottom row. * * @param row The row to highlight. - * @internal */ drawBottomRow(row: BottomRow) { // Highlight the vertical edge of the bottom row on the input side. @@ -231,8 +215,6 @@ export class Highlighter { /** * Draw the highlight on the left side of the block. - * - * @internal */ drawLeft() { const outputConnection = this.info_.outputConnection; @@ -267,7 +249,6 @@ export class Highlighter { * Add a highlight to an inline input. * * @param input The input to highlight. - * @internal */ drawInlineInput(input: InlineInput) { const offset = this.highlightOffset_; diff --git a/core/renderers/geras/info.ts b/core/renderers/geras/info.ts index 305cde369..78262cdb9 100644 --- a/core/renderers/geras/info.ts +++ b/core/renderers/geras/info.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Old (compatibility) renderer. - * Geras: spirit of old age. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.RenderInfo'); @@ -34,13 +28,12 @@ import type {Renderer} from './renderer.js'; /** - * An object containing all sizing information needed to draw this block. + * An object containing all sizing information needed to draw this block, + * customized for the geras renderer. * * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @alias Blockly.geras.RenderInfo */ export class RenderInfo extends BaseRenderInfo { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -51,7 +44,6 @@ export class RenderInfo extends BaseRenderInfo { /** * @param renderer The renderer in use. * @param block The block to measure. - * @internal */ constructor(renderer: Renderer, block: BlockSvg) { super(renderer, block); @@ -62,7 +54,6 @@ export class RenderInfo extends BaseRenderInfo { * Get the block renderer in use. * * @returns The block renderer in use. - * @internal */ override getRenderer(): Renderer { return this.renderer_; diff --git a/core/renderers/geras/measurables/inline_input.ts b/core/renderers/geras/measurables/inline_input.ts index be3b6578a..b361528f0 100644 --- a/core/renderers/geras/measurables/inline_input.ts +++ b/core/renderers/geras/measurables/inline_input.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing inline inputs with connections on a - * rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.InlineInput'); @@ -23,8 +17,6 @@ import type {ConstantProvider as GerasConstantProvider} from '../constants.js'; /** * An object containing information about the space an inline input takes up * during rendering. - * - * @alias Blockly.geras.InlineInput */ export class InlineInput extends BaseInlineInput { override constants_: GerasConstantProvider; @@ -32,7 +24,6 @@ export class InlineInput extends BaseInlineInput { /** * @param constants The rendering constants provider. * @param input The inline input to measure and store information for. - * @internal */ constructor(constants: BaseConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/geras/measurables/statement_input.ts b/core/renderers/geras/measurables/statement_input.ts index 2fa21fa11..3720fce01 100644 --- a/core/renderers/geras/measurables/statement_input.ts +++ b/core/renderers/geras/measurables/statement_input.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing statement inputs with connections on a - * rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.StatementInput'); @@ -23,8 +17,6 @@ import type {ConstantProvider as GerasConstantProvider} from '../constants.js'; /** * An object containing information about the space a statement input takes up * during rendering. - * - * @alias Blockly.geras.StatementInput */ export class StatementInput extends BaseStatementInput { override constants_: GerasConstantProvider; @@ -32,7 +24,6 @@ export class StatementInput extends BaseStatementInput { /** * @param constants The rendering constants provider. * @param input The statement input to measure and store information for. - * @internal */ constructor(constants: BaseConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/geras/path_object.ts b/core/renderers/geras/path_object.ts index 07d2fcbc5..dcdcb6673 100644 --- a/core/renderers/geras/path_object.ts +++ b/core/renderers/geras/path_object.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that owns a block's rendering SVG elements. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.PathObject'); @@ -25,19 +20,13 @@ import type {ConstantProvider} from './constants.js'; /** * An object that handles creating and setting each of the SVG elements * used by the renderer. - * - * @alias Blockly.geras.PathObject */ export class PathObject extends BasePathObject { - /** @internal */ svgPathDark: SVGElement; - /** @internal */ svgPathLight: SVGElement; /** * The colour of the dark path on the block in '#RRGGBB' format. - * - * @internal */ colourDark = '#000000'; @@ -45,7 +34,6 @@ export class PathObject extends BasePathObject { * @param root The root SVG element. * @param style The style object to use for colouring. * @param constants The renderer's constants. - * @internal */ constructor( root: SVGElement, style: BlockStyle, @@ -74,7 +62,6 @@ export class PathObject extends BasePathObject { * Set the highlight path generated by the renderer onto the SVG element. * * @param highlightPath The highlight path. - * @internal */ setHighlightPath(highlightPath: string) { this.svgPathLight.setAttribute('d', highlightPath); diff --git a/core/renderers/geras/renderer.ts b/core/renderers/geras/renderer.ts index bdc4969b2..54b36cfc1 100644 --- a/core/renderers/geras/renderer.ts +++ b/core/renderers/geras/renderer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Geras renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.geras.Renderer'); @@ -26,9 +21,12 @@ import {PathObject} from './path_object.js'; /** - * The geras renderer. + * The geras renderer. This renderer was designed to be backwards compatible + * with pre-2019 Blockly. Newer projects that are not constrained by backwards + * compatibility should use thrasos, which is a more modern take on this + * renderer. * - * @alias Blockly.geras.Renderer + * Geras is the ancient Greek spirit of old age. */ export class Renderer extends BaseRenderer { /** The renderer's highlight constant provider. */ @@ -36,7 +34,6 @@ export class Renderer extends BaseRenderer { /** * @param name The renderer name. - * @internal */ constructor(name: string) { super(name); @@ -45,8 +42,6 @@ export class Renderer extends BaseRenderer { /** * Initialize the renderer. Geras has a highlight provider in addition to * the normal constant provider. - * - * @internal */ override init( theme: Theme, opt_rendererOverrides?: {[rendererConstant: string]: any}) { @@ -93,7 +88,6 @@ export class Renderer extends BaseRenderer { * @param root The root SVG element. * @param style The style object to use for colouring. * @returns The renderer path object. - * @internal */ override makePathObject(root: SVGElement, style: BlockStyle): PathObject { return new PathObject( @@ -114,7 +108,6 @@ export class Renderer extends BaseRenderer { * is called, the renderer has already been initialized. * * @returns The highlight constant provider. - * @internal */ getHighlightConstants(): HighlightConstantProvider { if (!this.highlightConstants_) { diff --git a/core/renderers/measurables/base.ts b/core/renderers/measurables/base.ts index 105396b63..98a9510c8 100644 --- a/core/renderers/measurables/base.ts +++ b/core/renderers/measurables/base.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for graphically rendering a block as SVG. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Measurable'); @@ -21,8 +16,6 @@ import {Types} from './types.js'; * The base class to represent a part of a block that takes up space during * rendering. The constructor for each non-spacer Measurable records the size * of the block element (e.g. field, statement input). - * - * @alias Blockly.blockRendering.Measurable */ export class Measurable { width = 0; @@ -39,7 +32,6 @@ export class Measurable { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { this.constants_ = constants; diff --git a/core/renderers/measurables/bottom_row.ts b/core/renderers/measurables/bottom_row.ts index f72809052..36418afad 100644 --- a/core/renderers/measurables/bottom_row.ts +++ b/core/renderers/measurables/bottom_row.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object representing a bottom row on a rendered block. - * of its subcomponents. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.BottomRow'); @@ -26,21 +20,15 @@ import {Types} from './types.js'; * a block as well as spacing information for the bottom row. * Elements in a bottom row can consist of corners, spacers and next * connections. - * - * @alias Blockly.blockRendering.BottomRow */ export class BottomRow extends Row { /** * Whether this row has a next connection. - * - * @internal */ hasNextConnection = false; /** * The next connection on the row, if any. - * - * @internal */ connection: NextConnection|null = null; @@ -48,8 +36,6 @@ export class BottomRow extends Row { * The amount that the bottom of the block extends below the horizontal * edge, e.g. because of a next connection. Must be non-negative (see * #2820). - * - * @internal */ descenderHeight = 0; @@ -61,7 +47,6 @@ export class BottomRow extends Row { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/measurables/connection.ts b/core/renderers/measurables/connection.ts index ab4dbcd37..d69374a90 100644 --- a/core/renderers/measurables/connection.ts +++ b/core/renderers/measurables/connection.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Base class representing the space a connection takes up during - * rendering. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Connection'); @@ -24,8 +18,6 @@ import {Types} from './types.js'; /** * The base class to represent a connection and the space that it takes up on * the block. - * - * @alias Blockly.blockRendering.Connection */ export class Connection extends Measurable { shape: Shape; @@ -35,7 +27,6 @@ export class Connection extends Measurable { * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this * represents. - * @internal */ constructor( constants: ConstantProvider, public connectionModel: RenderedConnection) { diff --git a/core/renderers/measurables/external_value_input.ts b/core/renderers/measurables/external_value_input.ts index 86adebe9d..bcb0aea4d 100644 --- a/core/renderers/measurables/external_value_input.ts +++ b/core/renderers/measurables/external_value_input.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing external value inputs with connections on a - * rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.ExternalValueInput'); @@ -24,8 +18,6 @@ import {Types} from './types.js'; /** * An object containing information about the space an external value input * takes up during rendering - * - * @alias Blockly.blockRendering.ExternalValueInput */ export class ExternalValueInput extends InputConnection { override height = 0; @@ -37,7 +29,6 @@ export class ExternalValueInput extends InputConnection { /** * @param constants The rendering constants provider. * @param input The external value input to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/measurables/field.ts b/core/renderers/measurables/field.ts index 344f3e636..46c043d69 100644 --- a/core/renderers/measurables/field.ts +++ b/core/renderers/measurables/field.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a field in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Field'); @@ -25,8 +19,6 @@ import {Types} from './types.js'; /** * An object containing information about the space a field takes up during * rendering - * - * @alias Blockly.blockRendering.Field */ export class Field extends Measurable { isEditable: boolean; @@ -38,7 +30,6 @@ export class Field extends Measurable { * @param constants The rendering constants provider. * @param field The field to measure and store information for. * @param parentInput The parent input for the field. - * @internal */ constructor( constants: ConstantProvider, public field: BlocklyField, diff --git a/core/renderers/measurables/hat.ts b/core/renderers/measurables/hat.ts index 2d747c834..c35f8947b 100644 --- a/core/renderers/measurables/hat.ts +++ b/core/renderers/measurables/hat.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a hat in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Hat'); @@ -22,15 +16,12 @@ import {Types} from './types.js'; /** * An object containing information about the space a hat takes up during * rendering. - * - * @alias Blockly.blockRendering.Hat */ export class Hat extends Measurable { ascenderHeight: number; /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/measurables/icon.ts b/core/renderers/measurables/icon.ts index 3fdfd99fd..afba526ed 100644 --- a/core/renderers/measurables/icon.ts +++ b/core/renderers/measurables/icon.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing an icon in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Icon'); @@ -23,9 +17,7 @@ import {Types} from './types.js'; /** * An object containing information about the space an icon takes up during - * rendering - * - * @alias Blockly.blockRendering.Icon + * rendering. */ export class Icon extends Measurable { isVisible: boolean; @@ -33,11 +25,10 @@ export class Icon extends Measurable { /** * An object containing information about the space an icon takes up during - * rendering + * rendering. * * @param constants The rendering constants provider. * @param icon The icon to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, public icon: BlocklyIcon) { super(constants); diff --git a/core/renderers/measurables/in_row_spacer.ts b/core/renderers/measurables/in_row_spacer.ts index c3474f403..589b14608 100644 --- a/core/renderers/measurables/in_row_spacer.ts +++ b/core/renderers/measurables/in_row_spacer.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a spacer in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.InRowSpacer'); @@ -22,14 +16,11 @@ import {Types} from './types.js'; /** * An object containing information about a spacer between two elements on a * row. - * - * @alias Blockly.blockRendering.InRowSpacer */ export class InRowSpacer extends Measurable { /** * @param constants The rendering constants provider. * @param width The width of the spacer. - * @internal */ constructor(constants: ConstantProvider, width: number) { super(constants); diff --git a/core/renderers/measurables/inline_input.ts b/core/renderers/measurables/inline_input.ts index a252b5950..5b04370fc 100644 --- a/core/renderers/measurables/inline_input.ts +++ b/core/renderers/measurables/inline_input.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing inline inputs with connections on a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.InlineInput'); @@ -23,9 +17,7 @@ import {Types} from './types.js'; /** * An object containing information about the space an inline input takes up - * during rendering - * - * @alias Blockly.blockRendering.InlineInput + * during rendering. */ export class InlineInput extends InputConnection { connectionHeight: number; @@ -34,7 +26,6 @@ export class InlineInput extends InputConnection { /** * @param constants The rendering constants provider. * @param input The inline input to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/measurables/input_connection.ts b/core/renderers/measurables/input_connection.ts index 3a2d23a06..64d0769be 100644 --- a/core/renderers/measurables/input_connection.ts +++ b/core/renderers/measurables/input_connection.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing inputs with connections on a rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.InputConnection'); @@ -23,9 +18,7 @@ import {Types} from './types.js'; /** * The base class to represent an input that takes up space on a block - * during rendering - * - * @alias Blockly.blockRendering.InputConnection + * during rendering. */ export class InputConnection extends Connection { align: number; @@ -38,7 +31,6 @@ export class InputConnection extends Connection { /** * @param constants The rendering constants provider. * @param input The input to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, public input: Input) { super(constants, input.connection as RenderedConnection); diff --git a/core/renderers/measurables/input_row.ts b/core/renderers/measurables/input_row.ts index 40854f958..65bf43480 100644 --- a/core/renderers/measurables/input_row.ts +++ b/core/renderers/measurables/input_row.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object representing a row that holds one or more inputs on a - * rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.InputRow'); @@ -24,20 +18,15 @@ import {Types} from './types.js'; /** * An object containing information about a row that holds one or more inputs. - * - * @alias Blockly.blockRendering.InputRow */ export class InputRow extends Row { /** * The total width of all blocks connected to this row. - * - * @internal */ connectedBlockWidths = 0; /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); @@ -46,8 +35,6 @@ export class InputRow extends Row { /** * Inspect all subcomponents and populate all size properties on the row. - * - * @internal */ override measure() { this.width = this.minWidth; diff --git a/core/renderers/measurables/jagged_edge.ts b/core/renderers/measurables/jagged_edge.ts index b9721ffab..72ef7fb60 100644 --- a/core/renderers/measurables/jagged_edge.ts +++ b/core/renderers/measurables/jagged_edge.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a jagged edge in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.JaggedEdge'); @@ -20,15 +14,12 @@ import {Types} from './types.js'; /** - * An object containing information about the jagged edge of a collapsed block - * takes up during rendering - * - * @alias Blockly.blockRendering.JaggedEdge + * An object containing information about the space the jagged edge of a + * collapsed block takes up during rendering. */ export class JaggedEdge extends Measurable { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/measurables/next_connection.ts b/core/renderers/measurables/next_connection.ts index 9be182963..997e4c0f9 100644 --- a/core/renderers/measurables/next_connection.ts +++ b/core/renderers/measurables/next_connection.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing the space a next connection takes up during - * rendering. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.NextConnection'); @@ -23,15 +17,12 @@ import {Types} from './types.js'; /** * An object containing information about the space a next connection takes * up during rendering. - * - * @alias Blockly.blockRendering.NextConnection */ export class NextConnection extends Connection { /** * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this * represents. - * @internal */ constructor( constants: ConstantProvider, connectionModel: RenderedConnection) { diff --git a/core/renderers/measurables/output_connection.ts b/core/renderers/measurables/output_connection.ts index 17a73c1c2..7d493b002 100644 --- a/core/renderers/measurables/output_connection.ts +++ b/core/renderers/measurables/output_connection.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing the space a output connection takes up - * during rendering. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.OutputConnection'); @@ -23,8 +17,6 @@ import {Types} from './types.js'; /** * An object containing information about the space an output connection takes * up during rendering. - * - * @alias Blockly.blockRendering.OutputConnection */ export class OutputConnection extends Connection { startX: number; @@ -35,7 +27,6 @@ export class OutputConnection extends Connection { * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this * represents. - * @internal */ constructor( constants: ConstantProvider, connectionModel: RenderedConnection) { diff --git a/core/renderers/measurables/previous_connection.ts b/core/renderers/measurables/previous_connection.ts index cb65f8746..b2b2444a5 100644 --- a/core/renderers/measurables/previous_connection.ts +++ b/core/renderers/measurables/previous_connection.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing the space a previous connection takes up - * during rendering. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.PreviousConnection'); @@ -23,15 +17,12 @@ import {Types} from './types.js'; /** * An object containing information about the space a previous connection takes * up during rendering. - * - * @alias Blockly.blockRendering.PreviousConnection */ export class PreviousConnection extends Connection { /** * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this * represents. - * @internal */ constructor( constants: ConstantProvider, connectionModel: RenderedConnection) { diff --git a/core/renderers/measurables/round_corner.ts b/core/renderers/measurables/round_corner.ts index 0e0c809bf..ad7ebab02 100644 --- a/core/renderers/measurables/round_corner.ts +++ b/core/renderers/measurables/round_corner.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a round corner in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.RoundCorner'); @@ -22,14 +16,11 @@ import {Types} from './types.js'; /** * An object containing information about the space a rounded corner takes up * during rendering. - * - * @alias Blockly.blockRendering.RoundCorner */ export class RoundCorner extends Measurable { /** * @param constants The rendering constants provider. * @param opt_position The position of this corner. - * @internal */ constructor(constants: ConstantProvider, opt_position?: string) { super(constants); diff --git a/core/renderers/measurables/row.ts b/core/renderers/measurables/row.ts index 17aed1e07..77e9472f0 100644 --- a/core/renderers/measurables/row.ts +++ b/core/renderers/measurables/row.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object representing a single row on a rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Row'); @@ -23,85 +18,62 @@ import {Types} from './types.js'; /** * An object representing a single row on a rendered block and all of its * subcomponents. - * - * @alias Blockly.blockRendering.Row */ export class Row { - /** @internal */ type: number; /** * An array of elements contained in this row. - * - * @internal */ elements: Measurable[] = []; /** * The height of the row. - * - * @internal */ height = 0; /** * The width of the row, from the left edge of the block to the right. * Does not include child blocks unless they are inline. - * - * @internal */ width = 0; /** * The minimum height of the row. - * - * @internal */ minHeight = 0; /** * The minimum width of the row, from the left edge of the block to the * right. Does not include child blocks unless they are inline. - * - * @internal */ minWidth = 0; /** * The width of the row, from the left edge of the block to the edge of the * block or any connected child blocks. - * - * @internal */ widthWithConnectedBlocks = 0; /** * The Y position of the row relative to the origin of the block's svg * group. - * - * @internal */ yPos = 0; /** * The X position of the row relative to the origin of the block's svg * group. - * - * @internal */ xPos = 0; /** * Whether the row has any external inputs. - * - * @internal */ hasExternalInput = false; /** * Whether the row has any statement inputs. - * - * @internal */ hasStatement = false; @@ -114,30 +86,22 @@ export class Row { /** * Whether the row has any inline inputs. - * - * @internal */ hasInlineInput = false; /** * Whether the row has any dummy inputs. - * - * @internal */ hasDummyInput = false; /** * Whether the row has a jagged edge. - * - * @internal */ hasJaggedEdge = false; notchOffset: number; /** * Alignment of the row. - * - * @internal */ align: number|null = null; @@ -145,7 +109,6 @@ export class Row { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { /** The renderer's constant provider. */ @@ -161,7 +124,6 @@ export class Row { * Get the last input on this row, if it has one. * * @returns The last input on the row, or null. - * @internal */ getLastInput(): InputConnection|null { // TODO: Consider moving this to InputRow, if possible. @@ -176,8 +138,6 @@ export class Row { /** * Inspect all subcomponents and populate all size properties on the row. - * - * @internal */ measure() { throw Error('Unexpected attempt to measure a base Row.'); @@ -187,7 +147,6 @@ export class Row { * Determines whether this row should start with an element spacer. * * @returns Whether the row should start with a spacer. - * @internal */ startsWithElemSpacer(): boolean { return true; @@ -197,7 +156,6 @@ export class Row { * Determines whether this row should end with an element spacer. * * @returns Whether the row should end with a spacer. - * @internal */ endsWithElemSpacer(): boolean { return true; @@ -207,7 +165,6 @@ export class Row { * Convenience method to get the first spacer element on this row. * * @returns The first spacer element on this row. - * @internal */ getFirstSpacer(): InRowSpacer|null { for (let i = 0; i < this.elements.length; i++) { @@ -223,7 +180,6 @@ export class Row { * Convenience method to get the last spacer element on this row. * * @returns The last spacer element on this row. - * @internal */ getLastSpacer(): InRowSpacer|null { for (let i = this.elements.length - 1; i >= 0; i--) { diff --git a/core/renderers/measurables/spacer_row.ts b/core/renderers/measurables/spacer_row.ts index 2a9d1be26..47970ea00 100644 --- a/core/renderers/measurables/spacer_row.ts +++ b/core/renderers/measurables/spacer_row.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object representing a spacer between two rows. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.SpacerRow'); @@ -21,8 +16,6 @@ import {Types} from './types.js'; /** * An object containing information about a spacer between two rows. - * - * @alias Blockly.blockRendering.SpacerRow */ export class SpacerRow extends Row { followsStatement = false; @@ -36,7 +29,6 @@ export class SpacerRow extends Row { * @param constants The rendering constants provider. * @param height The height of the spacer. * @param width The width of the spacer. - * @internal */ constructor( constants: ConstantProvider, public override height: number, diff --git a/core/renderers/measurables/square_corner.ts b/core/renderers/measurables/square_corner.ts index a37e63d23..d30b36fa0 100644 --- a/core/renderers/measurables/square_corner.ts +++ b/core/renderers/measurables/square_corner.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Objects representing a square corner in a row of a rendered - * block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.SquareCorner'); @@ -22,14 +16,11 @@ import {Types} from './types.js'; /** * An object containing information about the space a square corner takes up * during rendering. - * - * @alias Blockly.blockRendering.SquareCorner */ export class SquareCorner extends Measurable { /** * @param constants The rendering constants provider. * @param opt_position The position of this corner. - * @internal */ constructor(constants: ConstantProvider, opt_position?: string) { super(constants); diff --git a/core/renderers/measurables/statement_input.ts b/core/renderers/measurables/statement_input.ts index 58bbbdabe..ac5a0bfb2 100644 --- a/core/renderers/measurables/statement_input.ts +++ b/core/renderers/measurables/statement_input.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Class representing statement inputs with connections on a - * rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.StatementInput'); @@ -24,14 +18,11 @@ import {Types} from './types.js'; /** * An object containing information about the space a statement input takes up * during rendering - * - * @alias Blockly.blockRendering.StatementInput */ export class StatementInput extends InputConnection { /** * @param constants The rendering constants provider. * @param input The statement input to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/measurables/top_row.ts b/core/renderers/measurables/top_row.ts index 8c7c7f084..d8ebf9b9f 100644 --- a/core/renderers/measurables/top_row.ts +++ b/core/renderers/measurables/top_row.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Object representing a top row on a rendered block. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.TopRow'); @@ -28,16 +23,12 @@ import {Types} from './types.js'; * connections. * After this constructor is called, the row will contain all non-spacer * elements it needs. - * - * @alias Blockly.blockRendering.TopRow */ export class TopRow extends Row { /** * The starting point for drawing the row, in the y direction. * This allows us to draw hats and similar shapes that don't start at the * origin. Must be non-negative (see #2820). - * - * @internal */ capline = 0; @@ -52,7 +43,6 @@ export class TopRow extends Row { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); @@ -65,7 +55,6 @@ export class TopRow extends Row { * * @param block The block whose top row this represents. * @returns Whether or not the top row has a left square corner. - * @internal */ hasLeftSquareCorner(block: BlockSvg): boolean { const hasHat = diff --git a/core/renderers/measurables/types.ts b/core/renderers/measurables/types.ts index d4be3297a..da3bcbeff 100644 --- a/core/renderers/measurables/types.ts +++ b/core/renderers/measurables/types.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Measurable types. - * - * @namespace Blockly.blockRendering.Types - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.blockRendering.Types'); @@ -18,8 +13,6 @@ import type {Row} from './row.js'; /** * Types of rendering elements. - * - * @alias Blockly.blockRendering.Types */ class TypesContainer { [index: string]: number|Function; @@ -52,15 +45,11 @@ class TypesContainer { /** * A Left Corner Union Type. - * - * @internal */ LEFT_CORNER = this.LEFT_SQUARE_CORNER | this.LEFT_ROUND_CORNER; /** * A Right Corner Union Type. - * - * @internal */ RIGHT_CORNER = this.RIGHT_SQUARE_CORNER | this.RIGHT_ROUND_CORNER; @@ -77,7 +66,6 @@ class TypesContainer { * * @param type The name of the type. * @returns The enum flag value associated with that type. - * @internal */ getType(type: string): number { if (!Object.prototype.hasOwnProperty.call(this, type)) { @@ -92,7 +80,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a field. - * @internal */ isField(elem: Measurable): number { return elem.type & this.FIELD; @@ -103,7 +90,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a hat. - * @internal */ isHat(elem: Measurable): number { return elem.type & this.HAT; @@ -114,7 +100,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about an icon. - * @internal */ isIcon(elem: Measurable): number { return elem.type & this.ICON; @@ -125,7 +110,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a spacer. - * @internal */ isSpacer(elem: Measurable|Row): number { return elem.type & this.SPACER; @@ -136,7 +120,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about an in-row spacer. - * @internal */ isInRowSpacer(elem: Measurable): number { return elem.type & this.IN_ROW_SPACER; @@ -147,7 +130,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about an input. - * @internal */ isInput(elem: Measurable): number { return elem.type & this.INPUT; @@ -158,7 +140,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about an external input. - * @internal */ isExternalInput(elem: Measurable): number { return elem.type & this.EXTERNAL_VALUE_INPUT; @@ -169,7 +150,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about an inline input. - * @internal */ isInlineInput(elem: Measurable): number { return elem.type & this.INLINE_INPUT; @@ -180,7 +160,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a statement input. - * @internal */ isStatementInput(elem: Measurable): number { return elem.type & this.STATEMENT_INPUT; @@ -191,7 +170,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a previous connection. - * @internal */ isPreviousConnection(elem: Measurable): number { return elem.type & this.PREVIOUS_CONNECTION; @@ -202,7 +180,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a next connection. - * @internal */ isNextConnection(elem: Measurable): number { return elem.type & this.NEXT_CONNECTION; @@ -215,7 +192,6 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a previous or next * connection. - * @internal */ isPreviousOrNextConnection(elem: Measurable): number { return elem.type & (this.PREVIOUS_CONNECTION | this.NEXT_CONNECTION); @@ -226,7 +202,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a left round corner. - * @internal */ isLeftRoundedCorner(elem: Measurable): number { return elem.type & this.LEFT_ROUND_CORNER; @@ -237,7 +212,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a right round corner. - * @internal */ isRightRoundedCorner(elem: Measurable): number { return elem.type & this.RIGHT_ROUND_CORNER; @@ -248,7 +222,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a left square corner. - * @internal */ isLeftSquareCorner(elem: Measurable): number { return elem.type & this.LEFT_SQUARE_CORNER; @@ -259,7 +232,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a right square corner. - * @internal */ isRightSquareCorner(elem: Measurable): number { return elem.type & this.RIGHT_SQUARE_CORNER; @@ -270,7 +242,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a corner. - * @internal */ isCorner(elem: Measurable): number { return elem.type & this.CORNER; @@ -281,7 +252,6 @@ class TypesContainer { * * @param elem The element to check. * @returns 1 if the object stores information about a jagged edge. - * @internal */ isJaggedEdge(elem: Measurable): number { return elem.type & this.JAGGED_EDGE; @@ -292,7 +262,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about a row. - * @internal */ isRow(row: Row): number { return row.type & this.ROW; @@ -303,7 +272,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about a between-row spacer. - * @internal */ isBetweenRowSpacer(row: Row): number { return row.type & this.BETWEEN_ROW_SPACER; @@ -314,7 +282,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about a top row. - * @internal */ isTopRow(row: Row): number { return row.type & this.TOP_ROW; @@ -325,7 +292,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about a bottom row. - * @internal */ isBottomRow(row: Row): number { return row.type & this.BOTTOM_ROW; @@ -336,7 +302,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about a top or bottom row. - * @internal */ isTopOrBottomRow(row: Row): number { return row.type & (this.TOP_ROW | this.BOTTOM_ROW); @@ -347,7 +312,6 @@ class TypesContainer { * * @param row The row to check. * @returns 1 if the object stores information about an input row. - * @internal */ isInputRow(row: Row): number { return row.type & this.INPUT_ROW; diff --git a/core/renderers/minimalist/constants.ts b/core/renderers/minimalist/constants.ts index f9dc23aee..9ca86e839 100644 --- a/core/renderers/minimalist/constants.ts +++ b/core/renderers/minimalist/constants.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that provides constants for rendering blocks in the - * minimalist renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.minimalist.ConstantProvider'); @@ -17,12 +11,10 @@ import {ConstantProvider as BaseConstantProvider} from '../common/constants.js'; /** - * An object that provides constants for rendering blocks in the sample. - * - * @alias Blockly.minimalist.ConstantProvider + * An object that provides constants for rendering blocks in the minimalist + * renderer. */ export class ConstantProvider extends BaseConstantProvider { - /** @internal */ constructor() { super(); } diff --git a/core/renderers/minimalist/drawer.ts b/core/renderers/minimalist/drawer.ts index 1027a8d9d..a6325d351 100644 --- a/core/renderers/minimalist/drawer.ts +++ b/core/renderers/minimalist/drawer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Minimalist rendering drawer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.minimalist.Drawer'); @@ -20,15 +15,12 @@ import type {RenderInfo} from './info.js'; /** * An object that draws a block based on the given rendering information. - * - * @alias Blockly.minimalist.Drawer */ export class Drawer extends BaseDrawer { /** * @param block The block to render. * @param info An object containing all information needed to render this * block. - * @internal */ constructor(block: BlockSvg, info: RenderInfo) { super(block, info); diff --git a/core/renderers/minimalist/info.ts b/core/renderers/minimalist/info.ts index aa31270eb..887820dfe 100644 --- a/core/renderers/minimalist/info.ts +++ b/core/renderers/minimalist/info.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Minimalist render info object. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.minimalist.RenderInfo'); @@ -24,8 +19,6 @@ import type {Renderer} from './renderer.js'; * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @alias Blockly.minimalist.RenderInfo */ export class RenderInfo extends BaseRenderInfo { // Exclamation is fine b/c this is assigned by the super constructor. @@ -34,7 +27,6 @@ export class RenderInfo extends BaseRenderInfo { /** * @param renderer The renderer in use. * @param block The block to measure. - * @internal */ constructor(renderer: Renderer, block: BlockSvg) { super(renderer, block); @@ -44,7 +36,6 @@ export class RenderInfo extends BaseRenderInfo { * Get the block renderer in use. * * @returns The block renderer in use. - * @internal */ override getRenderer(): Renderer { return this.renderer_; diff --git a/core/renderers/minimalist/minimalist.ts b/core/renderers/minimalist/minimalist.ts index 433104b3d..807fe2a86 100644 --- a/core/renderers/minimalist/minimalist.ts +++ b/core/renderers/minimalist/minimalist.ts @@ -6,11 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Re-exports of Blockly.minimalist.* modules. - * - * @namespace Blockly.minimalist - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.minimalist'); diff --git a/core/renderers/minimalist/renderer.ts b/core/renderers/minimalist/renderer.ts index 2a4a509ee..86f1c78d4 100644 --- a/core/renderers/minimalist/renderer.ts +++ b/core/renderers/minimalist/renderer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Minimalist renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.minimalist.Renderer'); @@ -24,13 +19,10 @@ import {RenderInfo} from './info.js'; /** * The minimalist renderer. - * - * @alias Blockly.minimalist.Renderer */ export class Renderer extends BaseRenderer { /** * @param name The renderer name. - * @internal */ constructor(name: string) { super(name); diff --git a/core/renderers/thrasos/info.ts b/core/renderers/thrasos/info.ts index abedc8793..26f899c4c 100644 --- a/core/renderers/thrasos/info.ts +++ b/core/renderers/thrasos/info.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * New (evolving) renderer. - * Thrasos: spirit of boldness. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.thrasos.RenderInfo'); @@ -32,8 +26,6 @@ import type {Renderer} from './renderer.js'; * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @alias Blockly.thrasos.RenderInfo */ export class RenderInfo extends BaseRenderInfo { // Exclamation is fine b/c this is assigned by the super constructor. @@ -42,7 +34,6 @@ export class RenderInfo extends BaseRenderInfo { /** * @param renderer The renderer in use. * @param block The block to measure. - * @internal */ constructor(renderer: Renderer, block: BlockSvg) { super(renderer, block); @@ -52,7 +43,6 @@ export class RenderInfo extends BaseRenderInfo { * Get the block renderer in use. * * @returns The block renderer in use. - * @internal */ override getRenderer(): Renderer { return this.renderer_; diff --git a/core/renderers/thrasos/renderer.ts b/core/renderers/thrasos/renderer.ts index 88d6732a4..65be1d206 100644 --- a/core/renderers/thrasos/renderer.ts +++ b/core/renderers/thrasos/renderer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Thrasos renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.thrasos.Renderer'); @@ -20,14 +15,14 @@ import {RenderInfo} from './info.js'; /** - * The thrasos renderer. + * The thrasos renderer. This is a more modern take on the legacy geras + * renderer. * - * @alias Blockly.thrasos.Renderer + * Thrasos is the ancient Greek spirit of boldness. */ export class Renderer extends BaseRenderer { /** * @param name The renderer name. - * @internal */ constructor(name: string) { super(name); diff --git a/core/renderers/thrasos/thrasos.ts b/core/renderers/thrasos/thrasos.ts index 0854ca5ab..5b2b419f5 100644 --- a/core/renderers/thrasos/thrasos.ts +++ b/core/renderers/thrasos/thrasos.ts @@ -6,11 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Re-exports of Blockly.thrasos.* modules. - * - * @namespace Blockly.thrasos - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.thrasos'); diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index 4d7832aac..73ee82e61 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that provides constants for rendering blocks in Zelos - * mode. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.ConstantProvider'); @@ -38,8 +32,6 @@ export interface InsideCorners { /** * An object that provides constants for rendering blocks in Zelos mode. - * - * @alias Blockly.zelos.ConstantProvider */ export class ConstantProvider extends BaseConstantProvider { GRID_UNIT = 4; @@ -49,8 +41,6 @@ export class ConstantProvider extends BaseConstantProvider { /** * Radius of the cursor for input and output connections. - * - * @internal */ CURSOR_RADIUS = 5; @@ -69,8 +59,6 @@ export class ConstantProvider extends BaseConstantProvider { * When a block with the outer shape contains an input block with the inner * shape on its left or right edge, the block elements are aligned such that * the padding specified is reached. - * - * @internal */ SHAPE_IN_SHAPE_PADDING: {[key: number]: {[key: number]: number}} = { 1: { @@ -128,8 +116,6 @@ export class ConstantProvider extends BaseConstantProvider { /** * The ID of the selected glow filter, or the empty string if no filter is * set. - * - * @internal */ selectedGlowFilterId = ''; @@ -141,8 +127,6 @@ export class ConstantProvider extends BaseConstantProvider { /** * The ID of the replacement glow filter, or the empty string if no filter * is set. - * - * @internal */ replacementGlowFilterId = ''; @@ -169,7 +153,6 @@ export class ConstantProvider extends BaseConstantProvider { */ SQUARED: Shape|null = null; - /** @internal */ constructor() { super(); @@ -312,9 +295,8 @@ export class ConstantProvider extends BaseConstantProvider { * * @returns An object containing sizing and path information about a hexagonal * shape for connections. - * @internal */ - makeHexagonal(): Shape { + protected makeHexagonal(): Shape { const maxWidth = this.MAX_DYNAMIC_CONNECTION_SHAPE_WIDTH; /** @@ -376,9 +358,8 @@ export class ConstantProvider extends BaseConstantProvider { * * @returns An object containing sizing and path information about a rounded * shape for connections. - * @internal */ - makeRounded(): Shape { + protected makeRounded(): Shape { const maxWidth = this.MAX_DYNAMIC_CONNECTION_SHAPE_WIDTH; const maxHeight = maxWidth * 2; @@ -449,9 +430,8 @@ export class ConstantProvider extends BaseConstantProvider { * * @returns An object containing sizing and path information about a squared * shape for connections. - * @internal */ - makeSquared(): Shape { + protected makeSquared(): Shape { const radius = this.CORNER_RADIUS; /** diff --git a/core/renderers/zelos/drawer.ts b/core/renderers/zelos/drawer.ts index f081166b1..931afc5d2 100644 --- a/core/renderers/zelos/drawer.ts +++ b/core/renderers/zelos/drawer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Zelos renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.Drawer'); @@ -30,8 +25,6 @@ import type {PathObject} from './path_object.js'; /** * An object that draws a block based on the given rendering information. - * - * @alias Blockly.zelos.Drawer */ export class Drawer extends BaseDrawer { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -41,7 +34,6 @@ export class Drawer extends BaseDrawer { * @param block The block to render. * @param info An object containing all information needed to render this * block. - * @internal */ constructor(block: BlockSvg, info: RenderInfo) { super(block, info); diff --git a/core/renderers/zelos/info.ts b/core/renderers/zelos/info.ts index 9071bb8da..30f179cba 100644 --- a/core/renderers/zelos/info.ts +++ b/core/renderers/zelos/info.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Makecode/scratch-style renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.RenderInfo'); @@ -42,8 +37,6 @@ import type {Renderer} from './renderer.js'; * This measure pass does not propagate changes to the block (although fields * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. - * - * @alias Blockly.zelos.RenderInfo */ export class RenderInfo extends BaseRenderInfo { override topRow: TopRow; @@ -60,7 +53,6 @@ export class RenderInfo extends BaseRenderInfo { /** * @param renderer The renderer in use. * @param block The block to measure. - * @internal */ constructor(renderer: Renderer, block: BlockSvg) { super(renderer, block); @@ -108,7 +100,6 @@ export class RenderInfo extends BaseRenderInfo { * Get the block renderer in use. * * @returns The block renderer in use. - * @internal */ override getRenderer(): Renderer { return this.renderer_ as Renderer; diff --git a/core/renderers/zelos/marker_svg.ts b/core/renderers/zelos/marker_svg.ts index 4227c3a9e..7e8ce2522 100644 --- a/core/renderers/zelos/marker_svg.ts +++ b/core/renderers/zelos/marker_svg.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for graphically rendering a marker as SVG. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.MarkerSvg'); @@ -27,8 +22,6 @@ import type {ConstantProvider as ZelosConstantProvider} from './constants.js'; /** * Class to draw a marker. - * - * @alias Blockly.zelos.MarkerSvg */ export class MarkerSvg extends BaseMarkerSvg { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -94,8 +87,8 @@ export class MarkerSvg extends BaseMarkerSvg { * @param y The y position of the circle. */ private positionCircle_(x: number, y: number) { - this.markerCircle_?.setAttribute('cx', x.toString()); - this.markerCircle_?.setAttribute('cy', y.toString()); + this.markerCircle_?.setAttribute('cx', `${x}`); + this.markerCircle_?.setAttribute('cy', `${y}`); this.currentMarkerSvg = this.markerCircle_; } diff --git a/core/renderers/zelos/measurables/bottom_row.ts b/core/renderers/zelos/measurables/bottom_row.ts index f4acded33..429f120ac 100644 --- a/core/renderers/zelos/measurables/bottom_row.ts +++ b/core/renderers/zelos/measurables/bottom_row.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object representing the bottom row of a rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.BottomRow'); @@ -22,13 +17,10 @@ import {BottomRow as BaseBottomRow} from '../../../renderers/measurables/bottom_ * a block as well as spacing information for the top row. * Elements in a bottom row can consist of corners, spacers and next * connections. - * - * @alias Blockly.zelos.BottomRow */ export class BottomRow extends BaseBottomRow { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/zelos/measurables/inputs.ts b/core/renderers/zelos/measurables/inputs.ts index b0e629dbe..4699bdd64 100644 --- a/core/renderers/zelos/measurables/inputs.ts +++ b/core/renderers/zelos/measurables/inputs.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Zelos specific objects representing inputs with connections on - * a rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.StatementInput'); @@ -22,8 +16,6 @@ import {StatementInput as BaseStatementInput} from '../../../renderers/measurabl /** * An object containing information about the space a statement input takes up * during rendering. - * - * @alias Blockly.zelos.StatementInput */ export class StatementInput extends BaseStatementInput { connectedBottomNextConnection = false; @@ -31,7 +23,6 @@ export class StatementInput extends BaseStatementInput { /** * @param constants The rendering constants provider. * @param input The statement input to measure and store information for. - * @internal */ constructor(constants: ConstantProvider, input: Input) { super(constants, input); diff --git a/core/renderers/zelos/measurables/row_elements.ts b/core/renderers/zelos/measurables/row_elements.ts index 0da74d4e5..db97735fc 100644 --- a/core/renderers/zelos/measurables/row_elements.ts +++ b/core/renderers/zelos/measurables/row_elements.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Zelos specific objects representing elements in a row of a - * rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.RightConnectionShape'); @@ -21,8 +15,6 @@ import {Types} from '../../../renderers/measurables/types.js'; /** * An object containing information about the space a right connection shape * takes up during rendering. - * - * @alias Blockly.zelos.RightConnectionShape */ export class RightConnectionShape extends Measurable { // Size is dynamic @@ -31,7 +23,6 @@ export class RightConnectionShape extends Measurable { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/zelos/measurables/top_row.ts b/core/renderers/zelos/measurables/top_row.ts index 9c3e207dc..531b10759 100644 --- a/core/renderers/zelos/measurables/top_row.ts +++ b/core/renderers/zelos/measurables/top_row.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object representing the top row of a rendered block. - * - * @class - */ import * as goog from '../../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.TopRow'); @@ -24,13 +19,10 @@ import {TopRow as BaseTopRow} from '../../../renderers/measurables/top_row.js'; * connections. * After this constructor is called, the row will contain all non-spacer * elements it needs. - * - * @alias Blockly.zelos.TopRow */ export class TopRow extends BaseTopRow { /** * @param constants The rendering constants provider. - * @internal */ constructor(constants: ConstantProvider) { super(constants); diff --git a/core/renderers/zelos/path_object.ts b/core/renderers/zelos/path_object.ts index fba99877a..ca99f4c77 100644 --- a/core/renderers/zelos/path_object.ts +++ b/core/renderers/zelos/path_object.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * An object that owns a block's rendering SVG elements. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.PathObject'); @@ -25,8 +20,6 @@ import type {ConstantProvider} from './constants.js'; /** * An object that handles creating and setting each of the SVG elements * used by the renderer. - * - * @alias Blockly.zelos.PathObject */ export class PathObject extends BasePathObject { /** The selected path of the block. */ @@ -49,14 +42,12 @@ export class PathObject extends BasePathObject { */ outputShapeType: number|null = null; - /** @internal */ public override constants: ConstantProvider; /** * @param root The root SVG element. * @param style The style object to use for colouring. * @param constants The renderer's constants. - * @internal */ constructor( root: SVGElement, style: BlockStyle, constants: ConstantProvider) { @@ -138,8 +129,6 @@ export class PathObject extends BasePathObject { /** * Method that's called when the drawer is about to draw the block. - * - * @internal */ beginDrawing() { this.remainingOutlines.clear(); @@ -150,8 +139,6 @@ export class PathObject extends BasePathObject { /** * Method that's called when the drawer is done drawing. - * - * @internal */ endDrawing() { // Go through all remaining outlines that were not used this draw pass, and @@ -170,7 +157,6 @@ export class PathObject extends BasePathObject { * * @param name The input name. * @param pathString The path. - * @internal */ setOutlinePath(name: string, pathString: string) { const outline = this.getOutlinePath_(name); diff --git a/core/renderers/zelos/renderer.ts b/core/renderers/zelos/renderer.ts index 6fa749104..cbef6c5a2 100644 --- a/core/renderers/zelos/renderer.ts +++ b/core/renderers/zelos/renderer.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Zelos renderer. - * - * @class - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos.Renderer'); @@ -32,16 +27,16 @@ import {PathObject} from './path_object.js'; /** - * The zelos renderer. + * The zelos renderer. This renderer emulates Scratch-style and MakeCode-style + * rendering. * - * @alias Blockly.zelos.Renderer + * Zelos is the ancient Greek spirit of rivalry and emulation. */ export class Renderer extends BaseRenderer { protected override constants_!: ConstantProvider; /** * @param name The renderer name. - * @internal */ constructor(name: string) { super(name); @@ -85,7 +80,6 @@ export class Renderer extends BaseRenderer { * @param workspace The workspace the cursor belongs to. * @param marker The marker. * @returns The object in charge of drawing the marker. - * @internal */ override makeMarkerDrawer(workspace: WorkspaceSvg, marker: Marker): MarkerSvg { @@ -98,7 +92,6 @@ export class Renderer extends BaseRenderer { * @param root The root SVG element. * @param style The style object to use for colouring. * @returns The renderer path object. - * @internal */ override makePathObject(root: SVGElement, style: BlockStyle): PathObject { return new PathObject( diff --git a/core/renderers/zelos/zelos.ts b/core/renderers/zelos/zelos.ts index fa402285b..edecc16f9 100644 --- a/core/renderers/zelos/zelos.ts +++ b/core/renderers/zelos/zelos.ts @@ -6,11 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Re-exports of Blockly.zelos.* modules. - * - * @namespace Blockly.zelos - */ import * as goog from '../../../closure/goog/goog.js'; goog.declareModuleId('Blockly.zelos'); diff --git a/core/scrollbar.ts b/core/scrollbar.ts index 652d5ae2d..f01bccf5f 100644 --- a/core/scrollbar.ts +++ b/core/scrollbar.ts @@ -31,8 +31,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * Class for a pure SVG scrollbar. * This technique offers a scrollbar that is guaranteed to work, but may not * look or behave like the system's scrollbars. - * - * @alias Blockly.Scrollbar */ export class Scrollbar { /** @@ -225,12 +223,12 @@ export class Scrollbar { this.svgBackground.setAttribute('height', String(scrollbarThickness)); this.outerSvg.setAttribute('height', String(scrollbarThickness)); this.svgHandle.setAttribute('height', String(scrollbarThickness - 5)); - this.svgHandle.setAttribute('y', String(2.5)); + this.svgHandle.setAttribute('y', '2.5'); } else { this.svgBackground.setAttribute('width', String(scrollbarThickness)); this.outerSvg.setAttribute('width', String(scrollbarThickness)); this.svgHandle.setAttribute('width', String(scrollbarThickness - 5)); - this.svgHandle.setAttribute('x', String(2.5)); + this.svgHandle.setAttribute('x', '2.5'); } } diff --git a/core/scrollbar_pair.ts b/core/scrollbar_pair.ts index 6c29a9648..35e3a0cd3 100644 --- a/core/scrollbar_pair.ts +++ b/core/scrollbar_pair.ts @@ -22,8 +22,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a pair of scrollbars. Horizontal and vertical. - * - * @alias Blockly.ScrollbarPair */ export class ScrollbarPair { hScroll: Scrollbar|null = null; diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index 5c55f04ab..e9bb0bd0c 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Handles serializing blocks to plain JavaScript objects only containing state. - * - * @namespace Blockly.serialization.blocks - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.serialization.blocks'); @@ -19,6 +14,7 @@ import * as eventUtils from '../events/utils.js'; import {inputTypes} from '../input_types.js'; import type {ISerializer} from '../interfaces/i_serializer.js'; import {Size} from '../utils/size.js'; +import * as utilsXml from '../utils/xml.js'; import type {Workspace} from '../workspace.js'; import * as Xml from '../xml.js'; @@ -32,8 +28,6 @@ import * as serializationRegistry from './registry.js'; /** * Represents the state of a connection. - * - * @alias Blockly.serialization.blocks.ConnectionState */ export interface ConnectionState { shadow: State|undefined; @@ -42,8 +36,6 @@ export interface ConnectionState { /** * Represents the state of a given block. - * - * @alias Blockly.serialization.blocks.State */ export interface State { type: string; @@ -51,6 +43,9 @@ export interface State { x?: number; y?: number; collapsed?: boolean; + deletable?: boolean; + movable?: boolean; + editable?: boolean; enabled?: boolean; inline?: boolean; data?: string; @@ -77,7 +72,6 @@ export interface State { * exist. True by default. * @returns The serialized state of the block, or null if the block could not be * serialied (eg it was an insertion marker). - * @alias Blockly.serialization.blocks.save */ export function save(block: Block, { addCoordinates = false, @@ -146,6 +140,15 @@ function saveAttributes(block: Block, state: State) { if (!block.isEnabled()) { state['enabled'] = false; } + if (!block.isOwnDeletable()) { + state['deletable'] = false; + } + if (!block.isOwnMovable()) { + state['movable'] = false; + } + if (!block.isOwnEditable()) { + state['editable'] = false; + } if (block.inputsInline !== undefined && block.inputsInline !== block.inputsInlineDefault) { state['inline'] = block.inputsInline; @@ -317,7 +320,6 @@ function saveConnection(connection: Connection, doFullSerialization: boolean): * @param param1 recordUndo: If true, events triggered by this function will be * undo-able by the user. False by default. * @returns The block that was just loaded. - * @alias Blockly.serialization.blocks.append */ export function append( state: State, workspace: Workspace, @@ -340,7 +342,6 @@ export function append( * it is created. False by default. recordUndo: If true, events triggered by * this function will be undo-able by the user. False by default. * @returns The block that was just appended. - * @alias Blockly.serialization.blocks.appendInternal * @internal */ export function appendInternal( @@ -443,6 +444,15 @@ function loadAttributes(block: Block, state: State) { if (state['collapsed']) { block.setCollapsed(true); } + if (state['deletable'] === false) { + block.setDeletable(false); + } + if (state['movable'] === false) { + block.setMovable(false); + } + if (state['editable'] === false) { + block.setEditable(false); + } if (state['enabled'] === false) { block.setEnabled(false); } @@ -468,7 +478,7 @@ function loadExtraState(block: Block, state: State) { if (block.loadExtraState) { block.loadExtraState(state['extraState']); } else if (block.domToMutation) { - block.domToMutation(Xml.textToDom(state['extraState'])); + block.domToMutation(utilsXml.textToDom(state['extraState'])); } } @@ -662,8 +672,6 @@ const saveBlock = save; /** * Serializer for saving and loading block state. - * - * @alias Blockly.serialization.blocks.BlockSerializer */ export class BlockSerializer implements ISerializer { priority: number; diff --git a/core/serialization/exceptions.ts b/core/serialization/exceptions.ts index 440769450..ff720f1bd 100644 --- a/core/serialization/exceptions.ts +++ b/core/serialization/exceptions.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Contains custom errors thrown by the serialization system. - * - * @namespace Blockly.serialization.exceptions - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.serialization.exceptions'); @@ -16,14 +11,12 @@ import type {Block} from '../block.js'; import type {State} from './blocks.js'; -/** @alias Blockly.serialization.exceptions.DeserializationError */ export class DeserializationError extends Error {} /** * Represents an error where the serialized state is expected to provide a * block type, but it is not provided. * - * @alias Blockly.serialization.exceptions.MissingBlockType */ export class MissingBlockType extends DeserializationError { /** @@ -38,8 +31,6 @@ export class MissingBlockType extends DeserializationError { /** * Represents an error where deserialization encountered a block that did * not have a connection that was defined in the serialized state. - * - * @alias Blockly.serialization.exceptions.MissingConnection */ export class MissingConnection extends DeserializationError { /** @@ -58,8 +49,6 @@ connection`); /** * Represents an error where deserialization tried to connect two connections * that were not compatible. - * - * @alias Blockly.serialization.exceptions.BadConnectionCheck */ export class BadConnectionCheck extends DeserializationError { /** @@ -83,8 +72,6 @@ ${childConnection} to its parent, because: ${reason}`); * was deserializing children of a shadow. * This is an error because it is an invariant of Blockly that shadow blocks * do not have real children. - * - * @alias Blockly.serialization.exceptions.RealChildOfShadow */ export class RealChildOfShadow extends DeserializationError { /** diff --git a/core/serialization/priorities.ts b/core/serialization/priorities.ts index b49c7222d..27eda2e8a 100644 --- a/core/serialization/priorities.ts +++ b/core/serialization/priorities.ts @@ -4,21 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * The top level namespace for priorities of plugin serializers. - * Includes constants for the priorities of different plugin serializers. Higher - * priorities are deserialized first. - * - * @namespace Blockly.serialization.priorities - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.serialization.priorities'); /** * The priority for deserializing variables. - * - * @alias Blockly.serialization.priorities.VARIABLES */ export const VARIABLES = 100; @@ -29,7 +20,5 @@ export const PROCEDURES = 75; /** * The priority for deserializing blocks. - * - * @alias Blockly.serialization.priorities.BLOCKS */ export const BLOCKS = 50; diff --git a/core/serialization/procedures.ts b/core/serialization/procedures.ts index 05f70b03b..06ec428df 100644 --- a/core/serialization/procedures.ts +++ b/core/serialization/procedures.ts @@ -7,10 +7,7 @@ import {IParameterModel} from '../interfaces/i_parameter_model.js'; import {IProcedureModel} from '../interfaces/i_procedure_model.js'; import type {ISerializer} from '../interfaces/i_serializer.js'; -import {ObservableProcedureModel} from '../procedures/observable_procedure_model.js'; -import {ObservableParameterModel} from '../procedures/observable_parameter_model.js'; import * as priorities from './priorities.js'; -// import * as serializationRegistry from './registry.js'; import type {Workspace} from '../workspace.js'; @@ -141,8 +138,9 @@ export class ProcedureSerializer saveProcedure(proc)); + return save.length ? save : null; } /** @@ -163,12 +161,3 @@ export class ProcedureSerializer(); - owner_: AnyDuringMigration; /** * @param workspace The main workspace. @@ -83,9 +80,7 @@ export class ThemeManager { const element = component.element; const propertyName = component.propertyName; const style = this.theme && this.theme.getComponentStyle(key); - // AnyDuringMigration because: Property 'style' does not exist on type - // 'Element'. - (element as AnyDuringMigration).style[propertyName] = style || ''; + element.style.setProperty(propertyName, style || ''); } } @@ -128,7 +123,9 @@ export class ThemeManager { * @param propertyName The inline style property name to update. * @internal */ - subscribe(element: Element, componentName: string, propertyName: string) { + subscribe( + element: HTMLElement|SVGElement, componentName: string, + propertyName: string) { if (!this.componentDB.has(componentName)) { this.componentDB.set(componentName, []); } @@ -138,9 +135,7 @@ export class ThemeManager { // Initialize the element with its corresponding theme style. const style = this.theme && this.theme.getComponentStyle(componentName); - // AnyDuringMigration because: Property 'style' does not exist on type - // 'Element'. - (element as AnyDuringMigration).style[propertyName] = style || ''; + element.style.setProperty(propertyName, style || ''); } /** @@ -149,7 +144,7 @@ export class ThemeManager { * @param element The element to unsubscribe. * @internal */ - unsubscribe(element: Element) { + unsubscribe(element: HTMLElement|SVGElement) { if (!element) { return; } @@ -174,13 +169,7 @@ export class ThemeManager { * @internal */ dispose() { - this.owner_ = null; - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Theme'. - this.theme = null as AnyDuringMigration; - // AnyDuringMigration because: Type 'null' is not assignable to type - // 'Workspace[]'. - this.subscribedWorkspaces_ = null as AnyDuringMigration; + this.subscribedWorkspaces_.length = 0; this.componentDB.clear(); } } @@ -188,7 +177,7 @@ export class ThemeManager { export namespace ThemeManager { /** The type for a Blockly UI Component. */ export interface Component { - element: Element; + element: HTMLElement|SVGElement; propertyName: string; } } diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index 9a2c125f6..16f814f26 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -30,8 +30,6 @@ import {ToolboxItem} from './toolbox_item.js'; /** * Class for a category in a toolbox. - * - * @alias Blockly.ToolboxCategory */ export class ToolboxCategory extends ToolboxItem implements ISelectableToolboxItem { @@ -59,19 +57,19 @@ export class ToolboxCategory extends ToolboxItem implements /** The colour of the category. */ protected colour_ = ''; - /** The html container for the category. */ + /** The HTML container for the category. */ protected htmlDiv_: HTMLDivElement|null = null; - /** The html element for the category row. */ + /** The HTML element for the category row. */ protected rowDiv_: HTMLDivElement|null = null; - /** The html element that holds children elements of the category row. */ + /** The HTML element that holds children elements of the category row. */ protected rowContents_: HTMLDivElement|null = null; - /** The html element for the toolbox icon. */ + /** The HTML element for the toolbox icon. */ protected iconDom_: Element|null = null; - /** The html element for the toolbox label. */ + /** The HTML element for the toolbox label. */ protected labelDom_: Element|null = null; protected cssConfig_: CssConfig; diff --git a/core/toolbox/collapsible_category.ts b/core/toolbox/collapsible_category.ts index 1c6ff27fd..0cb3df7b4 100644 --- a/core/toolbox/collapsible_category.ts +++ b/core/toolbox/collapsible_category.ts @@ -26,8 +26,6 @@ import {ToolboxSeparator} from './separator.js'; /** * Class for a category in a toolbox that can be collapsed. - * - * @alias Blockly.CollapsibleToolboxCategory */ export class CollapsibleToolboxCategory extends ToolboxCategory implements ICollapsibleToolboxItem { @@ -42,8 +40,6 @@ export class CollapsibleToolboxCategory extends ToolboxCategory implements /** The child toolbox items for this category. */ protected toolboxItems_: IToolboxItem[] = []; - override flyoutItems_: AnyDuringMigration; - override isHidden_: AnyDuringMigration; /** * @param categoryDef The information needed to create a category in the @@ -60,25 +56,18 @@ export class CollapsibleToolboxCategory extends ToolboxCategory implements override makeDefaultCssConfig_() { const cssConfig = super.makeDefaultCssConfig_(); - (cssConfig as AnyDuringMigration)['contents'] = 'blocklyToolboxContents'; + cssConfig['contents'] = 'blocklyToolboxContents'; return cssConfig; } override parseContents_(categoryDef: toolbox.CategoryInfo) { - // AnyDuringMigration because: Element implicitly has an 'any' type because - // expression of type '"contents"' can't be used to index type - // 'CategoryInfo'. - const contents = (categoryDef as AnyDuringMigration)['contents']; - let prevIsFlyoutItem = true; - - // AnyDuringMigration because: Element implicitly has an 'any' type because - // expression of type '"custom"' can't be used to index type 'CategoryInfo'. - if ((categoryDef as AnyDuringMigration)['custom']) { - // AnyDuringMigration because: Element implicitly has an 'any' type - // because expression of type '"custom"' can't be used to index type - // 'CategoryInfo'. - this.flyoutItems_ = (categoryDef as AnyDuringMigration)['custom']; - } else if (contents) { + if ('custom' in categoryDef) { + this.flyoutItems_ = categoryDef['custom']; + } else { + const contents = categoryDef['contents']; + if (!contents) return; + this.flyoutItems_ = []; + let prevIsFlyoutItem = true; for (let i = 0; i < contents.length; i++) { const itemDef = contents[i]; // Separators can exist as either a flyout item or a toolbox item so @@ -123,8 +112,8 @@ export class CollapsibleToolboxCategory extends ToolboxCategory implements super.init(); this.setExpanded( - (this.toolboxItemDef_ as AnyDuringMigration)['expanded'] === 'true' || - (this.toolboxItemDef_ as AnyDuringMigration)['expanded']); + this.toolboxItemDef_['expanded'] === 'true' || + !!this.toolboxItemDef_['expanded']); } override createDom_() { @@ -141,7 +130,7 @@ export class CollapsibleToolboxCategory extends ToolboxCategory implements override createIconDom_() { const toolboxIcon = document.createElement('span'); if (!this.parentToolbox_.isHorizontal()) { - const className = (this.cssConfig_ as AnyDuringMigration)['icon']; + const className = this.cssConfig_['icon']; if (className) { dom.addClass(toolboxIcon, className); } @@ -161,7 +150,7 @@ export class CollapsibleToolboxCategory extends ToolboxCategory implements protected createSubCategoriesDom_(subcategories: IToolboxItem[]): HTMLDivElement { const contentsContainer = document.createElement('div'); - const className = (this.cssConfig_ as AnyDuringMigration)['contents']; + const className = this.cssConfig_['contents']; if (className) { dom.addClass(contentsContainer, className); } diff --git a/core/toolbox/separator.ts b/core/toolbox/separator.ts index 26fac7e32..41c600655 100644 --- a/core/toolbox/separator.ts +++ b/core/toolbox/separator.ts @@ -24,8 +24,6 @@ import {ToolboxItem} from './toolbox_item.js'; /** * Class for a toolbox separator. This is the thin visual line that appears on * the toolbox. This item is not interactable. - * - * @alias Blockly.ToolboxSeparator */ export class ToolboxSeparator extends ToolboxItem { /** Name used for registering a toolbox separator. */ diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index 9b700fcf7..469515639 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -29,6 +29,7 @@ import type {IDraggable} from '../interfaces/i_draggable.js'; import type {IFlyout} from '../interfaces/i_flyout.js'; import type {IKeyboardAccessible} from '../interfaces/i_keyboard_accessible.js'; import type {ISelectableToolboxItem} from '../interfaces/i_selectable_toolbox_item.js'; +import {isSelectableToolboxItem} from '../interfaces/i_selectable_toolbox_item.js'; import type {IStyleable} from '../interfaces/i_styleable.js'; import type {IToolbox} from '../interfaces/i_toolbox.js'; import type {IToolboxItem} from '../interfaces/i_toolbox_item.js'; @@ -38,7 +39,6 @@ import type {KeyboardShortcut} from '../shortcut_registry.js'; import * as Touch from '../touch.js'; import * as aria from '../utils/aria.js'; import * as dom from '../utils/dom.js'; -import {KeyCodes} from '../utils/keycodes.js'; import {Rect} from '../utils/rect.js'; import * as toolbox from '../utils/toolbox.js'; import type {WorkspaceSvg} from '../workspace_svg.js'; @@ -50,8 +50,6 @@ import {CollapsibleToolboxCategory} from './collapsible_category.js'; /** * Class for a Toolbox. * Creates the toolbox's DOM. - * - * @alias Blockly.Toolbox */ export class Toolbox extends DeleteArea implements IAutoHideable, IKeyboardAccessible, @@ -64,10 +62,10 @@ export class Toolbox extends DeleteArea implements IAutoHideable, protected toolboxDef_: toolbox.ToolboxInfo; private readonly horizontalLayout_: boolean; - /** The html container for the toolbox. */ + /** The HTML container for the toolbox. */ HtmlDiv: HTMLDivElement|null = null; - /** The html container for the contents of a toolbox. */ + /** The HTML container for the contents of a toolbox. */ protected contentsDiv_: HTMLDivElement|null = null; /** Whether the Toolbox is visible. */ @@ -100,7 +98,6 @@ export class Toolbox extends DeleteArea implements IAutoHideable, * Ex: [[node, name, func], [node, name, func]]. */ protected boundEvents_: browserEvents.Data[] = []; - override wouldDelete_: AnyDuringMigration; /** The workspace this toolbox is on. */ protected readonly workspace_: WorkspaceSvg; @@ -112,10 +109,9 @@ export class Toolbox extends DeleteArea implements IAutoHideable, this.workspace_ = workspace; /** The JSON describing the contents of this toolbox. */ - // AnyDuringMigration because: Type 'ToolboxInfo | { contents: never[]; }' - // is not assignable to type 'ToolboxInfo'. - this.toolboxDef_ = (workspace.options.languageTree || {'contents': []}) as - AnyDuringMigration; + this.toolboxDef_ = + (workspace.options.languageTree || + {contents: new Array()}); /** Whether the toolbox should be laid out horizontally. */ this.horizontalLayout_ = workspace.options.horizontalLayout; @@ -271,21 +267,21 @@ export class Toolbox extends DeleteArea implements IAutoHideable, */ protected onKeyDown_(e: KeyboardEvent) { let handled = false; - switch (e.keyCode) { - case KeyCodes.DOWN: + switch (e.key) { + case 'ArrowDown': handled = this.selectNext_(); break; - case KeyCodes.UP: + case 'ArrowUp': handled = this.selectPrevious_(); break; - case KeyCodes.LEFT: + case 'ArrowLeft': handled = this.selectParent_(); break; - case KeyCodes.RIGHT: + case 'ArrowRight': handled = this.selectChild_(); break; - case KeyCodes.ENTER: - case KeyCodes.SPACE: + case 'Enter': + case ' ': if (this.selectedItem_ && this.selectedItem_.isCollapsible()) { const collapsibleItem = this.selectedItem_ as ICollapsibleToolboxItem; collapsibleItem.toggleExpanded(); @@ -299,9 +295,8 @@ export class Toolbox extends DeleteArea implements IAutoHideable, if (!handled && this.selectedItem_) { // TODO(#6097): Figure out who implements onKeyDown and which interface it // should be part of. - const untypedItem = this.selectedItem_ as AnyDuringMigration; - if (untypedItem.onKeyDown) { - handled = untypedItem.onKeyDown(e); + if ((this.selectedItem_ as any).onKeyDown) { + handled = (this.selectedItem_ as any).onKeyDown(e); } } @@ -796,33 +791,20 @@ export class Toolbox extends DeleteArea implements IAutoHideable, setSelectedItem(newItem: IToolboxItem|null) { const oldItem = this.selectedItem_; - if (!newItem && !oldItem || newItem && !newItem.isSelectable()) { + if (!newItem && !oldItem || newItem && !isSelectableToolboxItem(newItem)) { return; } - newItem = newItem as ISelectableToolboxItem; - // AnyDuringMigration because: Argument of type 'IToolboxItem' is not - // assignable to parameter of type 'ISelectableToolboxItem'. - if (this.shouldDeselectItem_(oldItem, newItem as AnyDuringMigration) && - oldItem !== null) { + if (this.shouldDeselectItem_(oldItem, newItem) && oldItem !== null) { this.deselectItem_(oldItem); } - // AnyDuringMigration because: Argument of type 'IToolboxItem' is not - // assignable to parameter of type 'ISelectableToolboxItem'. - if (this.shouldSelectItem_(oldItem, newItem as AnyDuringMigration) && - newItem !== null) { - // AnyDuringMigration because: Argument of type 'IToolboxItem' is not - // assignable to parameter of type 'ISelectableToolboxItem'. - this.selectItem_(oldItem, newItem as AnyDuringMigration); + if (this.shouldSelectItem_(oldItem, newItem) && newItem !== null) { + this.selectItem_(oldItem, newItem); } - // AnyDuringMigration because: Argument of type 'IToolboxItem' is not - // assignable to parameter of type 'ISelectableToolboxItem'. - this.updateFlyout_(oldItem, newItem as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'IToolboxItem' is not - // assignable to parameter of type 'ISelectableToolboxItem'. - this.fireSelectEvent_(oldItem, newItem as AnyDuringMigration); + this.updateFlyout_(oldItem, newItem); + this.fireSelectEvent_(oldItem, newItem); } /** @@ -1044,11 +1026,10 @@ export class Toolbox extends DeleteArea implements IAutoHideable, this.boundEvents_ = []; this.contents_ = []; - // AnyDuringMigration because: Argument of type 'HTMLDivElement | null' is - // not assignable to parameter of type 'Element'. - this.workspace_.getThemeManager().unsubscribe( - this.HtmlDiv as AnyDuringMigration); - dom.removeNode(this.HtmlDiv); + if (this.HtmlDiv) { + this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv); + dom.removeNode(this.HtmlDiv); + } } } diff --git a/core/toolbox/toolbox_item.ts b/core/toolbox/toolbox_item.ts index 36e0e14ac..3fe7ffb5b 100644 --- a/core/toolbox/toolbox_item.ts +++ b/core/toolbox/toolbox_item.ts @@ -22,8 +22,6 @@ import type {WorkspaceSvg} from '../workspace_svg.js'; /** * Class for an item in the toolbox. - * - * @alias Blockly.ToolboxItem */ export class ToolboxItem implements IToolboxItem { protected id_: string; diff --git a/core/tooltip.ts b/core/tooltip.ts index cdd5bde0d..1eb608a83 100644 --- a/core/tooltip.ts +++ b/core/tooltip.ts @@ -4,16 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Library to create tooltips for Blockly. - * First, call createDom() after onload. - * Second, set the 'tooltip' property on any SVG element that needs a tooltip. - * If the tooltip is a string, or a function that returns a string, that message - * will be displayed. If the tooltip is an SVG element, then that object's - * tooltip will be used. Third, call bindMouseEvents(e) passing the SVG element. - * - * @namespace Blockly.Tooltip - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Tooltip'); @@ -27,8 +17,6 @@ import * as blocklyString from './utils/string.js'; * Either a string, an object containing a tooltip property, or a function which * returns either a string, or another arbitrarily nested function which * eventually unwinds to a string. - * - * @alias Blockly.Tooltip.TipInfo */ export type TipInfo = string|{tooltip: AnyDuringMigration}|(() => TipInfo|string|Function); @@ -38,8 +26,6 @@ export type TipInfo = * 1st parameter: the div element to render content into. * 2nd parameter: the element being moused over (i.e., the element for which the * tooltip should be shown). - * - * @alias Blockly.Tooltip.CustomTooltip */ export type CustomTooltip = (p1: Element, p2: Element) => AnyDuringMigration; @@ -55,7 +41,6 @@ let customTooltip: CustomTooltip|undefined = undefined; * tooltip UI. * * @param customFn A custom tooltip used to render an alternate tooltip UI. - * @alias Blockly.Tooltip.setCustomTooltip */ export function setCustomTooltip(customFn: CustomTooltip) { customTooltip = customFn; @@ -77,7 +62,6 @@ let visible = false; * Returns whether or not a tooltip is showing * * @returns True if a tooltip is showing - * @alias Blockly.Tooltip.isVisible */ export function isVisible(): boolean { return visible; @@ -88,8 +72,6 @@ let blocked = false; /** * Maximum width (in characters) of a tooltip. - * - * @alias Blockly.Tooltip.LIMIT */ export const LIMIT = 50; @@ -120,36 +102,26 @@ let poisonedElement: AnyDuringMigration = null; /** * Horizontal offset between mouse cursor and tooltip. - * - * @alias Blockly.Tooltip.OFFSET_X */ export const OFFSET_X = 0; /** * Vertical offset between mouse cursor and tooltip. - * - * @alias Blockly.Tooltip.OFFSET_Y */ export const OFFSET_Y = 10; /** * Radius mouse can move before killing tooltip. - * - * @alias Blockly.Tooltip.RADIUS_OK */ export const RADIUS_OK = 10; /** * Delay before tooltip appears. - * - * @alias Blockly.Tooltip.HOVER_MS */ export const HOVER_MS = 750; /** * Horizontal padding between tooltip and screen edge. - * - * @alias Blockly.Tooltip.MARGINS */ export const MARGINS = 5; @@ -160,7 +132,6 @@ let containerDiv: HTMLDivElement|null = null; * Returns the HTML tooltip container. * * @returns The HTML tooltip container. - * @alias Blockly.Tooltip.getDiv */ export function getDiv(): HTMLDivElement|null { return containerDiv; @@ -171,7 +142,6 @@ export function getDiv(): HTMLDivElement|null { * * @param object The object to get the tooltip text of. * @returns The tooltip text of the element. - * @alias Blockly.Tooltip.getTooltipOfObject */ export function getTooltipOfObject(object: AnyDuringMigration|null): string { const obj = getTargetObject(object); @@ -208,8 +178,6 @@ function getTargetObject(obj: object|null): {tooltip: AnyDuringMigration}|null { /** * Create the tooltip div and inject it onto the page. - * - * @alias Blockly.Tooltip.createDom */ export function createDom() { if (containerDiv) { @@ -226,7 +194,6 @@ export function createDom() { * Binds the required mouse events onto an SVG element. * * @param element SVG element onto which tooltip is to be bound. - * @alias Blockly.Tooltip.bindMouseEvents */ export function bindMouseEvents(element: Element) { // TODO (#6097): Don't stash wrapper info on the DOM. @@ -245,7 +212,6 @@ export function bindMouseEvents(element: Element) { * Unbinds tooltip mouse events from the SVG element. * * @param element SVG element onto which tooltip is bound. - * @alias Blockly.Tooltip.unbindMouseEvents */ export function unbindMouseEvents(element: Element|null) { if (!element) { @@ -300,6 +266,7 @@ function onMouseOut(_e: PointerEvent) { hide(); }, 1); clearTimeout(showPid); + showPid = 0; } /** @@ -346,7 +313,6 @@ function onMouseMove(e: Event) { /** * Dispose of the tooltip. * - * @alias Blockly.Tooltip.dispose * @internal */ export function dispose() { @@ -357,8 +323,6 @@ export function dispose() { /** * Hide the tooltip. - * - * @alias Blockly.Tooltip.hide */ export function hide() { if (visible) { @@ -369,6 +333,7 @@ export function hide() { } if (showPid) { clearTimeout(showPid); + showPid = 0; } } @@ -376,7 +341,6 @@ export function hide() { * Hide any in-progress tooltips and block showing new tooltips until the next * call to unblock(). * - * @alias Blockly.Tooltip.block * @internal */ export function block() { @@ -388,7 +352,6 @@ export function block() { * Unblock tooltips: allow them to be scheduled and shown according to their own * logic. * - * @alias Blockly.Tooltip.unblock * @internal */ export function unblock() { diff --git a/core/touch.ts b/core/touch.ts index 250b162a1..9de586c44 100644 --- a/core/touch.ts +++ b/core/touch.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Touch handling for Blockly. - * - * @namespace Blockly.Touch - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Touch'); @@ -50,8 +45,6 @@ let touchIdentifier_: string|null = null; /** * The TOUCH_MAP lookup dictionary specifies additional touch events to fire, * in conjunction with mouse events. - * - * @alias Blockly.Touch.TOUCH_MAP */ export const TOUCH_MAP: {[key: string]: string[]} = { 'mousedown': ['pointerdown'], @@ -77,7 +70,6 @@ let longPid_: AnyDuringMigration = 0; * * @param e Touch start event. * @param gesture The gesture that triggered this longStart. - * @alias Blockly.Touch.longStart * @internal */ export function longStart(e: PointerEvent, gesture: Gesture) { @@ -94,7 +86,6 @@ export function longStart(e: PointerEvent, gesture: Gesture) { * Nope, that's not a long-press. Either touchend or touchcancel was fired, * or a drag hath begun. Kill the queued long-press task. * - * @alias Blockly.Touch.longStop * @internal */ export function longStop() { @@ -108,8 +99,6 @@ export function longStop() { * Clear the touch identifier that tracks which touch stream to pay attention * to. This ends the current drag/gesture and allows other pointers to be * captured. - * - * @alias Blockly.Touch.clearTouchIdentifier */ export function clearTouchIdentifier() { touchIdentifier_ = null; @@ -123,7 +112,6 @@ export function clearTouchIdentifier() { * @param e The event to check. * @returns True if this event should be passed through to the registered * handler; false if it should be blocked. - * @alias Blockly.Touch.shouldHandleEvent */ export function shouldHandleEvent(e: Event): boolean { // Do not replace the startsWith with a check for `instanceof PointerEvent`. @@ -139,7 +127,6 @@ export function shouldHandleEvent(e: Event): boolean { * * @param e Pointer event. * @returns The pointerId of the event. - * @alias Blockly.Touch.getTouchIdentifierFromEvent */ export function getTouchIdentifierFromEvent(e: PointerEvent): string { return `${e.pointerId}`; @@ -154,7 +141,6 @@ export function getTouchIdentifierFromEvent(e: PointerEvent): string { * @param e Pointer event. * @returns Whether the identifier on the event matches the current saved * identifier. - * @alias Blockly.Touch.checkTouchIdentifier */ export function checkTouchIdentifier(e: PointerEvent): boolean { const identifier = getTouchIdentifierFromEvent(e); @@ -181,7 +167,6 @@ export function checkTouchIdentifier(e: PointerEvent): boolean { * make a touch event work in a mouse event handler. * * @param e A touch event. - * @alias Blockly.Touch.setClientFromTouch */ export function setClientFromTouch(e: Event|PseudoEvent) { deprecation.warn('setClientFromTouch()', 'version 9', 'version 10'); @@ -206,7 +191,6 @@ export function setClientFromTouch(e: Event|PseudoEvent) { * * @param e An event. * @returns True if it is a mouse, touch, or pointer event; false otherwise. - * @alias Blockly.Touch.isMouseOrTouchEvent */ export function isMouseOrTouchEvent(e: Event|PseudoEvent): boolean { deprecation.warn('isMouseOrTouchEvent()', 'version 9', 'version 10'); @@ -219,7 +203,6 @@ export function isMouseOrTouchEvent(e: Event|PseudoEvent): boolean { * * @param e An event. * @returns True if it is a touch or pointer event; false otherwise. - * @alias Blockly.Touch.isTouchEvent */ export function isTouchEvent(e: Event|PseudoEvent): boolean { deprecation.warn('isTouchEvent()', 'version 9', 'version 10'); @@ -234,7 +217,6 @@ export function isTouchEvent(e: Event|PseudoEvent): boolean { * @returns An array of events or pseudo events. * Each pseudo-touch event will have exactly one changed touch and there * will be no real touch events. - * @alias Blockly.Touch.splitEventByTouches */ export function splitEventByTouches(e: Event): Array { deprecation.warn('splitEventByTouches()', 'version 9', 'version 10'); diff --git a/core/trashcan.ts b/core/trashcan.ts index 04c1196e7..5d4d87f58 100644 --- a/core/trashcan.ts +++ b/core/trashcan.ts @@ -43,8 +43,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a trash can. - * - * @alias Blockly.Trashcan */ export class Trashcan extends DeleteArea implements IAutoHideable, IPositionable { @@ -449,7 +447,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, // Linear interpolation between min and max. const opacity = OPACITY_MIN + this.lidOpen_ * (OPACITY_MAX - OPACITY_MIN); if (this.svgGroup_) { - this.svgGroup_.style.opacity = opacity.toString(); + this.svgGroup_.style.opacity = `${opacity}`; } if (this.lidOpen_ > this.minOpenness_ && this.lidOpen_ < 1) { diff --git a/core/utils.ts b/core/utils.ts index 3891d0b21..cb03341f0 100644 --- a/core/utils.ts +++ b/core/utils.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods. - * - * @namespace Blockly.utils - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils'); @@ -75,7 +70,6 @@ export { * @param element SVG element to find the coordinates of. * @returns Object with .x and .y properties. * @deprecated Use **Blockly.utils.svgMath.getRelativeXY** instead. - * @alias Blockly.utils.getRelativeXY */ export function getRelativeXY(element: Element): Coordinate { deprecation.warn( @@ -92,7 +86,6 @@ export function getRelativeXY(element: Element): Coordinate { * of the div Blockly was injected into, the behaviour is undefined. * @returns Object with .x and .y properties. * @deprecated Use **Blockly.utils.svgMath.getInjectionDivXY** instead. - * @alias Blockly.utils.getInjectionDivXY_ */ function getInjectionDivXY(element: Element): Coordinate { deprecation.warn( @@ -113,7 +106,6 @@ export const getInjectionDivXY_ = getInjectionDivXY; * interpolation tokens. * @returns Array of strings and numbers. * @deprecated Use **Blockly.utils.parsing.tokenizeInterpolation** instead. - * @alias Blockly.utils.tokenizeInterpolation */ export function tokenizeInterpolation(message: string): Array { deprecation.warn( @@ -131,7 +123,6 @@ export function tokenizeInterpolation(message: string): Array { * references. * @returns String with message references replaced. * @deprecated Use **Blockly.utils.parsing.replaceMessageReferences** instead. - * @alias Blockly.utils.replaceMessageReferences */ export function replaceMessageReferences(message: string|any): string { deprecation.warn( @@ -148,7 +139,6 @@ export function replaceMessageReferences(message: string|any): string { * @returns True if all message references have matching values. * Otherwise, false. * @deprecated Use **Blockly.utils.parsing.checkMessageReferences** instead. - * @alias Blockly.utils.checkMessageReferences */ export function checkMessageReferences(message: string): boolean { deprecation.warn( @@ -163,7 +153,6 @@ export function checkMessageReferences(message: string): boolean { * * @returns True if 3D transforms are supported. * @deprecated Use **Blockly.utils.svgMath.is3dSupported** instead. - * @alias Blockly.utils.is3dSupported */ export function is3dSupported(): boolean { deprecation.warn( @@ -178,7 +167,6 @@ export function is3dSupported(): boolean { * * @returns An object containing window width, height, and scroll position in * window coordinates. - * @alias Blockly.utils.getViewportBBox * @deprecated Use **Blockly.utils.svgMath.getViewportBBox** instead. * @internal */ @@ -195,7 +183,6 @@ export function getViewportBBox(): Rect { * @param arr Array from which to remove value. * @param value Value to remove. * @returns True if an element was removed. - * @alias Blockly.utils.arrayRemove * @deprecated Use **Blockly.array.removeElem** instead. * @internal */ @@ -212,7 +199,6 @@ export function arrayRemove(arr: Array, value: T): boolean { * * @returns Object with values 'x' and 'y'. * @deprecated Use **Blockly.utils.svgMath.getDocumentScroll** instead. - * @alias Blockly.utils.getDocumentScroll */ export function getDocumentScroll(): Coordinate { deprecation.warn( @@ -230,7 +216,6 @@ export function getDocumentScroll(): Coordinate { * that are not inside a value or statement input of the block). * @returns Map of types to type counts for descendants of the bock. * @deprecated Use **Blockly.common.getBlockTypeCounts** instead. - * @alias Blockly.utils.getBlockTypeCounts */ export function getBlockTypeCounts( block: Block, opt_stripFollowing?: boolean): {[key: string]: number} { @@ -267,7 +252,6 @@ export function screenToWsCoordinates( * the input was an HSV hue value. * @throws {Error} If the colour cannot be parsed. * @deprecated Use **Blockly.utils.parsing.parseBlockColour** instead. - * @alias Blockly.utils.parseBlockColour */ export function parseBlockColour(colour: number| string): {hue: number|null, hex: string} { @@ -283,7 +267,6 @@ export function parseBlockColour(colour: number| * @param fn Function to run. * @throws Error Will throw if no global document can be found (e.g., Node.js). * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.runAfterPageLoad */ export function runAfterPageLoad(fn: () => void) { deprecation.warn( diff --git a/core/utils/aria.ts b/core/utils/aria.ts index fcacf4da7..e43190709 100644 --- a/core/utils/aria.ts +++ b/core/utils/aria.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * ARIA-related constants and utilities. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.aria - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.aria'); @@ -24,8 +17,6 @@ const ROLE_ATTRIBUTE = 'role'; /** * ARIA role values. * Copied from Closure's goog.a11y.aria.Role - * - * @alias Blockly.utils.aria.Role */ export enum Role { // ARIA role for an interactive control of tabular data. @@ -64,8 +55,6 @@ export enum Role { /** * ARIA states and properties. * Copied from Closure's goog.a11y.aria.State - * - * @alias Blockly.utils.aria.State */ export enum State { // ARIA property for setting the currently active descendant of an element, @@ -129,7 +118,6 @@ export enum State { * * @param element DOM node to set role of. * @param roleName Role name. - * @alias Blockly.utils.aria.setRole */ export function setRole(element: Element, roleName: Role) { element.setAttribute(ROLE_ATTRIBUTE, roleName); @@ -144,7 +132,6 @@ export function setRole(element: Element, roleName: Role) { * Automatically adds prefix 'aria-' to the state name if the attribute is * not an extra attribute. * @param value Value for the state attribute. - * @alias Blockly.utils.aria.setState */ export function setState( element: Element, stateName: State, value: string|boolean|number|string[]) { diff --git a/core/utils/array.ts b/core/utils/array.ts index 26cda7961..faee551e4 100644 --- a/core/utils/array.ts +++ b/core/utils/array.ts @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @namespace Blockly.utils.array */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.array'); @@ -15,7 +14,6 @@ goog.declareModuleId('Blockly.utils.array'); * @param arr Array from which to remove value. * @param value Value to remove. * @returns True if an element was removed. - * @alias Blockly.array.removeElem * @internal */ export function removeElem(arr: Array, value: T): boolean { diff --git a/core/utils/colour.ts b/core/utils/colour.ts index fad93adb8..0e9d91017 100644 --- a/core/utils/colour.ts +++ b/core/utils/colour.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods for colour manipulation. - * - * @namespace Blockly.utils.colour - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.colour'); @@ -16,15 +11,12 @@ goog.declareModuleId('Blockly.utils.colour'); /** * The richness of block colours, regardless of the hue. * Must be in the range of 0 (inclusive) to 1 (exclusive). - * - * @alias Blockly.utils.colour.hsvSaturation */ let hsvSaturation = 0.45; /** * Get the richness of block colours, regardless of the hue. * - * @alias Blockly.utils.colour.getHsvSaturation * @returns The current richness. * @internal */ @@ -37,7 +29,6 @@ export function getHsvSaturation(): number { * * @param newSaturation The new richness, in the range of 0 (inclusive) to 1 * (exclusive) - * @alias Blockly.utils.colour.setHsvSaturation * @internal */ export function setHsvSaturation(newSaturation: number) { @@ -47,15 +38,12 @@ export function setHsvSaturation(newSaturation: number) { /** * The intensity of block colours, regardless of the hue. * Must be in the range of 0 (inclusive) to 1 (exclusive). - * - * @alias Blockly.utils.colour.hsvValue */ let hsvValue = 0.65; /** * Get the intensity of block colours, regardless of the hue. * - * @alias Blockly.utils.colour.getHsvValue * @returns The current intensity. * @internal */ @@ -68,7 +56,6 @@ export function getHsvValue(): number { * * @param newValue The new intensity, in the range of 0 (inclusive) to 1 * (exclusive) - * @alias Blockly.utils.colour.setHsvValue * @internal */ export function setHsvValue(newValue: number) { @@ -86,10 +73,9 @@ export function setHsvValue(newValue: number) { * @param str Colour in some CSS format. * @returns A string containing a hex representation of the colour, or null if * can't be parsed. - * @alias Blockly.utils.colour.parse */ export function parse(str: string|number): string|null { - str = String(str).toLowerCase().trim(); + str = `${str}`.toLowerCase().trim(); let hex = names[str]; if (hex) { // e.g. 'red' @@ -125,7 +111,6 @@ export function parse(str: string|number): string|null { * @param g Amount of green, int between 0 and 255. * @param b Amount of blue, int between 0 and 255. * @returns Hex representation of the colour. - * @alias Blockly.utils.colour.rgbToHex */ export function rgbToHex(r: number, g: number, b: number): string { const rgb = r << 16 | g << 8 | b; @@ -141,7 +126,6 @@ export function rgbToHex(r: number, g: number, b: number): string { * @param colour String representing colour in any colour format ('#ff0000', * 'red', '0xff000', etc). * @returns RGB representation of the colour. - * @alias Blockly.utils.colour.hexToRgb */ export function hexToRgb(colour: string): number[] { const hex = parse(colour); @@ -164,7 +148,6 @@ export function hexToRgb(colour: string): number[] { * @param s Saturation value in [0, 1]. * @param v Brightness in [0, 255]. * @returns Hex representation of the colour. - * @alias Blockly.utils.colour.hsvToHex */ export function hsvToHex(h: number, s: number, v: number): string { let red = 0; @@ -226,7 +209,6 @@ export function hsvToHex(h: number, s: number, v: number): string { * @param factor The weight to be given to colour1 over colour2. * Values should be in the range [0, 1]. * @returns Combined colour represented in hex. - * @alias Blockly.utils.colour.blend */ export function blend(colour1: string, colour2: string, factor: number): string| null { @@ -251,8 +233,6 @@ export function blend(colour1: string, colour2: string, factor: number): string| * https://www.w3.org/TR/2018/REC-css-color-3-20180619/#html4 * The keys of this map are the lowercase "readable" names of the colours, * while the values are the "hex" values. - * - * @alias Blockly.utils.colour.names */ export const names: {[key: string]: string} = { 'aqua': '#00ffff', @@ -278,7 +258,6 @@ export const names: {[key: string]: string} = { * * @param hue Hue on a colour wheel (0-360). * @returns RGB code, e.g. '#5ba65b'. - * @alias Blockly.utils.colour.hueToHex */ export function hueToHex(hue: number): string { return hsvToHex(hue, hsvSaturation, hsvValue * 255); diff --git a/core/utils/coordinate.ts b/core/utils/coordinate.ts index 80ef56e00..12d422b70 100644 --- a/core/utils/coordinate.ts +++ b/core/utils/coordinate.ts @@ -17,8 +17,6 @@ goog.declareModuleId('Blockly.utils.Coordinate'); /** * Class for representing coordinates and positions. - * - * @alias Blockly.utils.Coordinate */ export class Coordinate { /** diff --git a/core/utils/deprecation.ts b/core/utils/deprecation.ts index af2800fb3..b09e5bc6a 100644 --- a/core/utils/deprecation.ts +++ b/core/utils/deprecation.ts @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Helper function for warning developers about deprecations. - * This method is not specific to Blockly. - * - * @namespace Blockly.utils.deprecation - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.deprecation'); @@ -23,7 +17,6 @@ goog.declareModuleId('Blockly.utils.deprecation'); * @param deletionDate The date of deletion. Prefer 'version n.0.0' * format, and fall back to 'month yyyy' or 'quarter yyyy' format. * @param opt_use The name of a function or property to use instead, if any. - * @alias Blockly.utils.deprecation.warn * @internal */ export function warn( diff --git a/core/utils/dom.ts b/core/utils/dom.ts index c8e799fe2..363000480 100644 --- a/core/utils/dom.ts +++ b/core/utils/dom.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods for DOM manipulation. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.dom - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.dom'); @@ -19,30 +12,22 @@ import type {Svg} from './svg.js'; /** * Required name space for SVG elements. - * - * @alias Blockly.utils.dom.SVG_NS */ export const SVG_NS = 'http://www.w3.org/2000/svg'; /** * Required name space for HTML elements. - * - * @alias Blockly.utils.dom.HTML_NS */ export const HTML_NS = 'http://www.w3.org/1999/xhtml'; /** * Required name space for XLINK elements. - * - * @alias Blockly.utils.dom.XLINK_NS */ export const XLINK_NS = 'http://www.w3.org/1999/xlink'; /** * Node type constants. * https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType - * - * @alias Blockly.utils.dom.NodeType */ export enum NodeType { ELEMENT_NODE = 1, @@ -67,12 +52,11 @@ let canvasContext: CanvasRenderingContext2D|null = null; * @param attrs Dictionary of attribute names and values. * @param opt_parent Optional parent on which to append the element. * @returns if name is a string or a more specific type if it a member of Svg. - * @alias Blockly.utils.dom.createSvgElement */ export function createSvgElement( name: string|Svg, attrs: {[key: string]: string|number}, opt_parent?: Element|null): T { - const e = document.createElementNS(SVG_NS, String(name)) as T; + const e = document.createElementNS(SVG_NS, `${name}`) as T; for (const key in attrs) { e.setAttribute(key, `${attrs[key]}`); } @@ -90,7 +74,6 @@ export function createSvgElement( * @param element DOM element to add class to. * @param className Name of class to add. * @returns True if class was added, false if already present. - * @alias Blockly.utils.dom.addClass */ export function addClass(element: Element, className: string): boolean { const classNames = className.split(' '); @@ -106,7 +89,6 @@ export function addClass(element: Element, className: string): boolean { * * @param element DOM element to remove classes from. * @param classNames A string of one or multiple class names for an element. - * @alias Blockly.utils.dom.removeClasses */ export function removeClasses(element: Element, classNames: string) { element.classList.remove(...classNames.split(' ')); @@ -120,7 +102,6 @@ export function removeClasses(element: Element, classNames: string) { * @param element DOM element to remove class from. * @param className Name of class to remove. * @returns True if class was removed, false if never present. - * @alias Blockly.utils.dom.removeClass */ export function removeClass(element: Element, className: string): boolean { const classNames = className.split(' '); @@ -137,7 +118,6 @@ export function removeClass(element: Element, className: string): boolean { * @param element DOM element to check. * @param className Name of class to check. * @returns True if class exists, false otherwise. - * @alias Blockly.utils.dom.hasClass */ export function hasClass(element: Element, className: string): boolean { return element.classList.contains(className); @@ -148,7 +128,6 @@ export function hasClass(element: Element, className: string): boolean { * * @param node The node to remove. * @returns The node removed if removed; else, null. - * @alias Blockly.utils.dom.removeNode */ // Copied from Closure goog.dom.removeNode export function removeNode(node: Node|null): Node|null { @@ -161,7 +140,6 @@ export function removeNode(node: Node|null): Node|null { * * @param newNode New element to insert. * @param refNode Existing element to precede new node. - * @alias Blockly.utils.dom.insertAfter */ export function insertAfter(newNode: Element, refNode: Element) { const siblingNode = refNode.nextSibling; @@ -182,7 +160,6 @@ export function insertAfter(newNode: Element, refNode: Element) { * @param parent The node that should contain the other node. * @param descendant The node to test presence of. * @returns Whether the parent node contains the descendant node. - * @alias Blockly.utils.dom.containsNode */ export function containsNode(parent: Node, descendant: Node): boolean { return !!( @@ -197,7 +174,6 @@ export function containsNode(parent: Node, descendant: Node): boolean { * * @param element Element to which the CSS transform will be applied. * @param transform The value of the CSS `transform` property. - * @alias Blockly.utils.dom.setCssTransform */ export function setCssTransform( element: HTMLElement|SVGElement, transform: string) { @@ -208,8 +184,6 @@ export function setCssTransform( /** * Start caching text widths. Every call to this function MUST also call * stopTextWidthCache. Caches must not survive between execution threads. - * - * @alias Blockly.utils.dom.startTextWidthCache */ export function startTextWidthCache() { cacheReference++; @@ -221,8 +195,6 @@ export function startTextWidthCache() { /** * Stop caching field widths. Unless caching was already on when the * corresponding call to startTextWidthCache was made. - * - * @alias Blockly.utils.dom.stopTextWidthCache */ export function stopTextWidthCache() { cacheReference--; @@ -236,7 +208,6 @@ export function stopTextWidthCache() { * * @param textElement An SVG 'text' element. * @returns Width of element. - * @alias Blockly.utils.dom.getTextWidth */ export function getTextWidth(textElement: SVGTextElement): number { const key = textElement.textContent + '\n' + textElement.className.baseVal; @@ -277,7 +248,6 @@ export function getTextWidth(textElement: SVGTextElement): number { * @param fontWeight The font weight to use. * @param fontFamily The font family to use. * @returns Width of element. - * @alias Blockly.utils.dom.getFastTextWidth */ export function getFastTextWidth( textElement: SVGTextElement, fontSize: number, fontWeight: string, @@ -298,7 +268,6 @@ export function getFastTextWidth( * @param fontWeight The font weight to use. * @param fontFamily The font family to use. * @returns Width of element. - * @alias Blockly.utils.dom.getFastTextWidthWithSizeString */ export function getFastTextWidthWithSizeString( textElement: SVGTextElement, fontSize: string, fontWeight: string, @@ -351,7 +320,6 @@ export function getFastTextWidthWithSizeString( * @param fontWeight The font weight to use. * @param fontFamily The font family to use. * @returns Font measurements. - * @alias Blockly.utils.dom.measureFontMetrics */ export function measureFontMetrics( text: string, fontSize: string, fontWeight: string, diff --git a/core/utils/idgenerator.ts b/core/utils/idgenerator.ts index e0b647df1..3f7d66f5a 100644 --- a/core/utils/idgenerator.ts +++ b/core/utils/idgenerator.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Generators for unique IDs. - * - * @namespace Blockly.utils.idGenerator - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.idGenerator'); @@ -59,7 +54,6 @@ let nextId = 0; * primarily be used for IDs that end up in the DOM. * * @returns The next unique identifier. - * @alias Blockly.utils.idGenerator.getNextUniqueId */ export function getNextUniqueId(): string { return 'blockly-' + (nextId++).toString(36); @@ -70,7 +64,6 @@ export function getNextUniqueId(): string { * * @see internal.genUid * @returns A globally unique ID string. - * @alias Blockly.utils.idGenerator.genUid */ export function genUid(): string { return internal.genUid(); diff --git a/core/utils/keycodes.ts b/core/utils/keycodes.ts index 49aa8f8d7..b6e4baf63 100644 --- a/core/utils/keycodes.ts +++ b/core/utils/keycodes.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Constant declarations for common key codes. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.KeyCodes - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.KeyCodes'); @@ -22,8 +15,6 @@ goog.declareModuleId('Blockly.utils.KeyCodes'); * * This list is not localized and therefore some of the key codes are not * correct for non US keyboard layouts. See comments below. - * - * @alias Blockly.utils.KeyCodes */ export enum KeyCodes { WIN_KEY_FF_LINUX = 0, diff --git a/core/utils/math.ts b/core/utils/math.ts index c92749aa5..1704c3ae3 100644 --- a/core/utils/math.ts +++ b/core/utils/math.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods for math. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.math - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.math'); @@ -21,7 +14,6 @@ goog.declareModuleId('Blockly.utils.math'); * * @param angleDegrees Angle in degrees. * @returns Angle in radians. - * @alias Blockly.utils.math.toRadians */ export function toRadians(angleDegrees: number): number { return angleDegrees * Math.PI / 180; @@ -33,7 +25,6 @@ export function toRadians(angleDegrees: number): number { * * @param angleRadians Angle in radians. * @returns Angle in degrees. - * @alias Blockly.utils.math.toDegrees */ export function toDegrees(angleRadians: number): number { return angleRadians * 180 / Math.PI; @@ -46,7 +37,6 @@ export function toDegrees(angleRadians: number): number { * @param number The number to clamp. * @param upperBound The desired upper bound. * @returns The clamped number. - * @alias Blockly.utils.math.clamp */ export function clamp( lowerBound: number, number: number, upperBound: number): number { diff --git a/core/utils/metrics.ts b/core/utils/metrics.ts index 495e017b8..d83e2b8a0 100644 --- a/core/utils/metrics.ts +++ b/core/utils/metrics.ts @@ -4,16 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Workspace metrics definitions. - * - * @namespace Blockly.utils.Metrics - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.Metrics'); -/** @alias Blockly.utils.Metrics */ export interface Metrics { /** Height of the visible portion of the workspace. */ viewHeight: number; diff --git a/core/utils/object.ts b/core/utils/object.ts index 708c69905..a36ea18c2 100644 --- a/core/utils/object.ts +++ b/core/utils/object.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods for objects. - * - * @namespace Blockly.utils.object - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.object'); @@ -22,7 +17,6 @@ import * as deprecation from './deprecation.js'; * @param parentCtor Parent class. * @suppress {strictMissingProperties} superClass_ is not defined on Function. * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.object.inherits */ export function inherits(childCtor: Function, parentCtor: Function) { deprecation.warn('Blockly.utils.object.inherits', 'version 9', 'version 10'); @@ -50,7 +44,6 @@ export function inherits(childCtor: Function, parentCtor: Function) { * @param target Target. * @param source Source. * @deprecated Use the built-in **Object.assign** instead. - * @alias Blockly.utils.object.mixin */ export function mixin(target: AnyDuringMigration, source: AnyDuringMigration) { deprecation.warn( @@ -66,7 +59,6 @@ export function mixin(target: AnyDuringMigration, source: AnyDuringMigration) { * @param target Target. * @param source Source. * @returns The resulting object. - * @alias Blockly.utils.object.deepMerge */ export function deepMerge( target: AnyDuringMigration, @@ -87,7 +79,6 @@ export function deepMerge( * @param obj Object containing values. * @returns Array of values. * @deprecated Use the built-in **Object.values** instead. - * @alias Blockly.utils.object.values */ export function values(obj: AnyDuringMigration): AnyDuringMigration[] { deprecation.warn( diff --git a/core/utils/parsing.ts b/core/utils/parsing.ts index 3a2fdd611..bd5160cf3 100644 --- a/core/utils/parsing.ts +++ b/core/utils/parsing.ts @@ -4,9 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * @namespace Blockly.utils.parsing - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.parsing'); @@ -109,7 +106,7 @@ function tokenizeInterpolationInternal( // When parsing interpolation tokens, numbers are special // placeholders (%1, %2, etc). Make sure all other values are // strings. - tokens.push(String(rawValue)); + tokens.push(`${rawValue}`); } else { tokens.push(rawValue); } @@ -166,7 +163,6 @@ function tokenizeInterpolationInternal( * @param message Text which might contain string table references and * interpolation tokens. * @returns Array of strings and numbers. - * @alias Blockly.utils.parsing.tokenizeInterpolation */ export function tokenizeInterpolation(message: string): (string|number)[] { return tokenizeInterpolationInternal(message, true); @@ -180,7 +176,6 @@ export function tokenizeInterpolation(message: string): (string|number)[] { * @param message Message, which may be a string that contains * string table references. * @returns String with message references replaced. - * @alias Blockly.utils.parsing.replaceMessageReferences */ export function replaceMessageReferences(message: string|any): string { if (typeof message !== 'string') { @@ -199,7 +194,6 @@ export function replaceMessageReferences(message: string|any): string { * @param message Text which might contain string table references. * @returns True if all message references have matching values. * Otherwise, false. - * @alias Blockly.utils.parsing.checkMessageReferences */ export function checkMessageReferences(message: string): boolean { let validSoFar = true; @@ -230,7 +224,6 @@ export function checkMessageReferences(message: string): boolean { * @returns An object containing the colour as * a #RRGGBB string, and the hue if the input was an HSV hue value. * @throws {Error} If the colour cannot be parsed. - * @alias Blockly.utils.parsing.parseBlockColour */ export function parseBlockColour(colour: number| string): {hue: number|null, hex: string} { diff --git a/core/utils/rect.ts b/core/utils/rect.ts index af97efd1c..a0ed1ca37 100644 --- a/core/utils/rect.ts +++ b/core/utils/rect.ts @@ -17,8 +17,6 @@ goog.declareModuleId('Blockly.utils.Rect'); /** * Class for representing rectangular regions. - * - * @alias Blockly.utils.Rect */ export class Rect { /** diff --git a/core/utils/sentinel.ts b/core/utils/sentinel.ts deleted file mode 100644 index f6b8da26d..000000000 --- a/core/utils/sentinel.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * A type used to create flag values. - * - * @class - */ -import * as goog from '../../closure/goog/goog.js'; -goog.declareModuleId('Blockly.utils.Sentinel'); - - -/** - * A type used to create flag values. - * - * @alias Blockly.utils.Sentinel - */ -export class Sentinel {} diff --git a/core/utils/size.ts b/core/utils/size.ts index 3424c48fa..504b8182f 100644 --- a/core/utils/size.ts +++ b/core/utils/size.ts @@ -17,8 +17,6 @@ goog.declareModuleId('Blockly.utils.Size'); /** * Class for representing sizes consisting of a width and height. - * - * @alias Blockly.utils.Size */ export class Size { /** diff --git a/core/utils/string.ts b/core/utils/string.ts index 35856f354..f7d8e8540 100644 --- a/core/utils/string.ts +++ b/core/utils/string.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods for string manipulation. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.string - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.string'); @@ -24,7 +17,6 @@ import * as deprecation from './deprecation.js'; * @param str The string to check. * @param prefix A string to look for at the start of `str`. * @returns True if `str` begins with `prefix`. - * @alias Blockly.utils.string.startsWith * @deprecated Use built-in **string.startsWith** instead. */ export function startsWith(str: string, prefix: string): boolean { @@ -39,7 +31,6 @@ export function startsWith(str: string, prefix: string): boolean { * * @param array Array of strings. * @returns Length of shortest string. - * @alias Blockly.utils.string.shortestStringLength */ export function shortestStringLength(array: string[]): number { if (!array.length) { @@ -59,7 +50,6 @@ export function shortestStringLength(array: string[]): number { * @param array Array of strings. * @param opt_shortest Length of shortest string. * @returns Length of common prefix. - * @alias Blockly.utils.string.commonWordPrefix */ export function commonWordPrefix( array: string[], opt_shortest?: number): number { @@ -98,7 +88,6 @@ export function commonWordPrefix( * @param array Array of strings. * @param opt_shortest Length of shortest string. * @returns Length of common suffix. - * @alias Blockly.utils.string.commonWordSuffix */ export function commonWordSuffix( array: string[], opt_shortest?: number): number { @@ -136,7 +125,6 @@ export function commonWordSuffix( * @param text Text to wrap. * @param limit Width to wrap each line. * @returns Wrapped text. - * @alias Blockly.utils.string.wrap */ export function wrap(text: string, limit: number): string { const lines = text.split('\n'); @@ -306,7 +294,6 @@ function wrapToText(words: string[], wordBreaks: boolean[]): string { * * @param str Input string. * @returns True if number, false otherwise. - * @alias Blockly.utils.string.isNumber */ export function isNumber(str: string): boolean { return /^\s*-?\d+(\.\d+)?\s*$/.test(str); diff --git a/core/utils/style.ts b/core/utils/style.ts index dbe6f9020..7c53079bd 100644 --- a/core/utils/style.ts +++ b/core/utils/style.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utilities for element styles. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.style - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.style'); @@ -26,7 +19,6 @@ import {Size} from './size.js'; * * @param element Element to get size of. * @returns Object with width/height properties. - * @alias Blockly.utils.style.getSize */ export function getSize(element: Element): Size { return TEST_ONLY.getSizeInternal(element); @@ -84,7 +76,6 @@ function getSizeWithDisplay(element: Element): Size { * @param element Element to get style of. * @param property Property to get (camel-case). * @returns Style value. - * @alias Blockly.utils.style.getComputedStyle */ export function getComputedStyle(element: Element, property: string): string { const styles = window.getComputedStyle(element); @@ -104,7 +95,6 @@ export function getComputedStyle(element: Element, property: string): string { * @param style Property to get (camel-case). * @returns Style value. * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.style.getCascadedStyle */ export function getCascadedStyle(element: Element, style: string): string { deprecation.warn( @@ -123,7 +113,6 @@ export function getCascadedStyle(element: Element, style: string): string { * * @param el Element to get the page offset for. * @returns The page offset. - * @alias Blockly.utils.style.getPageOffset */ export function getPageOffset(el: Element): Coordinate { const pos = new Coordinate(0, 0); @@ -146,7 +135,6 @@ export function getPageOffset(el: Element): Coordinate { * Similar to Closure's goog.style.getViewportPageOffset * * @returns The page offset of the viewport. - * @alias Blockly.utils.style.getViewportPageOffset */ export function getViewportPageOffset(): Coordinate { const body = document.body; @@ -162,7 +150,6 @@ export function getViewportPageOffset(): Coordinate { * * @param element The element to get the border widths for. * @returns The computed border widths. - * @alias Blockly.utils.style.getBorderBox */ export function getBorderBox(element: Element): Rect { const left = parseFloat(getComputedStyle(element, 'borderLeftWidth')); @@ -185,7 +172,6 @@ export function getBorderBox(element: Element): Rect { * scroll element will be used. * @param opt_center Whether to center the element in the container. * Defaults to false. - * @alias Blockly.utils.style.scrollIntoContainerView */ export function scrollIntoContainerView( element: Element, container: Element, opt_center?: boolean) { @@ -207,7 +193,6 @@ export function scrollIntoContainerView( * @param opt_center Whether to center the element in the container. * Defaults to false. * @returns The new scroll position of the container. - * @alias Blockly.utils.style.getContainerOffsetToScrollInto */ export function getContainerOffsetToScrollInto( element: Element, container: Element, opt_center?: boolean): Coordinate { diff --git a/core/utils/svg.ts b/core/utils/svg.ts index 798505351..04904fcb9 100644 --- a/core/utils/svg.ts +++ b/core/utils/svg.ts @@ -16,8 +16,6 @@ goog.declareModuleId('Blockly.utils.Svg'); /** * A name with the type of the SVG element stored in the generic. - * - * @alias Blockly.utils.Svg */ export class Svg<_T> { /** @internal */ diff --git a/core/utils/svg_math.ts b/core/utils/svg_math.ts index 60820c915..2ab1dca63 100644 --- a/core/utils/svg_math.ts +++ b/core/utils/svg_math.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility methods realted to figuring out positions of SVG elements. - * - * @namespace Blockly.utils.svgMath - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.svgMath'); @@ -43,7 +38,6 @@ const XY_STYLE_REGEX = * * @param element SVG element to find the coordinates of. * @returns Object with .x and .y properties. - * @alias Blockly.utils.svgMath.getRelativeXY */ export function getRelativeXY(element: Element): Coordinate { const xy = new Coordinate(0, 0); @@ -90,7 +84,6 @@ export function getRelativeXY(element: Element): Coordinate { * @param element SVG element to find the coordinates of. If this is not a child * of the div Blockly was injected into, the behaviour is undefined. * @returns Object with .x and .y properties. - * @alias Blockly.utils.svgMath.getInjectionDivXY */ export function getInjectionDivXY(element: Element): Coordinate { let x = 0; @@ -114,7 +107,6 @@ export function getInjectionDivXY(element: Element): Coordinate { * * @returns True if 3D transforms are supported. * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.svgMath.is3dSupported */ export function is3dSupported(): boolean { // All browsers support translate3d in 2022. @@ -129,7 +121,6 @@ export function is3dSupported(): boolean { * * @returns An object containing window width, height, and scroll position in * window coordinates. - * @alias Blockly.utils.svgMath.getViewportBBox * @internal */ export function getViewportBBox(): Rect { @@ -145,7 +136,6 @@ export function getViewportBBox(): Rect { * Copied from Closure's goog.dom.getDocumentScroll. * * @returns Object with values 'x' and 'y'. - * @alias Blockly.utils.svgMath.getDocumentScroll */ export function getDocumentScroll(): Coordinate { const el = document.documentElement; @@ -161,7 +151,6 @@ export function getDocumentScroll(): Coordinate { * @param screenCoordinates The screen coordinates to be converted to workspace * coordinates * @returns The workspace coordinates. - * @alias Blockly.utils.svgMath.screenToWsCoordinates */ export function screenToWsCoordinates( ws: WorkspaceSvg, screenCoordinates: Coordinate): Coordinate { diff --git a/core/utils/svg_paths.ts b/core/utils/svg_paths.ts index d87766604..ee7dd8d9c 100644 --- a/core/utils/svg_paths.ts +++ b/core/utils/svg_paths.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Methods for creating parts of SVG path strings. See - * - * @namespace Blockly.utils.svgPaths - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.svgPaths'); @@ -22,7 +17,6 @@ goog.declareModuleId('Blockly.utils.svgPaths'); * @param x The x coordinate. * @param y The y coordinate. * @returns A string of the format ' x,y ' - * @alias Blockly.utils.svgPaths.point */ export function point(x: number, y: number): string { return ' ' + x + ',' + y + ' '; @@ -40,7 +34,6 @@ export function point(x: number, y: number): string { * x, y '. * @returns A string defining one or more Bezier curves. See the MDN * documentation for exact format. - * @alias Blockly.utils.svgPaths.curve */ export function curve(command: string, points: string[]): string { return ' ' + command + points.join(''); @@ -55,7 +48,6 @@ export function curve(command: string, points: string[]): string { * @param x The absolute x coordinate. * @param y The absolute y coordinate. * @returns A string of the format ' M x,y ' - * @alias Blockly.utils.svgPaths.moveTo */ export function moveTo(x: number, y: number): string { return ' M ' + x + ',' + y + ' '; @@ -70,7 +62,6 @@ export function moveTo(x: number, y: number): string { * @param dx The relative x coordinate. * @param dy The relative y coordinate. * @returns A string of the format ' m dx,dy ' - * @alias Blockly.utils.svgPaths.moveBy */ export function moveBy(dx: number, dy: number): string { return ' m ' + dx + ',' + dy + ' '; @@ -85,7 +76,6 @@ export function moveBy(dx: number, dy: number): string { * @param dx The relative x coordinate. * @param dy The relative y coordinate. * @returns A string of the format ' l dx,dy ' - * @alias Blockly.utils.svgPaths.lineTo */ export function lineTo(dx: number, dy: number): string { return ' l ' + dx + ',' + dy + ' '; @@ -100,7 +90,6 @@ export function lineTo(dx: number, dy: number): string { * @param points An array containing all of the points to draw lines to, in * order. The points are represented as strings of the format ' dx,dy '. * @returns A string of the format ' l (dx,dy)+ ' - * @alias Blockly.utils.svgPaths.line */ export function line(points: string[]): string { return ' l' + points.join(''); @@ -118,7 +107,6 @@ export function line(points: string[]): string { * @param val The coordinate to pass to the command. It may be absolute or * relative. * @returns A string of the format ' command val ' - * @alias Blockly.utils.svgPaths.lineOnAxis */ export function lineOnAxis(command: string, val: number): string { return ' ' + command + ' ' + val + ' '; @@ -136,7 +124,6 @@ export function lineOnAxis(command: string, val: number): string { * @param point The point to move the cursor to after drawing the arc, specified * either in absolute or relative coordinates depending on the command. * @returns A string of the format 'command radius radius flags point' - * @alias Blockly.utils.svgPaths.arc */ export function arc( command: string, flags: string, radius: number, point: string): string { diff --git a/core/utils/toolbox.ts b/core/utils/toolbox.ts index 89b2fdbb2..0f6ecddac 100644 --- a/core/utils/toolbox.ts +++ b/core/utils/toolbox.ts @@ -4,25 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility functions for the toolbox and flyout. - * - * @namespace Blockly.utils.toolbox - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.toolbox'); import type {ConnectionState} from '../serialization/blocks.js'; import type {CssConfig as CategoryCssConfig} from '../toolbox/category.js'; import type {CssConfig as SeparatorCssConfig} from '../toolbox/separator.js'; -import * as Xml from '../xml.js'; +import * as utilsXml from './xml.js'; /** * The information needed to create a block in the toolbox. * Note that disabled has a different type for backwards compatibility. - * - * @alias Blockly.utils.toolbox.BlockInfo */ export interface BlockInfo { kind: string; @@ -46,8 +39,6 @@ export interface BlockInfo { /** * The information needed to create a separator in the toolbox. - * - * @alias Blockly.utils.toolbox.SeparatorInfo */ export interface SeparatorInfo { kind: string; @@ -58,8 +49,6 @@ export interface SeparatorInfo { /** * The information needed to create a button in the toolbox. - * - * @alias Blockly.utils.toolbox.ButtonInfo */ export interface ButtonInfo { kind: string; @@ -69,8 +58,6 @@ export interface ButtonInfo { /** * The information needed to create a label in the toolbox. - * - * @alias Blockly.utils.toolbox.LabelInfo */ export interface LabelInfo { kind: string; @@ -80,15 +67,11 @@ export interface LabelInfo { /** * The information needed to create either a button or a label in the flyout. - * - * @alias Blockly.utils.toolbox.ButtonOrLabelInfo */ export type ButtonOrLabelInfo = ButtonInfo|LabelInfo; /** * The information needed to create a category in the toolbox. - * - * @alias Blockly.utils.toolbox.StaticCategoryInfo */ export interface StaticCategoryInfo { kind: string; @@ -99,12 +82,11 @@ export interface StaticCategoryInfo { colour: string|undefined; cssconfig: CategoryCssConfig|undefined; hidden: string|undefined; + expanded?: string|boolean; } /** * The information needed to create a custom category. - * - * @alias Blockly.utils.toolbox.DynamicCategoryInfo */ export interface DynamicCategoryInfo { kind: string; @@ -114,34 +96,27 @@ export interface DynamicCategoryInfo { colour: string|undefined; cssconfig: CategoryCssConfig|undefined; hidden: string|undefined; + expanded?: string|boolean; } /** * The information needed to create either a dynamic or static category. - * - * @alias Blockly.utils.toolbox.CategoryInfo */ export type CategoryInfo = StaticCategoryInfo|DynamicCategoryInfo; /** * Any information that can be used to create an item in the toolbox. - * - * @alias Blockly.utils.toolbox.ToolboxItemInfo */ export type ToolboxItemInfo = FlyoutItemInfo|StaticCategoryInfo; /** * All the different types that can be displayed in a flyout. - * - * @alias Blockly.utils.toolbox.FlyoutItemInfo */ export type FlyoutItemInfo = BlockInfo|SeparatorInfo|ButtonInfo|LabelInfo|DynamicCategoryInfo; /** * The JSON definition of a toolbox. - * - * @alias Blockly.utils.toolbox.ToolboxInfo */ export interface ToolboxInfo { kind?: string; @@ -150,22 +125,16 @@ export interface ToolboxInfo { /** * An array holding flyout items. - * - * @alias Blockly.utils.toolbox.FlyoutItemInfoArray */ export type FlyoutItemInfoArray = FlyoutItemInfo[]; /** * All of the different types that can create a toolbox. - * - * @alias Blockly.utils.toolbox.ToolboxDefinition */ export type ToolboxDefinition = Node|ToolboxInfo|string; /** * All of the different types that can be used to show items in a flyout. - * - * @alias Blockly.utils.toolbox.FlyoutDefinition */ export type FlyoutDefinition = FlyoutItemInfoArray|NodeList|ToolboxInfo|Node[]; @@ -185,8 +154,6 @@ const FLYOUT_TOOLBOX_KIND = 'flyoutToolbox'; /** * Position of the toolbox and/or flyout relative to the workspace. - * - * @alias Blockly.utils.toolbox.Position */ export enum Position { TOP, @@ -200,7 +167,6 @@ export enum Position { * * @param toolboxDef The definition of the toolbox in one of its many forms. * @returns Object holding information for creating a toolbox. - * @alias Blockly.utils.toolbox.convertToolboxDefToJson * @internal */ export function convertToolboxDefToJson(toolboxDef: ToolboxDefinition| @@ -250,7 +216,6 @@ function validateToolbox(toolboxJson: ToolboxInfo) { * * @param flyoutDef The definition of the flyout in one of its many forms. * @returns A list of flyout items. - * @alias Blockly.utils.toolbox.convertFlyoutDefToJsonArray * @internal */ export function convertFlyoutDefToJsonArray(flyoutDef: FlyoutDefinition| @@ -282,7 +247,6 @@ export function convertFlyoutDefToJsonArray(flyoutDef: FlyoutDefinition| * * @param toolboxJson Object holding information for creating a toolbox. * @returns True if the toolbox has categories. - * @alias Blockly.utils.toolbox.hasCategories * @internal */ export function hasCategories(toolboxJson: ToolboxInfo|null): boolean { @@ -313,7 +277,6 @@ function hasCategoriesInternal(toolboxJson: ToolboxInfo|null): boolean { * * @param categoryInfo Object holing information for creating a category. * @returns True if the category has subcategories. - * @alias Blockly.utils.toolbox.isCategoryCollapsible * @internal */ export function isCategoryCollapsible(categoryInfo: CategoryInfo): boolean { @@ -413,14 +376,13 @@ function addAttributes(node: Node, obj: AnyDuringMigration) { * * @param toolboxDef DOM tree of blocks, or text representation of same. * @returns DOM tree of blocks, or null. - * @alias Blockly.utils.toolbox.parseToolboxTree */ export function parseToolboxTree(toolboxDef: Element|null|string): Element| null { let parsedToolboxDef: Element|null = null; if (toolboxDef) { if (typeof toolboxDef === 'string') { - parsedToolboxDef = Xml.textToDom(toolboxDef); + parsedToolboxDef = utilsXml.textToDom(toolboxDef); if (parsedToolboxDef.nodeName.toLowerCase() !== 'xml') { throw TypeError('Toolbox should be an document.'); } diff --git a/core/utils/useragent.ts b/core/utils/useragent.ts index d0b7f91e8..386c99965 100644 --- a/core/utils/useragent.ts +++ b/core/utils/useragent.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Useragent detection. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.userAgent - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.userAgent'); @@ -78,26 +71,18 @@ isTablet = isIPad || isAndroid && !has('Mobile') || has('Silk'); isMobile = !isTablet && (isIPhone || isAndroid); })(globalThis['navigator'] && globalThis['navigator']['userAgent'] || ''); -/** @alias Blockly.utils.userAgent.raw */ export const raw: string = rawUserAgent; -/** @alias Blockly.utils.userAgent.JavaFx */ export const JavaFx: boolean = isJavaFx; -/** @alias Blockly.utils.userAgent.GECKO */ export const GECKO: boolean = isGecko; -/** @alias Blockly.utils.userAgent.ANDROID */ export const ANDROID: boolean = isAndroid; -/** @alias Blockly.utils.userAgent.IPAD */ export const IPAD: boolean = isIPad; -/** @alias Blockly.utils.userAgent.IPHONE */ export const IPHONE: boolean = isIPhone; -/** @alias Blockly.utils.userAgent.MAC */ export const MAC: boolean = isMac; -/** @alias Blockly.utils.userAgent.MOBILE */ export const MOBILE: boolean = isMobile; diff --git a/core/utils/xml.ts b/core/utils/xml.ts index c33712992..a02f1a8d6 100644 --- a/core/utils/xml.ts +++ b/core/utils/xml.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * XML element manipulation. - * These methods are not specific to Blockly, and could be factored out into - * a JavaScript framework such as Closure. - * - * @namespace Blockly.utils.xml - */ import * as goog from '../../closure/goog/goog.js'; goog.declareModuleId('Blockly.utils.xml'); @@ -61,8 +54,6 @@ export function injectDependencies(dependencies: { /** * Namespace for Blockly's XML. - * - * @alias Blockly.utils.xml.NAME_SPACE */ export const NAME_SPACE = 'https://developers.google.com/blockly/xml'; @@ -71,7 +62,6 @@ export const NAME_SPACE = 'https://developers.google.com/blockly/xml'; * * @returns The document object. * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.xml.getDocument */ export function getDocument(): Document { deprecation.warn('Blockly.utils.xml.getDocument', 'version 9', 'version 10'); @@ -83,7 +73,6 @@ export function getDocument(): Document { * * @param xmlDocument The document object to use. * @deprecated No longer provided by Blockly. - * @alias Blockly.utils.xml.setDocument */ export function setDocument(xmlDocument: Document) { deprecation.warn('Blockly.utils.xml.setDocument', 'version 9', 'version 10'); @@ -95,7 +84,6 @@ export function setDocument(xmlDocument: Document) { * * @param tagName Name of DOM element. * @returns New DOM element. - * @alias Blockly.utils.xml.createElement */ export function createElement(tagName: string): Element { return document.createElementNS(NAME_SPACE, tagName); @@ -106,19 +94,34 @@ export function createElement(tagName: string): Element { * * @param text Text content. * @returns New DOM text node. - * @alias Blockly.utils.xml.createTextNode */ export function createTextNode(text: string): Text { return document.createTextNode(text); } +/** + * Converts an XML string into a DOM structure. + * + * @param text An XML string. + * @returns A DOM object representing the singular child of the document + * element. + * @throws if the text doesn't parse. + */ +export function textToDom(text: string): Element { + const doc = textToDomDocument(text); + if (!doc || !doc.documentElement || + doc.getElementsByTagName('parsererror').length) { + throw Error('textToDom was unable to parse: ' + text); + } + return doc.documentElement; +} + /** * Converts an XML string into a DOM tree. * * @param text XML string. * @returns The DOM document. * @throws if XML doesn't parse. - * @alias Blockly.utils.xml.textToDomDocument */ export function textToDomDocument(text: string): Document { const oParser = new DOMParser(); @@ -131,7 +134,6 @@ export function textToDomDocument(text: string): Document { * * @param dom A tree of XML nodes. * @returns Text representation. - * @alias Blockly.utils.xml.domToText */ export function domToText(dom: Node): string { const oSerializer = new XMLSerializer(); diff --git a/core/variable_map.ts b/core/variable_map.ts index ecba4b87f..722c51b12 100644 --- a/core/variable_map.ts +++ b/core/variable_map.ts @@ -32,8 +32,6 @@ import type {Workspace} from './workspace.js'; * Class for a variable map. This contains a dictionary data structure with * variable types as keys and lists of variables as values. The list of * variables are the type indicated by the key. - * - * @alias Blockly.VariableMap */ export class VariableMap { /** @@ -46,10 +44,18 @@ export class VariableMap { /** @param workspace The workspace this map belongs to. */ constructor(public workspace: Workspace) {} - /** Clear the variable map. */ + /** Clear the variable map. Fires events for every deletion. */ clear() { - this.variableMap.clear(); + for (const variables of this.variableMap.values()) { + while (variables.length > 0) { + this.deleteVariable(variables[0]); + } + } + if (this.variableMap.size !== 0) { + throw Error('Non-empty variable map'); + } } + /* Begin functions for renaming variables. */ /** * Rename the given variable by updating its name in the variable map. @@ -63,7 +69,10 @@ export class VariableMap { const type = variable.type; const conflictVar = this.getVariable(newName, type); const blocks = this.workspace.getAllBlocks(false); - eventUtils.setGroup(true); + const existingGroup = eventUtils.getGroup(); + if (!existingGroup) { + eventUtils.setGroup(true); + } try { // The IDs may match if the rename is a simple case change (name1 -> // Name1). @@ -74,7 +83,7 @@ export class VariableMap { variable, newName, conflictVar, blocks); } } finally { - eventUtils.setGroup(false); + eventUtils.setGroup(existingGroup); } } @@ -144,6 +153,7 @@ export class VariableMap { // And remove it from the list. arrayUtils.removeElem(this.variableMap.get(type)!, variable); } + /* End functions for renaming variables. */ /** * Create a variable with a given name, optional type, and optional ID. @@ -189,6 +199,7 @@ export class VariableMap { return variable; } + /* Begin functions for variable deletion. */ /** * Delete a variable. @@ -205,6 +216,9 @@ export class VariableMap { variableList.splice(i, 1); eventUtils.fire( new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); + if (variableList.length === 0) { + this.variableMap.delete(variable.type); + } return; } } @@ -273,9 +287,7 @@ export class VariableMap { } this.deleteVariable(variable); } finally { - if (!existingGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); } } /* End functions for variable deletion. */ @@ -308,7 +320,7 @@ export class VariableMap { * @returns The variable with the given ID. */ getVariableById(id: string): VariableModel|null { - for (const [_key, variables] of this.variableMap) { + for (const variables of this.variableMap.values()) { for (const variable of variables) { if (variable.getId() === id) { return variable; diff --git a/core/variable_model.ts b/core/variable_model.ts index cfd832a90..11c901474 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -24,7 +24,6 @@ import type {Workspace} from './workspace.js'; * Holds information for the variable including name, ID, and type. * * @see {Blockly.FieldVariable} - * @alias Blockly.VariableModel */ export class VariableModel { type: string; diff --git a/core/variables.ts b/core/variables.ts index e50327347..901572bb0 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -4,22 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility functions for handling variables. - * - * @namespace Blockly.Variables - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Variables'); import {Blocks} from './blocks.js'; import * as dialog from './dialog.js'; +import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; import {Msg} from './msg.js'; +import {isLegacyProcedureDefBlock} from './interfaces/i_legacy_procedure_blocks.js'; import * as utilsXml from './utils/xml.js'; import {VariableModel} from './variable_model.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -import * as Xml from './xml.js'; /** @@ -28,8 +24,6 @@ import * as Xml from './xml.js'; * variable blocks. * See also Blockly.Procedures.CATEGORY_NAME and * Blockly.VariablesDynamic.CATEGORY_NAME. - * - * @alias Blockly.Variables.CATEGORY_NAME */ export const CATEGORY_NAME = 'VARIABLE'; @@ -41,7 +35,6 @@ export const CATEGORY_NAME = 'VARIABLE'; * * @param ws The workspace to search for variables. * @returns Array of variable models. - * @alias Blockly.Variables.allUsedVarModels */ export function allUsedVarModels(ws: Workspace): VariableModel[] { const blocks = ws.getAllBlocks(false); @@ -73,7 +66,6 @@ export function allUsedVarModels(ws: Workspace): VariableModel[] { * * @param workspace The workspace to search. * @returns A list of non-duplicated variable names. - * @alias Blockly.Variables.allDeveloperVariables */ export function allDeveloperVariables(workspace: Workspace): string[] { const blocks = workspace.getAllBlocks(false); @@ -97,7 +89,6 @@ export function allDeveloperVariables(workspace: Workspace): string[] { * * @param workspace The workspace containing variables. * @returns Array of XML elements. - * @alias Blockly.Variables.flyoutCategory */ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { let xmlList = new Array(); @@ -121,7 +112,6 @@ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { * * @param workspace The workspace containing variables. * @returns Array of XML block elements. - * @alias Blockly.Variables.flyoutCategoryBlocks */ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { const variableModelList = workspace.getVariablesOfType(''); @@ -142,7 +132,7 @@ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { block.setAttribute('type', 'math_change'); block.setAttribute('gap', Blocks['variables_get'] ? '20' : '8'); block.appendChild(generateVariableFieldDom(mostRecentVariable)); - const value = Xml.textToDom( + const value = utilsXml.textToDom( '' + '' + '1' + @@ -166,7 +156,6 @@ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { return xmlList; } -/** @alias Blockly.Variables.VAR_LETTER_OPTIONS */ export const VAR_LETTER_OPTIONS = 'ijkmnopqrstuvwxyzabcdefgh'; /** @@ -177,7 +166,6 @@ export const VAR_LETTER_OPTIONS = 'ijkmnopqrstuvwxyzabcdefgh'; * * @param workspace The workspace to be unique in. * @returns New variable name. - * @alias Blockly.Variables.generateUniqueName */ export function generateUniqueName(workspace: Workspace): string { return TEST_ONLY.generateUniqueNameInternal(workspace); @@ -199,7 +187,6 @@ function generateUniqueNameInternal(workspace: Workspace): string { * @param startChar The character to start the search at. * @param usedNames A list of all of the used names. * @returns A unique name that is not present in the usedNames array. - * @alias Blockly.Variables.generateUniqueNameFromOptions */ export function generateUniqueNameFromOptions( startChar: string, usedNames: string[]): string { @@ -251,7 +238,6 @@ export function generateUniqueNameFromOptions( * an existing variable was chosen. * @param opt_type The type of the variable like 'int', 'string', or ''. This * will default to '', which is a specific type. - * @alias Blockly.Variables.createVariableButtonHandler */ export function createVariableButtonHandler( workspace: Workspace, opt_callback?: (p1?: string|null) => void, @@ -260,32 +246,28 @@ export function createVariableButtonHandler( // This function needs to be named so it can be called recursively. function promptAndCheckWithAlert(defaultName: string) { promptName(Msg['NEW_VARIABLE_TITLE'], defaultName, function(text) { - if (text) { - const existing = nameUsedWithAnyType(text, workspace); - if (existing) { - let msg; - if (existing.type === type) { - msg = Msg['VARIABLE_ALREADY_EXISTS'].replace('%1', existing.name); - } else { - msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']; - msg = msg.replace('%1', existing.name).replace('%2', existing.type); - } - dialog.alert(msg, function() { - promptAndCheckWithAlert(text); - }); - } else { - // No conflict - workspace.createVariable(text, type); - if (opt_callback) { - opt_callback(text); - } - } - } else { - // User canceled prompt. - if (opt_callback) { - opt_callback(null); - } + if (!text) { // User canceled prompt. + if (opt_callback) opt_callback(null); + return; } + + const existing = nameUsedWithAnyType(text, workspace); + if (!existing) { // No conflict + workspace.createVariable(text, type); + if (opt_callback) opt_callback(text); + return; + } + + let msg; + if (existing.type === type) { + msg = Msg['VARIABLE_ALREADY_EXISTS'].replace('%1', existing.name); + } else { + msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']; + msg = msg.replace('%1', existing.name).replace('%2', existing.type); + } + dialog.alert(msg, function() { + promptAndCheckWithAlert(text); + }); }); } promptAndCheckWithAlert(''); @@ -301,7 +283,6 @@ export function createVariableButtonHandler( * @param opt_callback A callback. It will be passed an acceptable new variable * name, or null if change is to be aborted (cancel button), or undefined if * an existing variable was chosen. - * @alias Blockly.Variables.renameVariable */ export function renameVariable( workspace: Workspace, variable: VariableModel, @@ -311,28 +292,33 @@ export function renameVariable( const promptText = Msg['RENAME_VARIABLE_TITLE'].replace('%1', variable.name); promptName(promptText, defaultName, function(newName) { - if (newName) { - const existing = - nameUsedWithOtherType(newName, variable.type, workspace); - if (existing) { - const msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'] - .replace('%1', existing.name) - .replace('%2', existing.type); - dialog.alert(msg, function() { - promptAndCheckWithAlert(newName); - }); - } else { - workspace.renameVariableById(variable.getId(), newName); - if (opt_callback) { - opt_callback(newName); - } - } - } else { - // User canceled prompt. - if (opt_callback) { - opt_callback(null); - } + if (!newName) { // User canceled prompt. + if (opt_callback) opt_callback(null); + return; } + + const existing = nameUsedWithOtherType(newName, variable.type, workspace); + const procedure = + nameUsedWithConflictingParam(variable.name, newName, workspace); + if (!existing && !procedure) { // No conflict. + workspace.renameVariableById(variable.getId(), newName); + if (opt_callback) opt_callback(newName); + return; + } + + let msg = ''; + if (existing) { + msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'] + .replace('%1', existing.name) + .replace('%2', existing.type); + } else if (procedure) { + msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_A_PARAMETER'] + .replace('%1', newName) + .replace('%2', procedure); + } + dialog.alert(msg, function() { + promptAndCheckWithAlert(newName); + }); }); } promptAndCheckWithAlert(''); @@ -345,7 +331,6 @@ export function renameVariable( * @param defaultText The default value to show in the prompt's field. * @param callback A callback. It will be passed the new variable name, or null * if the user picked something illegal. - * @alias Blockly.Variables.promptName */ export function promptName( promptText: string, defaultText: string, @@ -392,7 +377,6 @@ function nameUsedWithOtherType( * @param name The name to search for. * @param workspace The workspace to search for the variable. * @returns The variable with the given name, or null if none was found. - * @alias Blockly.Variables.nameUsedWithAnyType */ export function nameUsedWithAnyType( name: string, workspace: Workspace): VariableModel|null { @@ -407,12 +391,73 @@ export function nameUsedWithAnyType( return null; } +/** + * Returns the name of the procedure with a conflicting parameter name, or null + * if one does not exist. + * + * This checks the procedure map if it contains models, and the legacy procedure + * blocks otherwise. + * + * @param oldName The old name of the variable. + * @param newName The proposed name of the variable. + * @param workspace The workspace to search for conflicting parameters. + * @internal + */ +export function nameUsedWithConflictingParam( + oldName: string, newName: string, workspace: Workspace): string|null { + return workspace.getProcedureMap().getProcedures().length ? + checkForConflictingParamWithProcedureModels(oldName, newName, workspace) : + checkForConflictingParamWithLegacyProcedures(oldName, newName, workspace); +} + +/** + * Returns the name of the procedure model with a conflicting param name, or + * null if one does not exist. + */ +function checkForConflictingParamWithProcedureModels( + oldName: string, newName: string, workspace: Workspace): string|null { + oldName = oldName.toLowerCase(); + newName = newName.toLowerCase(); + + const procedures = workspace.getProcedureMap().getProcedures(); + for (const procedure of procedures) { + const params = procedure.getParameters() + .filter(isVariableBackedParameterModel) + .map((param) => param.getVariableModel().name); + if (!params) continue; + const procHasOld = params.some((param) => param.toLowerCase() === oldName); + const procHasNew = params.some((param) => param.toLowerCase() === newName); + if (procHasOld && procHasNew) return procedure.getName(); + } + return null; +} + +/** + * Returns the name of the procedure block with a conflicting param name, or + * null if one does not exist. + */ +function checkForConflictingParamWithLegacyProcedures( + oldName: string, newName: string, workspace: Workspace): string|null { + oldName = oldName.toLowerCase(); + newName = newName.toLowerCase(); + + const blocks = workspace.getAllBlocks(false); + for (const block of blocks) { + if (!isLegacyProcedureDefBlock(block)) continue; + const def = block.getProcedureDef(); + const params = def[1]; + const blockHasOld = params.some((param) => param.toLowerCase() === oldName); + const blockHasNew = params.some((param) => param.toLowerCase() === newName); + if (blockHasOld && blockHasNew) return def[0]; + } + return null; +} + /** * Generate DOM objects representing a variable field. * * @param variableModel The variable model to represent. * @returns The generated DOM. - * @alias Blockly.Variables.generateVariableFieldDom */ export function generateVariableFieldDom(variableModel: VariableModel): Element { @@ -439,7 +484,6 @@ export function generateVariableFieldDom(variableModel: VariableModel): * @param opt_type The type to use to look up or create the variable. * @returns The variable corresponding to the given ID or name + type * combination. - * @alias Blockly.Variables.getOrCreateVariablePackage */ export function getOrCreateVariablePackage( workspace: Workspace, id: string|null, opt_name?: string, @@ -465,7 +509,6 @@ export function getOrCreateVariablePackage( * Only used if lookup by ID fails. * @returns The variable corresponding to the given ID or name + type * combination, or null if not found. - * @alias Blockly.Variables.getVariable */ export function getVariable( workspace: Workspace, id: string|null, opt_name?: string, @@ -543,7 +586,6 @@ function createVariable( * @returns The new array of variables that were freshly added to the workspace * after creating the new block, or [] if no new variables were added to the * workspace. - * @alias Blockly.Variables.getAddedVariables * @internal */ export function getAddedVariables( diff --git a/core/variables_dynamic.ts b/core/variables_dynamic.ts index 6191b99d2..da3b797aa 100644 --- a/core/variables_dynamic.ts +++ b/core/variables_dynamic.ts @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Utility functions for handling typed variables. - * - * @namespace Blockly.VariablesDynamic - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.VariablesDynamic'); @@ -28,8 +23,6 @@ import type {FlyoutButton} from './flyout_button.js'; * variable blocks. * See also Blockly.Variables.CATEGORY_NAME and * Blockly.Procedures.CATEGORY_NAME. - * - * @alias Blockly.VariablesDynamic.CATEGORY_NAME */ export const CATEGORY_NAME = 'VARIABLE_DYNAMIC'; @@ -75,7 +68,6 @@ export const onCreateVariableButtonClick_Colour = colourButtonClickHandler; * * @param workspace The workspace containing variables. * @returns Array of XML elements. - * @alias Blockly.VariablesDynamic.flyoutCategory */ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { let xmlList = new Array(); @@ -109,7 +101,6 @@ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { * * @param workspace The workspace containing variables. * @returns Array of XML block elements. - * @alias Blockly.VariablesDynamic.flyoutCategoryBlocks */ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { const variableModelList = workspace.getAllVariables(); diff --git a/core/warning.ts b/core/warning.ts index 76ae9ff00..8e80f9234 100644 --- a/core/warning.ts +++ b/core/warning.ts @@ -26,8 +26,6 @@ import {Svg} from './utils/svg.js'; /** * Class for a warning. - * - * @alias Blockly.Warning */ export class Warning extends Icon { private text: {[key: string]: string}; diff --git a/core/widgetdiv.ts b/core/widgetdiv.ts index 1ca04092f..0c5f1615d 100644 --- a/core/widgetdiv.ts +++ b/core/widgetdiv.ts @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * A div that floats on top of Blockly. This singleton contains - * temporary HTML UI widgets that the user is currently interacting with. - * E.g. text input areas, colour pickers, context menus. - * - * @namespace Blockly.WidgetDiv - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.WidgetDiv'); @@ -40,7 +33,6 @@ let containerDiv: HTMLDivElement|null; * Returns the HTML container for editor widgets. * * @returns The editor widget container. - * @alias Blockly.WidgetDiv.getDiv */ export function getDiv(): HTMLDivElement|null { return containerDiv; @@ -50,7 +42,6 @@ export function getDiv(): HTMLDivElement|null { * Allows unit tests to reset the div. Do not use outside of tests. * * @param newDiv The new value for the DIV field. - * @alias Blockly.WidgetDiv.testOnly_setDiv * @internal */ export function testOnly_setDiv(newDiv: HTMLDivElement|null) { @@ -59,8 +50,6 @@ export function testOnly_setDiv(newDiv: HTMLDivElement|null) { /** * Create the widget div and inject it onto the page. - * - * @alias Blockly.WidgetDiv.createDom */ export function createDom() { if (containerDiv) { @@ -80,7 +69,6 @@ export function createDom() { * @param rtl Right-to-left (true) or left-to-right (false). * @param newDispose Optional cleanup function to be run when the widget is * closed. - * @alias Blockly.WidgetDiv.show */ export function show(newOwner: unknown, rtl: boolean, newDispose: () => void) { hide(); @@ -103,8 +91,6 @@ export function show(newOwner: unknown, rtl: boolean, newDispose: () => void) { /** * Destroy the widget and hide the div. - * - * @alias Blockly.WidgetDiv.hide */ export function hide() { if (!isVisible()) { @@ -136,7 +122,6 @@ export function hide() { * Is the container visible? * * @returns True if visible. - * @alias Blockly.WidgetDiv.isVisible */ export function isVisible(): boolean { return !!owner; @@ -147,7 +132,6 @@ export function isVisible(): boolean { * object. * * @param oldOwner The object that was using this container. - * @alias Blockly.WidgetDiv.hideIfOwner */ export function hideIfOwner(oldOwner: unknown) { if (owner === oldOwner) { @@ -182,7 +166,6 @@ function positionInternal(x: number, y: number, height: number) { * window coordinates. * @param rtl Whether the workspace is in RTL mode. This determines horizontal * alignment. - * @alias Blockly.WidgetDiv.positionWithAnchor * @internal */ export function positionWithAnchor( diff --git a/core/workspace.ts b/core/workspace.ts index 0602fa834..04a03eb91 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -33,14 +33,12 @@ import {VariableMap} from './variable_map.js'; import type {VariableModel} from './variable_model.js'; import type {WorkspaceComment} from './workspace_comment.js'; import {IProcedureMap} from './interfaces/i_procedure_map.js'; -import {ObservableProcedureMap} from './procedures.js'; +import {ObservableProcedureMap} from './observable_procedure_map.js'; /** * Class for a workspace. This is a data structure that contains blocks. * There is no UI, and can be created headlessly. - * - * @alias Blockly.Workspace */ export class Workspace implements IASTNodeLocation { /** @@ -112,7 +110,7 @@ export class Workspace implements IASTNodeLocation { private readonly blockDB = new Map(); private readonly typedBlocksDB = new Map(); private variableMap: VariableMap; - private procedureMap: IProcedureMap = new ObservableProcedureMap(this); + private procedureMap: IProcedureMap = new ObservableProcedureMap(); /** * Blocks in the flyout can refer to variables that don't exist in the main @@ -172,22 +170,11 @@ export class Workspace implements IASTNodeLocation { */ private sortObjects_(a: Block|WorkspaceComment, b: Block|WorkspaceComment): number { - // AnyDuringMigration because: Property 'getRelativeToSurfaceXY' does not - // exist on type 'Block | WorkspaceComment'. - const aXY = (a as AnyDuringMigration).getRelativeToSurfaceXY(); - // AnyDuringMigration because: Property 'getRelativeToSurfaceXY' does not - // exist on type 'Block | WorkspaceComment'. - const bXY = (b as AnyDuringMigration).getRelativeToSurfaceXY(); - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => number'. - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => number'. - return aXY.y + - (Workspace.prototype.sortObjects_ as AnyDuringMigration).offset * - aXY.x - - (bXY.y + - (Workspace.prototype.sortObjects_ as AnyDuringMigration).offset * - bXY.x); + const offset = + Math.sin(math.toRadians(Workspace.SCAN_ANGLE)) * (this.RTL ? -1 : 1); + const aXY = a.getRelativeToSurfaceXY(); + const bXY = b.getRelativeToSurfaceXY(); + return aXY.y + offset * aXY.x - (bXY.y + offset * bXY.x); } /** @@ -221,17 +208,7 @@ export class Workspace implements IASTNodeLocation { // Copy the topBlocks list. const blocks = (new Array()).concat(this.topBlocks); if (ordered && blocks.length > 1) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => number'. - (this.sortObjects_ as AnyDuringMigration).offset = - Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => - // number'. - (this.sortObjects_ as AnyDuringMigration).offset *= -1; - } - blocks.sort(this.sortObjects_); + blocks.sort(this.sortObjects_.bind(this)); } return blocks; } @@ -274,20 +251,10 @@ export class Workspace implements IASTNodeLocation { } const blocks = this.typedBlocksDB.get(type)!.slice(0); if (ordered && blocks && blocks.length > 1) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => number'. - (this.sortObjects_ as AnyDuringMigration).offset = - Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => - // number'. - (this.sortObjects_ as AnyDuringMigration).offset *= -1; - } - blocks.sort(this.sortObjects_); + blocks.sort(this.sortObjects_.bind(this)); } - return blocks.filter(function(block: AnyDuringMigration) { + return blocks.filter(function(block: Block) { return !block.isInsertionMarker(); }); } @@ -340,17 +307,7 @@ export class Workspace implements IASTNodeLocation { // Copy the topComments list. const comments = (new Array()).concat(this.topComments); if (ordered && comments.length > 1) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => number'. - (this.sortObjects_ as AnyDuringMigration).offset = - Math.sin(math.toRadians(Workspace.SCAN_ANGLE)); - if (this.RTL) { - // AnyDuringMigration because: Property 'offset' does not exist on type - // '(a: Block | WorkspaceComment, b: Block | WorkspaceComment) => - // number'. - (this.sortObjects_ as AnyDuringMigration).offset *= -1; - } - comments.sort(this.sortObjects_); + comments.sort(this.sortObjects_.bind(this)); } return comments; } @@ -363,7 +320,7 @@ export class Workspace implements IASTNodeLocation { * @returns Array of blocks. */ getAllBlocks(ordered: boolean): Block[] { - let blocks: AnyDuringMigration[]; + let blocks: Block[]; if (ordered) { // Slow, but ordered. const topBlocks = this.getTopBlocks(true); @@ -402,9 +359,7 @@ export class Workspace implements IASTNodeLocation { while (this.topComments.length) { this.topComments[this.topComments.length - 1].dispose(); } - if (!existingGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); this.variableMap.clear(); if (this.potentialVariableMap) { this.potentialVariableMap.clear(); @@ -598,7 +553,7 @@ export class Workspace implements IASTNodeLocation { * to be created). * @returns True if there is capacity for the given map, false otherwise. */ - isCapacityAvailable(typeCountsMap: AnyDuringMigration): boolean { + isCapacityAvailable(typeCountsMap: {[key: string]: number}): boolean { if (!this.hasBlockLimits()) { return true; } @@ -661,9 +616,9 @@ export class Workspace implements IASTNodeLocation { // Do another undo/redo if the next one is of the same group. while (inputStack.length && inputEvent.group && inputEvent.group === inputStack[inputStack.length - 1].group) { - // AnyDuringMigration because: Argument of type 'Abstract | undefined' is - // not assignable to parameter of type 'Abstract'. - events.push(inputStack.pop() as AnyDuringMigration); + const event = inputStack.pop(); + if (!event) continue; + events.push(event); } // Push these popped events on the opposite stack. for (let i = 0; i < events.length; i++) { diff --git a/core/workspace_audio.ts b/core/workspace_audio.ts index 3c9d443f8..7874161f8 100644 --- a/core/workspace_audio.ts +++ b/core/workspace_audio.ts @@ -25,8 +25,6 @@ const SOUND_LIMIT = 100; /** * Class for loading, storing, and playing audio for a workspace. - * - * @alias Blockly.WorkspaceAudio */ export class WorkspaceAudio { /** Database of pre-loaded sounds. */ diff --git a/core/workspace_comment.ts b/core/workspace_comment.ts index 6e218c858..88418da82 100644 --- a/core/workspace_comment.ts +++ b/core/workspace_comment.ts @@ -22,8 +22,6 @@ import type {Workspace} from './workspace.js'; /** * Class for a workspace comment. - * - * @alias Blockly.WorkspaceComment */ export class WorkspaceComment { id: string; @@ -154,7 +152,7 @@ export class WorkspaceComment { * This is not valid if the comment is currently being dragged. * @internal */ - getXY(): Coordinate { + getRelativeToSurfaceXY(): Coordinate { return new Coordinate(this.xy_.x, this.xy_.y); } @@ -267,10 +265,10 @@ export class WorkspaceComment { */ toXmlWithXY(opt_noId?: boolean): Element { const element = this.toXml(opt_noId); - element.setAttribute('x', `${Math.round(this.xy_.x)}`); - element.setAttribute('y', `${Math.round(this.xy_.y)}`); - element.setAttribute('h', `${this.height_}`); - element.setAttribute('w', `${this.width_}`); + element.setAttribute('x', String(Math.round(this.xy_.x))); + element.setAttribute('y', String(Math.round(this.xy_.y))); + element.setAttribute('h', String(this.height_)); + element.setAttribute('w', String(this.width_)); return element; } @@ -309,9 +307,7 @@ export class WorkspaceComment { eventUtils.fire( new (eventUtils.get(eventUtils.COMMENT_CREATE))(comment)); } finally { - if (!existingGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); } } } diff --git a/core/workspace_comment_svg.ts b/core/workspace_comment_svg.ts index 9e5e96b0d..b440b0679 100644 --- a/core/workspace_comment_svg.ts +++ b/core/workspace_comment_svg.ts @@ -46,8 +46,6 @@ const TEXTAREA_OFFSET = 2; /** * Class for a workspace comment's SVG representation. - * - * @alias Blockly.WorkspaceCommentSvg */ export class WorkspaceCommentSvg extends WorkspaceComment implements IBoundedElement, IBubble, ICopyable { @@ -89,7 +87,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements private autoLayout_ = false; // Create core elements for the block. private readonly svgGroup_: SVGElement; - svgRect_: AnyDuringMigration; + svgRect_: SVGRectElement; /** Whether the comment is rendered onscreen and is a part of the DOM. */ private rendered_ = false; @@ -108,7 +106,6 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements opt_id?: string) { super(workspace, content, height, width, opt_id); this.svgGroup_ = dom.createSvgElement(Svg.G, {'class': 'blocklyComment'}); - (this.svgGroup_ as AnyDuringMigration).translate_ = ''; this.workspace = workspace; this.svgRect_ = dom.createSvgElement(Svg.RECT, { @@ -305,7 +302,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements * @returns Object with .x and .y properties in workspace coordinates. * @internal */ - getRelativeToSurfaceXY(): Coordinate { + override getRelativeToSurfaceXY(): Coordinate { let x = 0; let y = 0; @@ -313,7 +310,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements this.workspace.getBlockDragSurface()!.getGroup() : null; - let element = this.getSvgRoot(); + let element: Node|null = this.getSvgRoot(); if (element) { do { // Loop through this comment and every parent. @@ -330,9 +327,8 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements x += surfaceTranslation.x; y += surfaceTranslation.y; } - // AnyDuringMigration because: Type 'ParentNode | null' is not - // assignable to type 'SVGElement'. - element = element.parentNode as AnyDuringMigration; + + element = element.parentNode; } while (element && element !== this.workspace.getBubbleCanvas() && element !== dragSurfaceGroup); } @@ -408,13 +404,8 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements if (dragSurface) { dragSurface.translateSurface(newLoc.x, newLoc.y); } else { - (this.svgGroup_ as AnyDuringMigration).translate_ = - 'translate(' + newLoc.x + ',' + newLoc.y + ')'; - (this.svgGroup_ as AnyDuringMigration) - .setAttribute( - 'transform', - (this.svgGroup_ as AnyDuringMigration).translate_ + - (this.svgGroup_ as AnyDuringMigration).skew_); + const translation = `translate(${newLoc.x}, ${newLoc.y})`; + this.getSvgRoot().setAttribute('transform', translation); } } @@ -511,12 +502,9 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements */ setDragging(adding: boolean) { if (adding) { - const group = this.getSvgRoot(); - (group as AnyDuringMigration).translate_ = ''; - (group as AnyDuringMigration).skew_ = ''; - dom.addClass(this.svgGroup_, 'blocklyDragging'); + dom.addClass(this.getSvgRoot(), 'blocklyDragging'); } else { - dom.removeClass(this.svgGroup_, 'blocklyDragging'); + dom.removeClass(this.getSvgRoot(), 'blocklyDragging'); } } @@ -593,21 +581,11 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements } const element = this.toXml(opt_noId); const xy = this.getRelativeToSurfaceXY(); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. element.setAttribute( - 'x', - Math.round(this.workspace.RTL ? width - xy.x : xy.x) as - AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - element.setAttribute('y', Math.round(xy.y) as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - element.setAttribute('h', this.getHeight() as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - element.setAttribute('w', this.getWidth() as AnyDuringMigration); + 'x', String(Math.round(this.workspace.RTL ? width - xy.x : xy.x))); + element.setAttribute('y', String(Math.round(xy.y))); + element.setAttribute('h', String(this.getHeight())); + element.setAttribute('w', String(this.getWidth())); return element; } @@ -648,16 +626,12 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements const size = this.getHeightWidth(); // Add text area - this.createEditor_(); - // AnyDuringMigration because: Argument of type 'SVGForeignObjectElement | - // null' is not assignable to parameter of type 'Node'. - this.svgGroup_.appendChild(this.foreignObject_ as AnyDuringMigration); + const foreignObject = this.createEditor_(); + this.svgGroup_.appendChild(foreignObject); this.svgHandleTarget_ = dom.createSvgElement( Svg.RECT, {'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0}); - // AnyDuringMigration because: Argument of type 'SVGRectElement | null' is - // not assignable to parameter of type 'Node'. - this.svgGroup_.appendChild(this.svgHandleTarget_ as AnyDuringMigration); + this.svgGroup_.appendChild(this.svgHandleTarget_); this.svgRectTarget_ = dom.createSvgElement(Svg.RECT, { 'class': 'blocklyCommentTarget', 'x': 0, @@ -665,9 +639,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'rx': BORDER_RADIUS, 'ry': BORDER_RADIUS, }); - // AnyDuringMigration because: Argument of type 'SVGRectElement | null' is - // not assignable to parameter of type 'Node'. - this.svgGroup_.appendChild(this.svgRectTarget_ as AnyDuringMigration); + this.svgGroup_.appendChild(this.svgRectTarget_); // Add the resize icon this.addResizeDom_(); @@ -731,10 +703,10 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements textarea.readOnly = !this.isEditable(); body.appendChild(textarea); this.textarea_ = textarea; - this.foreignObject_!.appendChild(body); + this.foreignObject_.appendChild(body); // Don't zoom with mousewheel. browserEvents.conditionalBind( - textarea, 'wheel', this, function(e: AnyDuringMigration) { + textarea, 'wheel', this, function(e: WheelEvent) { e.stopPropagation(); }); browserEvents.conditionalBind( @@ -742,9 +714,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements function(this: WorkspaceCommentSvg, _e: Event) { this.setContent(textarea.value); }); - // AnyDuringMigration because: Type 'SVGForeignObjectElement | null' is not - // assignable to type 'Element'. - return this.foreignObject_ as AnyDuringMigration; + return this.foreignObject_; } /** Add the resize icon to the DOM */ @@ -752,14 +722,12 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements this.resizeGroup_ = dom.createSvgElement( Svg.G, {'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, this.svgGroup_); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. dom.createSvgElement( - Svg.POLYGON, - {'points': '0,x x,x x,0'.replace(/x/g, RESIZE_SIZE.toString())}, - this.resizeGroup_ as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. + Svg.POLYGON, { + 'points': + `0,${RESIZE_SIZE} ${RESIZE_SIZE},${RESIZE_SIZE} ${RESIZE_SIZE},0`, + }, + this.resizeGroup_); dom.createSvgElement( Svg.LINE, { 'class': 'blocklyResizeLine', @@ -768,9 +736,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'x2': RESIZE_SIZE - 1, 'y2': RESIZE_SIZE / 3, }, - this.resizeGroup_ as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. + this.resizeGroup_); dom.createSvgElement( Svg.LINE, { 'class': 'blocklyResizeLine', @@ -779,22 +745,18 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'x2': RESIZE_SIZE - 1, 'y2': RESIZE_SIZE * 2 / 3, }, - this.resizeGroup_ as AnyDuringMigration); + this.resizeGroup_); } /** Add the delete icon to the DOM */ private addDeleteDom_() { this.deleteGroup_ = dom.createSvgElement( Svg.G, {'class': 'blocklyCommentDeleteIcon'}, this.svgGroup_); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. this.deleteIconBorder_ = dom.createSvgElement( Svg.CIRCLE, {'class': 'blocklyDeleteIconShape', 'r': '7', 'cx': '7.5', 'cy': '7.5'}, - this.deleteGroup_ as AnyDuringMigration); + this.deleteGroup_); // x icon. - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. dom.createSvgElement( Svg.LINE, { 'x1': '5', @@ -804,9 +766,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'stroke': '#fff', 'stroke-width': '2', }, - this.deleteGroup_ as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'Element | undefined'. + this.deleteGroup_); dom.createSvgElement( Svg.LINE, { 'x1': '5', @@ -816,7 +776,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'stroke': '#fff', 'stroke-width': '2', }, - this.deleteGroup_ as AnyDuringMigration); + this.deleteGroup_); } /** @@ -927,17 +887,16 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements const topOffset = WorkspaceCommentSvg.TOP_OFFSET; const textOffset = TEXTAREA_OFFSET * 2; - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.foreignObject_!.setAttribute( - 'width', size.width as AnyDuringMigration); - this.foreignObject_!.setAttribute( - 'height', (size.height - topOffset).toString()); + this.foreignObject_?.setAttribute('width', String(size.width)); + this.foreignObject_?.setAttribute( + 'height', String(size.height - topOffset)); if (this.RTL) { - this.foreignObject_!.setAttribute('x', (-size.width).toString()); + this.foreignObject_?.setAttribute('x', String(-size.width)); } - this.textarea_!.style.width = size.width - textOffset + 'px'; - this.textarea_!.style.height = size.height - textOffset - topOffset + 'px'; + + if (!this.textarea_) return; + this.textarea_.style.width = size.width - textOffset + 'px'; + this.textarea_.style.height = size.height - textOffset - topOffset + 'px'; } /** @@ -952,24 +911,16 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements height = Math.max(height, 20 + WorkspaceCommentSvg.TOP_OFFSET); this.width_ = width; this.height_ = height; - this.svgRect_.setAttribute('width', width); - this.svgRect_.setAttribute('height', height); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.svgRectTarget_!.setAttribute('width', width as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.svgRectTarget_!.setAttribute('height', height as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.svgHandleTarget_!.setAttribute('width', width as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - this.svgHandleTarget_!.setAttribute( - 'height', WorkspaceCommentSvg.TOP_OFFSET as AnyDuringMigration); + this.svgRect_.setAttribute('width', `${width}`); + this.svgRect_.setAttribute('height', `${height}`); + this.svgRectTarget_?.setAttribute('width', `${width}`); + this.svgRectTarget_?.setAttribute('height', `${height}`); + this.svgHandleTarget_?.setAttribute('width', `${width}`); + this.svgHandleTarget_?.setAttribute( + 'height', String(WorkspaceCommentSvg.TOP_OFFSET)); if (this.RTL) { this.svgRect_.setAttribute('transform', 'scale(-1 1)'); - this.svgRectTarget_!.setAttribute('transform', 'scale(-1 1)'); + this.svgRectTarget_?.setAttribute('transform', 'scale(-1 1)'); } if (this.resizeGroup_) { @@ -979,7 +930,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'transform', 'translate(' + (-width + RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) + ') scale(-1 1)'); - this.deleteGroup_!.setAttribute( + this.deleteGroup_?.setAttribute( 'transform', 'translate(' + (-width + RESIZE_SIZE) + ',' + -RESIZE_SIZE + ') scale(-1 1)'); @@ -988,7 +939,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements 'transform', 'translate(' + (width - RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) + ')'); - this.deleteGroup_!.setAttribute( + this.deleteGroup_?.setAttribute( 'transform', 'translate(' + (width - RESIZE_SIZE) + ',' + -RESIZE_SIZE + ')'); } @@ -1094,7 +1045,7 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements eventUtils.enable(); } - WorkspaceComment.fireCreateEvent((comment)); + WorkspaceComment.fireCreateEvent(comment); return comment; } } diff --git a/core/workspace_dragger.ts b/core/workspace_dragger.ts index 686807e39..d3a50adc5 100644 --- a/core/workspace_dragger.ts +++ b/core/workspace_dragger.ts @@ -23,8 +23,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * Note that the workspace itself manages whether or not it has a drag surface * and how to do translations based on that. This simply passes the right * commands based on events. - * - * @alias Blockly.WorkspaceDragger */ export class WorkspaceDragger { private readonly horizontalScrollEnabled_: boolean; diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 06c43d682..7ac747c14 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -87,8 +87,6 @@ const ZOOM_TO_FIT_MARGIN = 20; /** * Class for a workspace. This is an onscreen area with optional trashcan, * scrollbars, bubbles, and dragging. - * - * @alias Blockly.WorkspaceSvg */ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { /** @@ -1076,13 +1074,13 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { this.cachedParentSvgSize.width = width; // This is set to support the public (but deprecated) Blockly.svgSize // method. - svg.setAttribute('data-cached-width', width.toString()); + svg.setAttribute('data-cached-width', `${width}`); } if (height != null) { this.cachedParentSvgSize.height = height; // This is set to support the public (but deprecated) Blockly.svgSize // method. - svg.setAttribute('data-cached-height', height.toString()); + svg.setAttribute('data-cached-height', `${height}`); } } @@ -1368,21 +1366,22 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { if (!existingGroup) { eventUtils.setGroup(true); } - let pastedThing; - // Checks if this is JSON. JSON has a type property, while elements don't. - if (state['type']) { - pastedThing = this.pasteBlock_(null, state as blocks.State); - } else { - const xmlBlock = state as Element; - if (xmlBlock.tagName.toLowerCase() === 'comment') { - pastedThing = this.pasteWorkspaceComment_(xmlBlock); + try { + // Checks if this is JSON. JSON has a type property, while elements don't. + if (state['type']) { + pastedThing = this.pasteBlock_(null, state as blocks.State); } else { - pastedThing = this.pasteBlock_(xmlBlock, null); + const xmlBlock = state as Element; + if (xmlBlock.tagName.toLowerCase() === 'comment') { + pastedThing = this.pasteWorkspaceComment_(xmlBlock); + } else { + pastedThing = this.pasteBlock_(xmlBlock, null); + } } + } finally { + eventUtils.setGroup(existingGroup); } - - eventUtils.setGroup(existingGroup); return pastedThing; } @@ -1892,39 +1891,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { common.setMainWorkspace(this); // We call e.preventDefault in many event handlers which means we // need to explicitly grab focus (e.g from a textarea) because - // the browser will not do it for us. How to do this is browser - // dependent. - this.setBrowserFocus(); - } - } - - /** Set the workspace to have focus in the browser. */ - private setBrowserFocus() { - // Blur whatever was focused since explicitly grabbing focus below does not - // work in Edge. - // In IE, SVGs can't be blurred or focused. Check to make sure the current - // focus can be blurred before doing so. - // See https://github.com/google/blockly/issues/4440 - if (document.activeElement && - document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - try { - // Focus the workspace SVG - this is for Chrome and Firefox. + // the browser will not do it for us. this.getParentSvg().focus({preventScroll: true}); - } catch (e) { - // IE and Edge do not support focus on SVG elements. When that fails - // above, get the injectionDiv (the workspace's parent) and focus that - // instead. This doesn't work in Chrome. - try { - // In IE11, use setActive (which is IE only) so the page doesn't scroll - // to the workspace gaining focus. - (this.getParentSvg().parentElement as any).setActive(); - } catch (e) { - // setActive support was discontinued in Edge so when that fails, call - // focus instead. - this.getParentSvg().parentElement!.focus({preventScroll: true}); - } } } @@ -2096,11 +2064,13 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { /** * Scroll the workspace to center on the given block. If the block has other - * blocks stacked below it, the workspace will be centered on the stack. + * blocks stacked below it, the workspace will be centered on the stack, + * unless blockOnly is true. * * @param id ID of block center on. + * @param blockOnly True to center only on the block itself, not its stack. */ - centerOnBlock(id: string|null) { + centerOnBlock(id: string|null, blockOnly?: boolean) { if (!this.isMovable()) { console.warn( 'Tried to move a non-movable workspace. This could result' + @@ -2116,7 +2086,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { // XY is in workspace coordinates. const xy = block.getRelativeToSurfaceXY(); // Height/width is in workspace units. - const heightWidth = block.getHeightWidth(); + const heightWidth = blockOnly ? {height: block.height, width: block.width} : + block.getHeightWidth(); // Find the enter of the block in workspace units. const blockCenterY = xy.y + heightWidth.height / 2; @@ -2588,7 +2559,6 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * scrollbars accordingly. * * @param workspace The workspace to resize. - * @alias Blockly.WorkspaceSvg.resizeSvgContents * @internal */ export function resizeSvgContents(workspace: WorkspaceSvg) { diff --git a/core/xml.ts b/core/xml.ts index 4ecde7780..ffc2f2bfc 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -4,17 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * XML reader and writer. - * - * @namespace Blockly.Xml - */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.Xml'); import type {Block} from './block.js'; import type {BlockSvg} from './block_svg.js'; import type {Connection} from './connection.js'; +import * as deprecation from './utils/deprecation.js'; import * as eventUtils from './events/utils.js'; import type {Field} from './field.js'; import {inputTypes} from './input_types.js'; @@ -35,7 +31,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; * @param workspace The workspace containing blocks. * @param opt_noId True if the encoder should skip the block IDs. * @returns XML DOM element. - * @alias Blockly.Xml.workspaceToDom */ export function workspaceToDom( workspace: Workspace, opt_noId?: boolean): Element { @@ -63,7 +58,6 @@ export function workspaceToDom( * * @param variableList List of all variable models. * @returns Tree of XML elements. - * @alias Blockly.Xml.variablesToDom */ export function variablesToDom(variableList: VariableModel[]): Element { const variables = utilsXml.createElement('variables'); @@ -87,7 +81,6 @@ export function variablesToDom(variableList: VariableModel[]): Element { * @param opt_noId True if the encoder should skip the block ID. * @returns Tree of XML elements or an empty document fragment if the block was * an insertion marker. - * @alias Blockly.Xml.blockToDomWithXY */ export function blockToDomWithXY(block: Block, opt_noId?: boolean): Element| DocumentFragment { @@ -105,14 +98,12 @@ export function blockToDomWithXY(block: Block, opt_noId?: boolean): Element| } const element = blockToDom(block, opt_noId); - const xy = block.getRelativeToSurfaceXY(); - // AnyDuringMigration because: Property 'setAttribute' does not exist on type - // 'Element | DocumentFragment'. - (element as AnyDuringMigration) - .setAttribute('x', Math.round(block.workspace.RTL ? width - xy.x : xy.x)); - // AnyDuringMigration because: Property 'setAttribute' does not exist on type - // 'Element | DocumentFragment'. - (element as AnyDuringMigration).setAttribute('y', Math.round(xy.y)); + if (isElement(element)) { + const xy = block.getRelativeToSurfaceXY(); + element.setAttribute( + 'x', String(Math.round(block.workspace.RTL ? width - xy.x : xy.x))); + element.setAttribute('y', String(Math.round(xy.y))); + } return element; } @@ -158,7 +149,6 @@ function allFieldsToDom(block: Block, element: Element) { * @param opt_noId True if the encoder should skip the block ID. * @returns Tree of XML elements or an empty document fragment if the block was * an insertion marker. - * @alias Blockly.Xml.blockToDom */ export function blockToDom(block: Block, opt_noId?: boolean): Element| DocumentFragment { @@ -176,9 +166,7 @@ export function blockToDom(block: Block, opt_noId?: boolean): Element| const element = utilsXml.createElement(block.isShadow() ? 'shadow' : 'block'); element.setAttribute('type', block.type); if (!opt_noId) { - // It's important to use setAttribute here otherwise IE11 won't serialize - // the block's ID when domToText is called. - element.setAttribute('id', block.id); + element.id = block.id; } if (block.mutationToDom) { // Custom data for an advanced block. @@ -197,15 +185,9 @@ export function blockToDom(block: Block, opt_noId?: boolean): Element| const commentElement = utilsXml.createElement('comment'); commentElement.appendChild(utilsXml.createTextNode(commentText)); - // AnyDuringMigration because: Argument of type 'boolean' is not assignable - // to parameter of type 'string'. - commentElement.setAttribute('pinned', pinned as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - commentElement.setAttribute('h', size.height as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'number' is not assignable - // to parameter of type 'string'. - commentElement.setAttribute('w', size.width as AnyDuringMigration); + commentElement.setAttribute('pinned', `${pinned}`); + commentElement.setAttribute('h', String(size.height)); + commentElement.setAttribute('w', String(size.width)); element.appendChild(commentElement); } @@ -248,7 +230,7 @@ export function blockToDom(block: Block, opt_noId?: boolean): Element| } if (block.inputsInline !== undefined && block.inputsInline !== block.inputsInlineDefault) { - element.setAttribute('inline', block.inputsInline.toString()); + element.setAttribute('inline', String(block.inputsInline)); } if (block.isCollapsed()) { element.setAttribute('collapsed', 'true'); @@ -337,7 +319,6 @@ function cloneShadow(shadow: Element, opt_noId?: boolean): Element { * * @param dom A tree of XML nodes. * @returns Text representation. - * @alias Blockly.Xml.domToText */ export function domToText(dom: Node): string { const text = utilsXml.domToText(dom); @@ -351,7 +332,6 @@ export function domToText(dom: Node): string { * * @param dom A tree of XML elements. * @returns Text representation. - * @alias Blockly.Xml.domToPrettyText */ export function domToPrettyText(dom: Node): string { // This function is not guaranteed to be correct for all XML. @@ -386,15 +366,13 @@ export function domToPrettyText(dom: Node): string { * @returns A DOM object representing the singular child of the document * element. * @throws if the text doesn't parse. - * @alias Blockly.Xml.textToDom + * @deprecated Moved to core/utils/xml.js. */ export function textToDom(text: string): Element { - const doc = utilsXml.textToDomDocument(text); - if (!doc || !doc.documentElement || - doc.getElementsByTagName('parsererror').length) { - throw Error('textToDom was unable to parse: ' + text); - } - return doc.documentElement; + deprecation.warn( + 'Blockly.Xml.textToDom', 'version 9', 'version 10', + 'Use Blockly.utils.xml.textToDom instead'); + return utilsXml.textToDom(text); } /** @@ -404,15 +382,12 @@ export function textToDom(text: string): Element { * @param xml XML DOM. * @param workspace The workspace. * @returns An array containing new block IDs. - * @alias Blockly.Xml.clearWorkspaceAndLoadFromXml */ export function clearWorkspaceAndLoadFromXml( xml: Element, workspace: WorkspaceSvg): string[] { workspace.setResizesEnabled(false); workspace.clear(); - // AnyDuringMigration because: Argument of type 'WorkspaceSvg' is not - // assignable to parameter of type 'Workspace'. - const blockIds = domToWorkspace(xml, workspace as AnyDuringMigration); + const blockIds = domToWorkspace(xml, workspace); workspace.setResizesEnabled(true); return blockIds; } @@ -425,7 +400,6 @@ export function clearWorkspaceAndLoadFromXml( * @returns An array containing new block IDs. * @suppress {strictModuleDepCheck} Suppress module check while workspace * comments are not bundled in. - * @alias Blockly.Xml.domToWorkspace */ export function domToWorkspace(xml: Element, workspace: Workspace): string[] { let width = 0; // Not used in LTR. @@ -456,16 +430,8 @@ export function domToWorkspace(xml: Element, workspace: Workspace): string[] { // to be moved to a nested destination in the next operation. const block = domToBlock(xmlChildElement, workspace); newBlockIds.push(block.id); - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - const blockX = xmlChildElement.hasAttribute('x') ? - parseInt(xmlChildElement.getAttribute('x') as AnyDuringMigration) : - 10; - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - const blockY = xmlChildElement.hasAttribute('y') ? - parseInt(xmlChildElement.getAttribute('y') as AnyDuringMigration) : - 10; + const blockX = parseInt(xmlChildElement.getAttribute('x') ?? '10', 10); + const blockY = parseInt(xmlChildElement.getAttribute('y') ?? '10', 10); if (!isNaN(blockX) && !isNaN(blockY)) { block.moveBy(workspace.RTL ? width - blockX : blockX, blockY); } @@ -492,9 +458,7 @@ export function domToWorkspace(xml: Element, workspace: Workspace): string[] { } } } finally { - if (!existingGroup) { - eventUtils.setGroup(false); - } + eventUtils.setGroup(existingGroup); dom.stopTextWidthCache(); } // Re-enable workspace resizing. @@ -512,7 +476,6 @@ export function domToWorkspace(xml: Element, workspace: Workspace): string[] { * @param xml The XML DOM. * @param workspace The workspace to add to. * @returns An array containing new block IDs. - * @alias Blockly.Xml.appendDomToWorkspace */ export function appendDomToWorkspace( xml: Element, workspace: WorkspaceSvg): string[] { @@ -566,7 +529,6 @@ export function appendDomToWorkspace( * @param xmlBlock XML block element. * @param workspace The workspace. * @returns The root block created. - * @alias Blockly.Xml.domToBlock */ export function domToBlock(xmlBlock: Element, workspace: Workspace): Block { // Create top-level block. @@ -608,8 +570,6 @@ export function domToBlock(xmlBlock: Element, workspace: Workspace): Block { eventUtils.enable(); } if (eventUtils.isEnabled()) { - // AnyDuringMigration because: Property 'get' does not exist on type - // '(name: string) => void'. const newVariables = Variables.getAddedVariables(workspace, variablesBeforeCreation); // Fire a VarCreate event for each (if any) new variable created. @@ -630,7 +590,6 @@ export function domToBlock(xmlBlock: Element, workspace: Workspace): Block { * * @param xmlVariables List of XML variable elements. * @param workspace The workspace to which the variable should be added. - * @alias Blockly.Xml.domToVariables */ export function domToVariables(xmlVariables: Element, workspace: Workspace) { for (let i = 0; i < xmlVariables.children.length; i++) { @@ -639,9 +598,8 @@ export function domToVariables(xmlVariables: Element, workspace: Workspace) { const id = xmlChild.getAttribute('id'); const name = xmlChild.textContent; - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - workspace.createVariable(name as AnyDuringMigration, type, id); + if (!name) return; + workspace.createVariable(name, type, id); } } @@ -743,12 +701,8 @@ function applyCommentTagNodes(xmlChildren: Element[], block: Block) { const xmlChild = xmlChildren[i]; const text = xmlChild.textContent; const pinned = xmlChild.getAttribute('pinned') === 'true'; - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - const width = parseInt(xmlChild.getAttribute('w') as AnyDuringMigration); - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - const height = parseInt(xmlChild.getAttribute('h') as AnyDuringMigration); + const width = parseInt(xmlChild.getAttribute('w') ?? '50', 10); + const height = parseInt(xmlChild.getAttribute('h') ?? '50', 10); block.setCommentText(text); block.commentModel.pinned = pinned; @@ -788,9 +742,11 @@ function applyFieldTagNodes(xmlChildren: Element[], block: Block) { for (let i = 0; i < xmlChildren.length; i++) { const xmlChild = xmlChildren[i]; const nodeName = xmlChild.getAttribute('name'); - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - domToField(block, nodeName as AnyDuringMigration, xmlChild); + if (!nodeName) { + console.warn(`Ignoring unnamed field in block ${block.type}`); + continue; + } + domToField(block, nodeName, xmlChild); } } @@ -802,24 +758,19 @@ function applyFieldTagNodes(xmlChildren: Element[], block: Block) { */ function findChildBlocks(xmlNode: Element): {childBlockElement: Element|null, childShadowElement: Element|null} { - const childBlockInfo = {childBlockElement: null, childShadowElement: null}; + let childBlockElement: Element|null = null; + let childShadowElement: Element|null = null; for (let i = 0; i < xmlNode.childNodes.length; i++) { const xmlChild = xmlNode.childNodes[i]; - if (xmlChild.nodeType === dom.NodeType.ELEMENT_NODE) { + if (isElement(xmlChild)) { if (xmlChild.nodeName.toLowerCase() === 'block') { - // AnyDuringMigration because: Type 'Element' is not assignable to type - // 'null'. - childBlockInfo.childBlockElement = - xmlChild as Element as AnyDuringMigration; + childBlockElement = xmlChild; } else if (xmlChild.nodeName.toLowerCase() === 'shadow') { - // AnyDuringMigration because: Type 'Element' is not assignable to type - // 'null'. - childBlockInfo.childShadowElement = - xmlChild as Element as AnyDuringMigration; + childShadowElement = xmlChild; } } } - return childBlockInfo; + return {childBlockElement, childShadowElement}; } /** * Applies input child nodes (value or statement) to the given block. @@ -835,9 +786,7 @@ function applyInputTagNodes( for (let i = 0; i < xmlChildren.length; i++) { const xmlChild = xmlChildren[i]; const nodeName = xmlChild.getAttribute('name'); - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string'. - const input = block.getInput(nodeName as AnyDuringMigration); + const input = nodeName ? block.getInput(nodeName) : null; if (!input) { console.warn( 'Ignoring non-existent input ' + nodeName + ' in block ' + @@ -911,10 +860,8 @@ function domToBlockHeadless( if (!prototypeName) { throw TypeError('Block type unspecified: ' + xmlBlock.outerHTML); } - const id = xmlBlock.getAttribute('id'); - // AnyDuringMigration because: Argument of type 'string | null' is not - // assignable to parameter of type 'string | undefined'. - block = workspace.newBlock(prototypeName, id as AnyDuringMigration); + const id = xmlBlock.getAttribute('id') ?? undefined; + block = workspace.newBlock(prototypeName, id); // Preprocess childNodes so tags can be processed in a consistent order. const xmlChildNameMap = mapSupportedXmlTags(xmlBlock); @@ -1020,7 +967,6 @@ function domToField(block: Block, fieldName: string, xml: Element) { * * @param xmlBlock XML block element or an empty DocumentFragment if the block * was an insertion marker. - * @alias Blockly.Xml.deleteNext */ export function deleteNext(xmlBlock: Element|DocumentFragment) { for (let i = 0; i < xmlBlock.childNodes.length; i++) { @@ -1031,3 +977,7 @@ export function deleteNext(xmlBlock: Element|DocumentFragment) { } } } + +function isElement(node: Node): node is Element { + return node.nodeType === dom.NodeType.ELEMENT_NODE; +} diff --git a/core/zoom_controls.ts b/core/zoom_controls.ts index b25ff4a85..5ae63f8a5 100644 --- a/core/zoom_controls.ts +++ b/core/zoom_controls.ts @@ -33,8 +33,6 @@ import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class for a zoom controls. - * - * @alias Blockly.ZoomControls */ export class ZoomControls implements IPositionable { /** @@ -44,22 +42,11 @@ export class ZoomControls implements IPositionable { id = 'zoomControls'; /** - * A handle to use to unbind the mouse down event handler for zoom reset - * button. Opaque data returned from browserEvents.conditionalBind. + * Array holding info needed to unbind events. + * Used for disposing. + * Ex: [[node, name, func], [node, name, func]]. */ - private onZoomResetWrapper: browserEvents.Data|null = null; - - /** - * A handle to use to unbind the mouse down event handler for zoom in - * button. Opaque data returned from browserEvents.conditionalBind. - */ - private onZoomInWrapper: browserEvents.Data|null = null; - - /** - * A handle to use to unbind the mouse down event handler for zoom out - * button. Opaque data returned from browserEvents.conditionalBind. - */ - private onZoomOutWrapper: browserEvents.Data|null = null; + private boundEvents: browserEvents.Data[] = []; /** The zoom in svg element. */ private zoomInGroup: SVGGElement|null = null; @@ -146,15 +133,10 @@ export class ZoomControls implements IPositionable { if (this.svgGroup) { dom.removeNode(this.svgGroup); } - if (this.onZoomResetWrapper) { - browserEvents.unbind(this.onZoomResetWrapper); - } - if (this.onZoomInWrapper) { - browserEvents.unbind(this.onZoomInWrapper); - } - if (this.onZoomOutWrapper) { - browserEvents.unbind(this.onZoomOutWrapper); + for (const event of this.boundEvents) { + browserEvents.unbind(event); } + this.boundEvents.length = 0; } /** @@ -275,8 +257,8 @@ export class ZoomControls implements IPositionable { this.workspace.options.pathToMedia + SPRITE.url); // Attach listener. - this.onZoomOutWrapper = browserEvents.conditionalBind( - this.zoomOutGroup, 'pointerdown', null, this.zoom.bind(this, -1)); + this.boundEvents.push(browserEvents.conditionalBind( + this.zoomOutGroup, 'pointerdown', null, this.zoom.bind(this, -1))); } /** @@ -321,8 +303,8 @@ export class ZoomControls implements IPositionable { this.workspace.options.pathToMedia + SPRITE.url); // Attach listener. - this.onZoomInWrapper = browserEvents.conditionalBind( - this.zoomInGroup, 'pointerdown', null, this.zoom.bind(this, 1)); + this.boundEvents.push(browserEvents.conditionalBind( + this.zoomInGroup, 'pointerdown', null, this.zoom.bind(this, 1))); } /** @@ -379,8 +361,8 @@ export class ZoomControls implements IPositionable { this.workspace.options.pathToMedia + SPRITE.url); // Attach event listeners. - this.onZoomResetWrapper = browserEvents.conditionalBind( - this.zoomResetGroup, 'pointerdown', null, this.resetZoom.bind(this)); + this.boundEvents.push(browserEvents.conditionalBind( + this.zoomResetGroup, 'pointerdown', null, this.resetZoom.bind(this))); } /** diff --git a/demos/blockfactory/analytics.js b/demos/blockfactory/analytics.js index 6febb8858..5611c09a9 100644 --- a/demos/blockfactory/analytics.js +++ b/demos/blockfactory/analytics.js @@ -171,8 +171,7 @@ BlocklyDevTools.Analytics.onExport = function(typeId, optMetadata) { */ BlocklyDevTools.Analytics.onError = function(e) { // stub - this.LOG_TO_CONSOLE_ && - console.log('Analytics.onError("' + e.toString() + '")'); + this.LOG_TO_CONSOLE_ && console.log('Analytics.onError("' + e + '")'); }; /** diff --git a/demos/blockfactory/app_controller.js b/demos/blockfactory/app_controller.js index 7fe4a11c9..5698033fe 100644 --- a/demos/blockfactory/app_controller.js +++ b/demos/blockfactory/app_controller.js @@ -138,7 +138,7 @@ AppController.prototype.formatBlockLibraryForExport_ = function(blockXmlMap) { // Append each block node to XML DOM. for (var blockType in blockXmlMap) { - var blockXmlDom = Blockly.Xml.textToDom(blockXmlMap[blockType]); + var blockXmlDom = Blockly.utils.xml.textToDom(blockXmlMap[blockType]); var blockNode = blockXmlDom.firstElementChild; xmlDom.appendChild(blockNode); } @@ -155,7 +155,7 @@ AppController.prototype.formatBlockLibraryForExport_ = function(blockXmlMap) { * @private */ AppController.prototype.formatBlockLibraryForImport_ = function(xmlText) { - var inputXml = Blockly.Xml.textToDom(xmlText); + var inputXml = Blockly.utils.xml.textToDom(xmlText); // Convert the live HTMLCollection of child Elements into a static array, // since the addition to editorWorkspaceXml below removes it from inputXml. var inputChildren = Array.from(inputXml.children); @@ -192,7 +192,7 @@ AppController.prototype.formatBlockLibraryForImport_ = function(xmlText) { * @private */ AppController.prototype.getBlockTypeFromXml_ = function(xmlText) { - var xmlDom = Blockly.Xml.textToDom(xmlText); + var xmlDom = Blockly.utils.xml.textToDom(xmlText); // Find factory base block. var factoryBaseBlockXml = xmlDom.getElementsByTagName('block')[0]; // Get field elements from factory base. diff --git a/demos/blockfactory/block_definition_extractor.js b/demos/blockfactory/block_definition_extractor.js index ef791a224..35186ac84 100644 --- a/demos/blockfactory/block_definition_extractor.js +++ b/demos/blockfactory/block_definition_extractor.js @@ -17,7 +17,6 @@ * * The exampleBlocklyBlock is usually the block loaded into the * preview workspace after manually entering the block definition. - * */ 'use strict'; diff --git a/demos/blockfactory/block_exporter_controller.js b/demos/blockfactory/block_exporter_controller.js index 66e7c61fe..bd41f2e74 100644 --- a/demos/blockfactory/block_exporter_controller.js +++ b/demos/blockfactory/block_exporter_controller.js @@ -9,7 +9,6 @@ * users to export block definitions and generator stubs of their saved blocks * easily using a visual interface. Depends on Block Exporter View and Block * Exporter Tools classes. Interacts with Export Settings in the index.html. - * */ 'use strict'; diff --git a/demos/blockfactory/block_exporter_tools.js b/demos/blockfactory/block_exporter_tools.js index bec5e86b2..58da9be1a 100644 --- a/demos/blockfactory/block_exporter_tools.js +++ b/demos/blockfactory/block_exporter_tools.js @@ -9,7 +9,6 @@ * block definitions and generator stubs for given block types. Also generates * toolbox XML for the exporter's workspace. Depends on the FactoryUtils for * its code generation functions. - * */ 'use strict'; diff --git a/demos/blockfactory/block_exporter_view.js b/demos/blockfactory/block_exporter_view.js index 6c2562a55..aa840e59d 100644 --- a/demos/blockfactory/block_exporter_view.js +++ b/demos/blockfactory/block_exporter_view.js @@ -7,7 +7,6 @@ /** * @fileoverview Javascript for the Block Exporter View class. Reads from and * manages a block selector through which users select blocks to export. - * */ 'use strict'; diff --git a/demos/blockfactory/block_library_controller.js b/demos/blockfactory/block_library_controller.js index 25d50726e..2192a7bdd 100644 --- a/demos/blockfactory/block_library_controller.js +++ b/demos/blockfactory/block_library_controller.js @@ -13,7 +13,6 @@ * - delete blocks * - clear their block library * Depends on BlockFactory functions defined in factory.js. - * */ 'use strict'; diff --git a/demos/blockfactory/block_library_storage.js b/demos/blockfactory/block_library_storage.js index dc19ce64f..c843ae542 100644 --- a/demos/blockfactory/block_library_storage.js +++ b/demos/blockfactory/block_library_storage.js @@ -7,7 +7,6 @@ /** * @fileoverview Javascript for Block Library's Storage Class. * Depends on Block Library for its namespace. - * */ 'use strict'; @@ -90,7 +89,7 @@ BlockLibraryStorage.prototype.removeBlock = function(blockType) { BlockLibraryStorage.prototype.getBlockXml = function(blockType) { var xml = this.blocks[blockType] || null; if (xml) { - var xml = Blockly.Xml.textToDom(xml); + var xml = Blockly.utils.xml.textToDom(xml); } return xml; }; diff --git a/demos/blockfactory/block_library_view.js b/demos/blockfactory/block_library_view.js index 2a47dcd0f..a47980408 100644 --- a/demos/blockfactory/block_library_view.js +++ b/demos/blockfactory/block_library_view.js @@ -7,7 +7,6 @@ /** * @fileoverview Javascript for BlockLibraryView class. It manages the display * of the Block Library dropdown, save, and delete buttons. - * */ 'use strict'; diff --git a/demos/blockfactory/block_option.js b/demos/blockfactory/block_option.js index efc308834..184c3c235 100644 --- a/demos/blockfactory/block_option.js +++ b/demos/blockfactory/block_option.js @@ -9,7 +9,6 @@ * of the various blocks that you may select in the Block Selector. Each block * option has a checkbox, a label, and a preview workspace through which to * view the block. - * */ 'use strict'; diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js index 6acdbee82..a77d8467a 100644 --- a/demos/blockfactory/factory.js +++ b/demos/blockfactory/factory.js @@ -10,7 +10,6 @@ * generate a preview block and starter code for the block (block definition and * generator stub. Uses the Block Factory namespace. Depends on the FactoryUtils * for its code generation functions. - * */ 'use strict'; @@ -305,7 +304,7 @@ BlockFactory.disableEnableLink = function() { */ BlockFactory.showStarterBlock = function() { BlockFactory.mainWorkspace.clear(); - var xml = Blockly.Xml.textToDom(BlockFactory.STARTER_BLOCK_XML_TEXT); + var xml = Blockly.utils.xml.textToDom(BlockFactory.STARTER_BLOCK_XML_TEXT); Blockly.Xml.domToWorkspace(xml, BlockFactory.mainWorkspace); }; diff --git a/demos/blockfactory/standard_categories.js b/demos/blockfactory/standard_categories.js index eefadf2b9..c0e82d503 100644 --- a/demos/blockfactory/standard_categories.js +++ b/demos/blockfactory/standard_categories.js @@ -10,7 +10,6 @@ * the lower case name of the category, and contains the Category object for * that particular category. Also has a list of core block types provided * by Blockly. - * */ 'use strict'; @@ -27,7 +26,7 @@ StandardCategories.categoryMap = Object.create(null); StandardCategories.categoryMap['logic'] = new ListElement(ListElement.TYPE_CATEGORY, 'Logic'); StandardCategories.categoryMap['logic'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -42,7 +41,7 @@ StandardCategories.categoryMap['logic'].hue = 210; StandardCategories.categoryMap['loops'] = new ListElement(ListElement.TYPE_CATEGORY, 'Loops'); StandardCategories.categoryMap['loops'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -77,7 +76,7 @@ StandardCategories.categoryMap['loops'].hue = 120; StandardCategories.categoryMap['math'] = new ListElement(ListElement.TYPE_CATEGORY, 'Math'); StandardCategories.categoryMap['math'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -170,7 +169,7 @@ StandardCategories.categoryMap['math'].hue = 230; StandardCategories.categoryMap['text'] = new ListElement(ListElement.TYPE_CATEGORY, 'Text'); StandardCategories.categoryMap['text'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -253,7 +252,7 @@ StandardCategories.categoryMap['text'].hue = 160; StandardCategories.categoryMap['lists'] = new ListElement(ListElement.TYPE_CATEGORY, 'Lists'); StandardCategories.categoryMap['lists'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -310,7 +309,7 @@ StandardCategories.categoryMap['lists'].hue = 260; StandardCategories.categoryMap['colour'] = new ListElement(ListElement.TYPE_CATEGORY, 'Colour'); StandardCategories.categoryMap['colour'].xml = - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + diff --git a/demos/blockfactory/workspacefactory/wfactory_controller.js b/demos/blockfactory/workspacefactory/wfactory_controller.js index 73a2a4b41..385feede8 100644 --- a/demos/blockfactory/workspacefactory/wfactory_controller.js +++ b/demos/blockfactory/workspacefactory/wfactory_controller.js @@ -16,7 +16,6 @@ * - updating the preview workspace * - changing a category name * - moving the position of a category. - * */ /** @@ -702,7 +701,7 @@ WorkspaceFactoryController.prototype.importFile = function(file, importMode) { // Try to parse XML from file and load it into toolbox editing area. // Print error message if fail. try { - var tree = Blockly.Xml.textToDom(reader.result); + var tree = Blockly.utils.xml.textToDom(reader.result); if (importMode === WorkspaceFactoryController.MODE_TOOLBOX) { // Switch mode. controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); diff --git a/demos/blockfactory/workspacefactory/wfactory_generator.js b/demos/blockfactory/workspacefactory/wfactory_generator.js index 02a1fa43e..ca1a47b09 100644 --- a/demos/blockfactory/workspacefactory/wfactory_generator.js +++ b/demos/blockfactory/workspacefactory/wfactory_generator.js @@ -10,7 +10,6 @@ * Blockly.Xml and depends on information in the model (holds a reference). * Depends on a hidden workspace created in the generator to load saved XML in * order to generate toolbox XML. - * */ diff --git a/demos/blockfactory/workspacefactory/wfactory_init.js b/demos/blockfactory/workspacefactory/wfactory_init.js index c04f451a9..352c1d220 100644 --- a/demos/blockfactory/workspacefactory/wfactory_init.js +++ b/demos/blockfactory/workspacefactory/wfactory_init.js @@ -9,7 +9,6 @@ * Adds click handlers to buttons and dropdowns, adds event listeners for * keydown events and Blockly events, and configures the initial setup of * the page. - * */ /** diff --git a/demos/blockfactory/workspacefactory/wfactory_model.js b/demos/blockfactory/workspacefactory/wfactory_model.js index 4b871ccf6..9b9586ea1 100644 --- a/demos/blockfactory/workspacefactory/wfactory_model.js +++ b/demos/blockfactory/workspacefactory/wfactory_model.js @@ -12,7 +12,6 @@ * move categories easily. Keeps track of the currently selected list * element. Also keeps track of all the user-created shadow blocks and * manipulates them as necessary. - * */ /** diff --git a/demos/blockfactory_old/factory.js b/demos/blockfactory_old/factory.js index 67be0de54..7ac395032 100644 --- a/demos/blockfactory_old/factory.js +++ b/demos/blockfactory_old/factory.js @@ -799,7 +799,7 @@ function init() { mainWorkspace); } else { var xml = ''; - Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), mainWorkspace); + Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom(xml), mainWorkspace); } mainWorkspace.clearUndo(); diff --git a/demos/code/code.js b/demos/code/code.js index b7459a5f4..7752e6763 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -127,11 +127,11 @@ Code.loadBlocks = function(defaultXml) { } else if (loadOnce) { // Language switching stores the blocks during the reload. delete window.sessionStorage.loadOnceBlocks; - var xml = Blockly.Xml.textToDom(loadOnce); + var xml = Blockly.utils.xml.textToDom(loadOnce); Blockly.Xml.domToWorkspace(xml, Code.workspace); } else if (defaultXml) { // Load the editor with default starting blocks. - var xml = Blockly.Xml.textToDom(defaultXml); + var xml = Blockly.utils.xml.textToDom(defaultXml); Blockly.Xml.domToWorkspace(xml, Code.workspace); } else if ('BlocklyStorage' in window) { // Restore saved blocks in a separate thread so that subsequent @@ -264,7 +264,7 @@ Code.tabClick = function(clickedName) { var xmlText = xmlTextarea.value; var xmlDom = null; try { - xmlDom = Blockly.Xml.textToDom(xmlText); + xmlDom = Blockly.utils.xml.textToDom(xmlText); } catch (e) { var q = window.confirm( MSG['parseError'].replace(/%1/g, 'XML').replace('%2', e)); @@ -459,7 +459,7 @@ Code.init = function() { var toolboxText = document.getElementById('toolbox').outerHTML; toolboxText = toolboxText.replace(/(^|[^%]){(\w+)}/g, function(m, p1, p2) {return p1 + MSG[p2];}); - var toolboxXml = Blockly.Xml.textToDom(toolboxText); + var toolboxXml = Blockly.utils.xml.textToDom(toolboxText); Code.workspace = Blockly.inject('content_blocks', {grid: diff --git a/demos/minimap/minimap.js b/demos/minimap/minimap.js index dd24a623c..a4343899a 100644 --- a/demos/minimap/minimap.js +++ b/demos/minimap/minimap.js @@ -198,7 +198,7 @@ Minimap.scaleMinimap = function() { var workspaceMetrics = Minimap.workspace.getMetrics(); var minimapMetrics = Minimap.minimap.getMetrics(); - // Scaling the mimimap such that all the blocks can be seen in the viewport. + // Scaling the minimap such that all the blocks can be seen in the viewport. // This padding is default because this is how to scrollbar(in main workspace) // is implemented. var topPadding = (workspaceMetrics.viewHeight) * Minimap.minimap.scale / diff --git a/generators/javascript/lists.js b/generators/javascript/lists.js index a614f2a0c..c2845d439 100644 --- a/generators/javascript/lists.js +++ b/generators/javascript/lists.js @@ -356,9 +356,9 @@ function ${JavaScript.FUNCTION_NAME_PLACEHOLDER_}(type, direction) { 'NUMERIC': function(a, b) { return Number(a) - Number(b); }, 'TEXT': function(a, b) { - return a.toString() > b.toString() ? 1 : -1; }, + return String(a) > String(b) ? 1 : -1; }, 'IGNORE_CASE': function(a, b) { - return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; }, + return String(a).toLowerCase() > String(b).toLowerCase() ? 1 : -1; }, }; var compare = compareFuncs[type]; return function(a, b) { return compare(a, b) * direction; }; diff --git a/gulpfile.js b/gulpfile.js index e2e41762f..0bad4309f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -40,7 +40,7 @@ module.exports = { deployDemosBeta: appengineTasks.deployDemosBeta, gitUpdateGithubPages: gitTasks.updateGithubPages, - // Manually-invokable targets, with prequisites where required. + // Manually-invokable targets, with prerequisites where required. format: buildTasks.format, messages: buildTasks.messages, // Generate msg/json/en.json et al. sortRequires: cleanupTasks.sortRequires, diff --git a/msg/json/bn.json b/msg/json/bn.json index 6590d6f3c..3b5491165 100644 --- a/msg/json/bn.json +++ b/msg/json/bn.json @@ -2,6 +2,7 @@ "@metadata": { "authors": [ "Aftabuzzaman", + "Aishik Rehman", "MasterMinhaz", "Rakibul", "Rasal Lia", @@ -15,8 +16,8 @@ "TODAY": "আজ", "DUPLICATE_BLOCK": "প্রতিলিপি", "ADD_COMMENT": "মন্তব্য যোগ করুন", - "REMOVE_COMMENT": "মন্তব্য সরাও", - "EXTERNAL_INPUTS": "বহি:স্থ ইনপুট", + "REMOVE_COMMENT": "মন্তব্য সরান", + "EXTERNAL_INPUTS": "বহিস্থ ইনপুট", "INLINE_INPUTS": "সারি ইনপুট", "DELETE_BLOCK": "ব্লকটি মুছে ফেল", "DELETE_X_BLOCKS": "%1 ব্লক অপসারণ কর", diff --git a/msg/json/bs.json b/msg/json/bs.json index ba09f5324..f561d647a 100644 --- a/msg/json/bs.json +++ b/msg/json/bs.json @@ -78,15 +78,22 @@ "CONTROLS_IF_MSG_IF": "ako", "CONTROLS_IF_MSG_ELSEIF": "inače ako", "CONTROLS_IF_MSG_ELSE": "inače", + "CONTROLS_IF_IF_TOOLTIP": "Dodaj, ukloni ili promijeni redoslijed sekcija kako bi ponovo konfigurisali ovaj if blok.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Dodajte uslov bloku \"ako\".", + "CONTROLS_IF_ELSE_TOOLTIP": "Dodaj konačni, sveobuhvatni uvjet u if blok.", "LOGIC_COMPARE_HELPURL": "https://bs.wikipedia.org/wiki/Nejednakost", "LOGIC_COMPARE_TOOLTIP_EQ": "Vraća tačno ako su oba ulaza jednaka jedan drugom.", + "LOGIC_COMPARE_TOOLTIP_NEQ": "Vraća tačno ako su oba ulaza jednaka jedan drugom.", "LOGIC_COMPARE_TOOLTIP_LT": "Vraća tačno ako je prvi ulaz manji od drugog ulaza.", + "LOGIC_COMPARE_TOOLTIP_LTE": "Vraća tačno ako je prvi ulaz manji ili jednak drugom ulazu.", "LOGIC_COMPARE_TOOLTIP_GT": "Vraća tačno ako je prvi ulaz veći od drugog ulaza.", + "LOGIC_COMPARE_TOOLTIP_GTE": "Vraća tačno ako je prvi ulaz veći ili jednak drugom ulazu.", "LOGIC_OPERATION_TOOLTIP_AND": "Vraća tačno ako su oba ulaza tačna.", "LOGIC_OPERATION_AND": "i", + "LOGIC_OPERATION_TOOLTIP_OR": "Vrati tačno ako je barem jedan od ulaza istinit.", "LOGIC_OPERATION_OR": "ili", "LOGIC_NEGATE_TITLE": "nije %1", + "LOGIC_NEGATE_TOOLTIP": "Vraća tačno ako je unos netačan. Vraća netačno ako je unos tačan.", "LOGIC_BOOLEAN_TRUE": "tačno", "LOGIC_BOOLEAN_FALSE": "netačno", "LOGIC_BOOLEAN_TOOLTIP": "Vraća ili tačno ili netačno.", diff --git a/msg/json/de.json b/msg/json/de.json index 8d1d0d631..cace0b548 100644 --- a/msg/json/de.json +++ b/msg/json/de.json @@ -55,7 +55,7 @@ "CANNOT_DELETE_VARIABLE_PROCEDURE": "Die Variable „%1“ kann nicht gelöscht werden, da sie Teil der Definition der Funktion „%2“ ist.", "DELETE_VARIABLE": "Die Variable „%1“ löschen", "COLOUR_PICKER_HELPURL": "https://de.wikipedia.org/wiki/Farbe", - "COLOUR_PICKER_TOOLTIP": "Wählt eine Farbe aus der Palette aus.", + "COLOUR_PICKER_TOOLTIP": "Wähle eine Farbe aus der Palette.", "COLOUR_RANDOM_TITLE": "zufällige Farbe", "COLOUR_RANDOM_TOOLTIP": "Erzeugt eine Farbe nach dem Zufallsprinzip.", "COLOUR_RGB_TITLE": "Farbe aus", diff --git a/msg/json/fi.json b/msg/json/fi.json index 6e8dc079e..b77a0265e 100644 --- a/msg/json/fi.json +++ b/msg/json/fi.json @@ -41,7 +41,7 @@ "REDO": "Tee uudelleen", "CHANGE_VALUE_TITLE": "Muuta arvoa:", "RENAME_VARIABLE": "Nimeä uudelleen muuttuja...", - "RENAME_VARIABLE_TITLE": "Nimeä uudelleen kaikki '%1' muuttujaa:", + "RENAME_VARIABLE_TITLE": "Nimeä uudelleen muuttuja '%1' kaikkialla:", "NEW_VARIABLE": "Luo muuttuja...", "NEW_STRING_VARIABLE": "Luo merkkijonomuuttuja...", "NEW_NUMBER_VARIABLE": "Luo numeromuuttuja...", diff --git a/msg/json/fr.json b/msg/json/fr.json index 6cc6a37b6..19225a337 100644 --- a/msg/json/fr.json +++ b/msg/json/fr.json @@ -283,7 +283,7 @@ "LISTS_GET_INDEX_GET_REMOVE": "obtenir et supprimer", "LISTS_GET_INDEX_REMOVE": "retirer", "LISTS_GET_INDEX_FROM_START": "nº", - "LISTS_GET_INDEX_FROM_END": "n° depuis la fin", + "LISTS_GET_INDEX_FROM_END": "nº depuis la fin", "LISTS_GET_INDEX_FIRST": "premier", "LISTS_GET_INDEX_LAST": "dernier", "LISTS_GET_INDEX_RANDOM": "au hasard", @@ -313,9 +313,9 @@ "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Ajoute l’élément à la fin d’une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Insère l’élément au hasard dans une liste.", "LISTS_GET_SUBLIST_START_FROM_START": "obtenir la sous-liste depuis le n°", - "LISTS_GET_SUBLIST_START_FROM_END": "obtenir la sous-liste depuis le n° depuis la fin", + "LISTS_GET_SUBLIST_START_FROM_END": "obtenir la sous-liste depuis le nº depuis la fin", "LISTS_GET_SUBLIST_START_FIRST": "obtenir la sous-liste depuis le début", - "LISTS_GET_SUBLIST_END_FROM_START": "jusqu’au n°", + "LISTS_GET_SUBLIST_END_FROM_START": "jusqu’au nº", "LISTS_GET_SUBLIST_END_FROM_END": "jusqu’au n° depuis la fin", "LISTS_GET_SUBLIST_END_LAST": "jusqu’à la fin", "LISTS_GET_SUBLIST_TOOLTIP": "Crée une copie de la partie spécifiée d’une liste.", diff --git a/msg/json/ia.json b/msg/json/ia.json index 0921c912f..e86fbf44a 100644 --- a/msg/json/ia.json +++ b/msg/json/ia.json @@ -20,10 +20,10 @@ "DELETE_X_BLOCKS": "Deler %1 blocos", "DELETE_ALL_BLOCKS": "Deler tote le %1 blocos?", "CLEAN_UP": "Rangiar le blocos", - "COLLAPSE_BLOCK": "Plicar bloco", - "COLLAPSE_ALL": "Plicar blocos", - "EXPAND_BLOCK": "Displicar bloco", - "EXPAND_ALL": "Displicar blocos", + "COLLAPSE_BLOCK": "Contraher bloco", + "COLLAPSE_ALL": "Contraher blocos", + "EXPAND_BLOCK": "Expander bloco", + "EXPAND_ALL": "Expander blocos", "DISABLE_BLOCK": "Disactivar bloco", "ENABLE_BLOCK": "Activar bloco", "HELP": "Adjuta", @@ -328,7 +328,7 @@ "PROCEDURES_IFRETURN_WARNING": "Attention: Iste bloco pote solmente esser usate in le definition de un function.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Dice qualcosa...", "WORKSPACE_ARIA_LABEL": "Spatio de travalio de Blockly", - "COLLAPSED_WARNINGS_WARNING": "Blocos plicate contine advertimentos.", + "COLLAPSED_WARNINGS_WARNING": "Il ha blocos contrahite con advertimentos.", "DIALOG_OK": "OK", "DIALOG_CANCEL": "Cancellar" } diff --git a/msg/json/kn.json b/msg/json/kn.json index dd1c68b4b..21c8bc93f 100644 --- a/msg/json/kn.json +++ b/msg/json/kn.json @@ -3,6 +3,7 @@ "authors": [ "Ananth subray", "Anoop rao", + "Ashay vb", "Ksh31", "Ksramwiki1957", "Mahadevaiah Siddaiah", @@ -109,6 +110,10 @@ "LOGIC_TERNARY_IF_FALSE": "ಸುಳ್ಳು ಆಗಿದ್ದರೆ", "LOGIC_TERNARY_TOOLTIP": "'ಪರೀಕ್ಷೆ'ಯಲ್ಲಿನ ಷರತ್ತನ್ನು ಪರಿಶೀಲಿಸಿ. ಷರತ್ತು ಸರಿಯಾಗಿದ್ದರೆ, 'ಸತ್ಯವಾಗಿದ್ದರೆ' ಮೌಲ್ಯವನ್ನು; ಇಲ್ಲದಿದ್ದರೆ 'ಸುಳ್ಳಾಗಿದ್ದರೆ' ಮೌಲ್ಯವನ್ನೂ ಹಿಂತಿರುಗಿಸುವುದು.", "MATH_NUMBER_TOOLTIP": "ಒಂದು ಸಂಖ್ಯೆ.", + "MATH_TRIG_SIN": "ಪಾಪ", + "MATH_TRIG_TAN": "ಕಂದುಬಣ್ಣ", + "MATH_TRIG_ASIN": "ಅಸಿನ್", + "MATH_TRIG_ACOS": "ಅಕೋಸ್", "MATH_ARITHMETIC_TOOLTIP_ADD": "ಎರಡು ಸಂಖ್ಯೆಗಳ ಮೊತ್ತವನ್ನು ಹಿಂತಿರುಗಿಸಿ.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "ಎರಡು ಸಂಖ್ಯೆಗಳ ವ್ಯತ್ಯಾಸವನ್ನು ಹಿಂತಿರುಗಿಸಿ.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "ಎರಡು ಸಂಖ್ಯೆಗಳ ಗುಣಲಬ್ಧವನ್ನು ಹಿಂತಿರುಗಿಸಿ.", @@ -241,6 +246,7 @@ "LISTS_GET_INDEX_GET": "ಪಡೆಯಿರಿ", "LISTS_GET_INDEX_GET_REMOVE": "ಪಡೆಯಿರಿ ಮತ್ತು ತೆಗೆದುಹಾಕಿ", "LISTS_GET_INDEX_REMOVE": "ತೆಗೆ", + "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# ಕೊನೆಯಿಂದ", "LISTS_GET_INDEX_FIRST": "ಮೊದಲ", "LISTS_GET_INDEX_LAST": "ಕೊನೆಯ", diff --git a/msg/json/ko.json b/msg/json/ko.json index 7ac1a8aee..c688b704b 100644 --- a/msg/json/ko.json +++ b/msg/json/ko.json @@ -18,6 +18,7 @@ "Priviet", "Revi", "SeoJeongHo", + "Snddl3", "Ykhwong", "아라" ] @@ -172,7 +173,7 @@ "MATH_IS_NEGATIVE": "가 음(-)수 이면", "MATH_IS_DIVISIBLE_BY": "가 다음 수로 나누어 떨어지면 :", "MATH_IS_TOOLTIP": "어떤 수가 짝 수, 홀 수, 소 수, 정 수, 양 수, 음 수, 나누어 떨어지는 수 인지 검사해 결과값을 돌려줍니다. 참(true) 또는 거짓(false) 값을 돌려줌.", - "MATH_CHANGE_TITLE": "바꾸기 %1 만큼 %2", + "MATH_CHANGE_TITLE": "%1 을 %2 만큼 바꾸기", "MATH_CHANGE_TOOLTIP": "변수 '%1' 에 저장되어있는 값에, 어떤 수를 더해, 변수에 다시 저장합니다.", "MATH_ROUND_HELPURL": "https://ko.wikipedia.org/wiki/반올림", "MATH_ROUND_TOOLTIP": "어떤 수를 반올림/올림/버림한 결과를, 정수값으로 돌려줍니다.", diff --git a/msg/json/lb.json b/msg/json/lb.json index 5e7a386ff..3734add45 100644 --- a/msg/json/lb.json +++ b/msg/json/lb.json @@ -3,7 +3,8 @@ "authors": [ "Les Meloures", "Robby", - "Soued031" + "Soued031", + "Volvox" ] }, "VARIABLES_DEFAULT_NAME": "Element", @@ -15,6 +16,7 @@ "DUPLICATE_COMMENT": "Bemierkung kopéieren", "DELETE_BLOCK": "Block läschen", "DELETE_X_BLOCKS": "%1 Bléck läschen", + "DELETE_ALL_BLOCKS": "All %1 Bléck läschen?", "CLEAN_UP": "Bléck opraumen", "COLLAPSE_BLOCK": "Block zesummeklappen", "COLLAPSE_ALL": "Bléck zesummeklappen", @@ -29,7 +31,15 @@ "RENAME_VARIABLE": "Variabel ëmbenennen...", "RENAME_VARIABLE_TITLE": "All '%1' Variabelen ëmbenennen op:", "NEW_VARIABLE": "Variabel uleeën...", - "NEW_VARIABLE_TITLE": "Neie variabelen Numm:", + "NEW_NUMBER_VARIABLE": "Zuelevariabel uleeën...", + "NEW_COLOUR_VARIABLE": "Faarfvariabel uleeën...", + "NEW_VARIABLE_TYPE_TITLE": "Neie Variabelentyp:", + "NEW_VARIABLE_TITLE": "Neie Variabelennumm:", + "VARIABLE_ALREADY_EXISTS": "Et gëtt schonn eng Variabel mam Numm '%1'.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Et gëtt schonn eng Variabel mam Numm '%1' fir een aneren Typ: '%2'.", + "DELETE_VARIABLE_CONFIRMATION": "%1 Verwendunge vun der Variabel '%2' läschen?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "D'Variabel '%1' kann net geläscht ginn, well se Deel vun der Definitioun vun der Funktioun '%2' ass.", + "DELETE_VARIABLE": "D'Variabel '%1' läschen", "COLOUR_PICKER_TOOLTIP": "Sicht eng Faarf an der Palette eraus.", "COLOUR_RANDOM_TITLE": "zoufälleg Faarf", "COLOUR_RANDOM_TOOLTIP": "Eng zoufälleg Faarf eraussichen.", @@ -62,6 +72,12 @@ "LOGIC_TERNARY_IF_TRUE": "wa wouer", "LOGIC_TERNARY_IF_FALSE": "wa falsch", "MATH_NUMBER_TOOLTIP": "Eng Zuel.", + "MATH_TRIG_SIN": "sin", + "MATH_TRIG_COS": "cos", + "MATH_TRIG_TAN": "tan", + "MATH_TRIG_ASIN": "asin", + "MATH_TRIG_ACOS": "acos", + "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_TOOLTIP_ADD": "Den Total vun den zwou Zuelen zréckginn.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "D'Produkt vun den zwou Zuelen zréckginn.", "MATH_SINGLE_HELPURL": "https://lb.wikipedia.org/wiki/Racine carrée", @@ -73,6 +89,7 @@ "MATH_IS_WHOLE": "ass eng ganz Zuel", "MATH_IS_POSITIVE": "ass positiv", "MATH_IS_NEGATIVE": "ass negativ", + "MATH_IS_DIVISIBLE_BY": "ass deelbar duerch", "MATH_CHANGE_TITLE": "änneren %1 ëm %2", "MATH_ROUND_TOOLTIP": "Eng Zuel op- oder ofrënnen.", "MATH_ROUND_OPERATOR_ROUND": "opronnen", @@ -84,6 +101,7 @@ "MATH_ONLIST_OPERATOR_RANDOM": "zoufällegt Element vun enger Lëscht", "MATH_MODULO_TITLE": "Rescht vu(n) %1 ÷ %2", "MATH_RANDOM_INT_TITLE": "zoufälleg ganz Zuel tëscht %1 a(n) %2", + "MATH_ATAN2_TITLE": "atan2 vun X:%1 Y:%2", "TEXT_TEXT_TOOLTIP": "E Buschtaf, e Wuert oder eng Textzeil.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "En Element bei den Text derbäisetzen.", "TEXT_LENGTH_TITLE": "Längt vu(n) %1", @@ -95,8 +113,10 @@ "TEXT_GET_SUBSTRING_END_LAST": "bis bei de leschte Buschtaf", "TEXT_PRINT_TITLE": "%1 drécken", "TEXT_PROMPT_TOOLTIP_TEXT": "Frot de Benotzer no engem Text.", + "TEXT_COUNT_MESSAGE0": "ziel %1 an %2", "TEXT_REPLACE_MESSAGE0": "%1 duerch %2 a(n) %3 ersetzen", "TEXT_REPLACE_TOOLTIP": "All Kéiers wou e bestëmmten Text do ass duerch en aneren Text ersetzen.", + "TEXT_REVERSE_MESSAGE0": "%1 ëmdréinen", "TEXT_REVERSE_TOOLTIP": "Dréint d'Reiefolleg vun den Zeechen am Text ëm.", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "Lëscht", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "En Element op d'Lëscht derbäisetzen.", @@ -111,7 +131,7 @@ "LISTS_GET_INDEX_RANDOM": "Zoufall", "LISTS_INDEX_FROM_START_TOOLTIP": "%1 ass dat éischt Element.", "LISTS_INDEX_FROM_END_TOOLTIP": "%1 ass dat éischt Element.", - "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Schéckt en zoufällegt Element aus enger Lëscht zréck.", + "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Gëtt en zoufällegt Element aus enger Lëscht zréck.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Hëlt dat lescht Element aus enger Lëscht eraus.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Hëlt en zoufällegt Element aus enger Lëscht eraus.", "LISTS_SET_INDEX_INSERT": "asetzen op", @@ -129,6 +149,7 @@ "PROCEDURES_DEFNORETURN_COMMENT": "Dës Funktioun beschreiwen...", "PROCEDURES_DEFRETURN_RETURN": "zréck", "PROCEDURES_CREATE_DO": "'%1' uleeën", + "PROCEDURES_IFRETURN_WARNING": "Opgepasst: Dëse Block däerf nëmmen bannent enger Funktiounsdefitioun benotzt ginn.", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Sot eppes...", "DIALOG_OK": "OK", "DIALOG_CANCEL": "Ofbriechen" diff --git a/msg/json/sd.json b/msg/json/sd.json index 308ad1608..f6e7b5f03 100644 --- a/msg/json/sd.json +++ b/msg/json/sd.json @@ -3,12 +3,14 @@ "authors": [ "Aursani", "Charan", + "Charoo", "Indus Asia", "Mehtab ahmed", "Tweety" ] }, "VARIABLES_DEFAULT_NAME": "اسم", + "UNNAMED_KEY": "بينام", "TODAY": "اڄ", "DUPLICATE_BLOCK": "نقل", "ADD_COMMENT": "رايو ڏيو", @@ -31,8 +33,16 @@ "REDO": "ٻيهر ڪريو", "CHANGE_VALUE_TITLE": "قدر بدلايو", "RENAME_VARIABLE": "ڦرڻي کي نئون نالو ڏيو...", + "RENAME_VARIABLE_TITLE": "سڀني '%1' کي تبديل ڪيو:", "NEW_VARIABLE": "نئون ڦرڻو...", + "NEW_STRING_VARIABLE": "اسٽرينگ وري ايبل ٺاھيو...", + "NEW_NUMBER_VARIABLE": "نمبر وري ايبل ٺاھيو...", + "NEW_COLOUR_VARIABLE": "رنگ وري ايبل ٺاھيو...", + "NEW_VARIABLE_TYPE_TITLE": "نئين وري ايبل جو قسم:", "NEW_VARIABLE_TITLE": "ڦرڻي جو نئون نالو:", + "VARIABLE_ALREADY_EXISTS": "'%1' جي نالي سان اڳ ئي وري ايبل موجود آھي.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "'%2' وري ايبل لاءِ '%1' وري اينل اڳ ئي موجود آھي،", + "DELETE_VARIABLE_CONFIRMATION": "'%2' وري ايبل جي استعمال %1 مٽايو؟", "COLOUR_PICKER_TOOLTIP": "رنگ دٻيءَ مان رنگ چونڊيو.", "COLOUR_RANDOM_TITLE": "بنا ترتيب رنگ", "COLOUR_RANDOM_TOOLTIP": "ڪو بہ ‌رنگ چونڊيو.", diff --git a/msg/json/skr-arab.json b/msg/json/skr-arab.json index 187cb3691..39d84d2ee 100644 --- a/msg/json/skr-arab.json +++ b/msg/json/skr-arab.json @@ -31,6 +31,7 @@ "NEW_VARIABLE": "متغیر بݨاؤ۔۔۔", "NEW_VARIABLE_TITLE": "نواں متغیر ناں:", "VARIABLE_ALREADY_EXISTS": "'%1' نامی متغیر پہلے موجود ہے۔", + "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_RANDOM_TITLE": "بنا ترتيب رنگ", "COLOUR_RGB_TITLE": "نال رن٘گ", "COLOUR_RGB_RED": "رتا", @@ -86,7 +87,7 @@ "LISTS_GET_INDEX_FROM_END": "# چھیکڑ کنوں", "LISTS_GET_INDEX_FIRST": "پہلا", "LISTS_GET_INDEX_LAST": "چھیکڑی", - "LISTS_GET_INDEX_RANDOM": "قُݨے نال", + "LISTS_GET_INDEX_RANDOM": "بے ترتیبا", "LISTS_SET_INDEX_SET": "سیٹ", "LISTS_SET_INDEX_INSERT": "تے درج کرو", "LISTS_SET_INDEX_INPUT_TO": "بطور", diff --git a/msg/json/sl.json b/msg/json/sl.json index 8e80cc25c..8e21e4a29 100644 --- a/msg/json/sl.json +++ b/msg/json/sl.json @@ -74,9 +74,9 @@ "CONTROLS_FOREACH_TITLE": "za vsak element %1 v seznamu %2", "CONTROLS_FOREACH_TOOLTIP": "Za vsak element v seznamu nastavi spremenljivko »%1« na ta element. Pri tem se izvedejo določeni stavki.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "prekini zanko", - "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "nadaljuj z naslednjo ponovitvijo zanke", + "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "nadaljuj z naslednjo iteracijo zanke", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Prekine vsebujočo zanko.", - "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Preskoči preostanek te zanke in nadaljuje z naslednjo ponovitvijo.", + "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Preskočite preostanek te zanke in nadaljujte z naslednjo iteracijo.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Pozor: Ta blok lahko uporabite znotraj zanke samo enkrat.", "CONTROLS_IF_TOOLTIP_1": "Če je vrednost resnična, izvedi določene stavke.", "CONTROLS_IF_TOOLTIP_2": "Če je vrednost resnična, izvedi prvo skupino stavkov. Sicer izvedi drugo skupino stavkov.", @@ -188,21 +188,27 @@ "MATH_ATAN2_TOOLTIP": "Vrne arkus tangens točke (X, Y) v stopinjah med −180 in 180.", "TEXT_TEXT_HELPURL": "https://sl.wikipedia.org/wiki/Niz", "TEXT_TEXT_TOOLTIP": "Črka, beseda ali vrstica besedila.", + "TEXT_JOIN_HELPURL": "https://github.com/google/blockly/wiki/Text#text-creation", "TEXT_JOIN_TITLE_CREATEWITH": "ustvari besedilo iz", "TEXT_JOIN_TOOLTIP": "Ustvari besedilo tako, da združi poljubno število elementov.", - "TEXT_CREATE_JOIN_TITLE_JOIN": "združi", + "TEXT_CREATE_JOIN_TITLE_JOIN": "spoji", "TEXT_CREATE_JOIN_TOOLTIP": "Doda, odstrani ali spremeni vrstni red odsekov za ponovno nastavitev tega bloka besedila.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Doda element k besedilu.", - "TEXT_APPEND_TITLE": "k %1 dodaj besedilo %2", - "TEXT_APPEND_TOOLTIP": "Doda besedilo k spremenljivki »%1«.", + "TEXT_APPEND_HELPURL": "https://github.com/google/blockly/wiki/Text#text-modification", + "TEXT_APPEND_TITLE": "k %1 pripni besedilo %2", + "TEXT_APPEND_TOOLTIP": "Pripne neko besedilo spremenljivki »%1«.", + "TEXT_LENGTH_HELPURL": "https://github.com/google/blockly/wiki/Text#text-modification", "TEXT_LENGTH_TITLE": "dolžina %1", "TEXT_LENGTH_TOOLTIP": "Vrne število znakov (vključno s presledki) v določenem besedilu.", + "TEXT_ISEMPTY_HELPURL": "https://github.com/google/blockly/wiki/Text#checking-for-empty-text", "TEXT_ISEMPTY_TITLE": "%1 je prazno", "TEXT_ISEMPTY_TOOLTIP": "Vrne resnično, če je določeno besedilo prazno.", + "TEXT_INDEXOF_HELPURL": "https://github.com/google/blockly/wiki/Text#finding-text", "TEXT_INDEXOF_TOOLTIP": "Vrne mesto (indeks) prve/zadnje pojavitve drugega besedila v prvem besedilu. Če besedila ne najde, vrne %1.", "TEXT_INDEXOF_TITLE": "v besedilu %1 %2 %3", "TEXT_INDEXOF_OPERATOR_FIRST": "najdi prvo pojavitev besedila", "TEXT_INDEXOF_OPERATOR_LAST": "najdi zadnjo pojavitev besedila", + "TEXT_CHARAT_HELPURL": "https://github.com/google/blockly/wiki/Text#extracting-text", "TEXT_CHARAT_TITLE": "v besedilu %1 %2", "TEXT_CHARAT_FROM_START": "vrni črko št.", "TEXT_CHARAT_FROM_END": "vrni črko št. od konca", @@ -218,6 +224,7 @@ "TEXT_GET_SUBSTRING_END_FROM_START": "do črke št.", "TEXT_GET_SUBSTRING_END_FROM_END": "do črke št. od konca", "TEXT_GET_SUBSTRING_END_LAST": "do zadnje črke", + "TEXT_CHANGECASE_HELPURL": "https://github.com/google/blockly/wiki/Text#adjusting-text-case", "TEXT_CHANGECASE_TOOLTIP": "Vrne kopijo besedila v drugi obliki.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "v VELIKE ČRKE", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "v male črke", @@ -226,6 +233,7 @@ "TEXT_TRIM_OPERATOR_BOTH": "odstrani presledke z obeh strani", "TEXT_TRIM_OPERATOR_LEFT": "odstrani presledke z leve strani", "TEXT_TRIM_OPERATOR_RIGHT": "odstrani presledke z desne strani", + "TEXT_PRINT_HELPURL": "https://github.com/google/blockly/wiki/Text#printing-text", "TEXT_PRINT_TITLE": "izpiši %1", "TEXT_PRINT_TOOLTIP": "Izpiše določeno besedilo, številko ali drugo vrednost.", "TEXT_PROMPT_TYPE_TEXT": "vprašaj za besedilo s sporočilom", @@ -237,6 +245,7 @@ "TEXT_REPLACE_MESSAGE0": "zamenjaj %1 z %2 v %3", "TEXT_REPLACE_TOOLTIP": "Zamenja vse pojavitve besedila v drugem besedilu.", "TEXT_REVERSE_MESSAGE0": "obrni %1", + "TEXT_REVERSE_HELPURL": "https://github.com/google/blockly/wiki/Text#reversing-text", "TEXT_REVERSE_TOOLTIP": "Obrne vrstni red znakov v besedilu.", "LISTS_CREATE_EMPTY_TITLE": "ustvari prazen seznam", "LISTS_CREATE_EMPTY_TOOLTIP": "Vrne seznam dolžine 0, ki ne vsebuje nobenih podatkovnih zapisov.", @@ -286,7 +295,7 @@ "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Nastavi naključni element seznama.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM": "Vstavi element na določeno mesto v seznamu.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Vstavi element na začetek seznama.", - "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Doda element na konec seznama.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Pripne element na konec seznama.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Vstavi element na naključno mesto v seznamu.", "LISTS_GET_SUBLIST_START_FROM_START": "ustvari podseznam od mesta št.", "LISTS_GET_SUBLIST_START_FROM_END": "ustvari podseznam od mesta št. od konca", @@ -302,11 +311,12 @@ "LISTS_SORT_TYPE_NUMERIC": "številsko", "LISTS_SORT_TYPE_TEXT": "abecedno", "LISTS_SORT_TYPE_IGNORECASE": "abecedno, prezri velikost črk", + "LISTS_SPLIT_HELPURL": "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists", "LISTS_SPLIT_LIST_FROM_TEXT": "ustvari seznam iz besedila", "LISTS_SPLIT_TEXT_FROM_LIST": "ustvari besedilo iz seznama", "LISTS_SPLIT_WITH_DELIMITER": "z ločilom", "LISTS_SPLIT_TOOLTIP_SPLIT": "Razdruži besedilo v seznam besedil s prelomom pri vsakem ločilu.", - "LISTS_SPLIT_TOOLTIP_JOIN": "Združi seznam besedil v eno besedilo z ločilom med besedili.", + "LISTS_SPLIT_TOOLTIP_JOIN": "Spoji seznam besedil v eno besedilo z razmejevalcem med besedili.", "LISTS_REVERSE_MESSAGE0": "obrni %1", "LISTS_REVERSE_TOOLTIP": "Obrne kopijo seznama.", "VARIABLES_GET_TOOLTIP": "Vrne vrednost spremenljivke.", @@ -328,7 +338,7 @@ "PROCEDURES_CALLNORETURN_TOOLTIP": "Izvede uporabniško določeno funkcijo »%1«.", "PROCEDURES_CALLRETURN_HELPURL": "https://sl.wikipedia.org/wiki/Subrutina", "PROCEDURES_CALLRETURN_TOOLTIP": "Izvede uporabniško funkcijo »%1« in uporabi njen izhod.", - "PROCEDURES_MUTATORCONTAINER_TITLE": "vnosi", + "PROCEDURES_MUTATORCONTAINER_TITLE": "vhodi", "PROCEDURES_MUTATORCONTAINER_TOOLTIP": "Doda, odstrani ali spremeni vrstni red vnosov za to funkcijo.", "PROCEDURES_MUTATORARG_TITLE": "ime vnosa:", "PROCEDURES_MUTATORARG_TOOLTIP": "Funkciji doda vnos.", diff --git a/msg/json/sr.json b/msg/json/sr.json index ab6714d5f..088bfa8f1 100644 --- a/msg/json/sr.json +++ b/msg/json/sr.json @@ -8,6 +8,7 @@ "Obsuser", "Perevod16", "Rancher", + "Zenfiric", "Zoranzoki21", "Милан Јелисавчић", "아라" diff --git a/msg/json/sw.json b/msg/json/sw.json index 76095333f..def24c10f 100644 --- a/msg/json/sw.json +++ b/msg/json/sw.json @@ -1,10 +1,12 @@ { "@metadata": { "authors": [ + "Wangombe", "Yasen igra" ] }, "TODAY": "Leo", "HELP": "Msaada", + "UNDO": "Tengua", "DIALOG_OK": "Sawa" } diff --git a/msg/json/zh-hans.json b/msg/json/zh-hans.json index 34019dba1..952dcb024 100644 --- a/msg/json/zh-hans.json +++ b/msg/json/zh-hans.json @@ -14,6 +14,7 @@ "Liuxinyu970226", "Luotiancheng", "Muhaoying", + "Phoenix3145", "Qiyue2001", "Shatteredwind", "Shimamura Sakura", @@ -128,6 +129,12 @@ "LOGIC_TERNARY_TOOLTIP": "检查“断言”里的条件语句。如果条件为真,则返回“如果为真”的值,否则,则返回“如果为假”的值。", "MATH_NUMBER_HELPURL": "https://zh.wikipedia.org/wiki/数", "MATH_NUMBER_TOOLTIP": "一个数值。", + "MATH_TRIG_SIN": "正弦", + "MATH_TRIG_COS": "余弦", + "MATH_TRIG_TAN": "正切", + "MATH_TRIG_ASIN": "反正弦", + "MATH_TRIG_ACOS": "反余玄", + "MATH_TRIG_ATAN": "反正切", "MATH_ARITHMETIC_HELPURL": "https://zh.wikipedia.org/wiki/算术", "MATH_ARITHMETIC_TOOLTIP_ADD": "返回两个数值的和。", "MATH_ARITHMETIC_TOOLTIP_MINUS": "返回两个数值的差。", diff --git a/msg/json/zh-hant.json b/msg/json/zh-hant.json index 2c5326e19..393438f5f 100644 --- a/msg/json/zh-hant.json +++ b/msg/json/zh-hant.json @@ -86,7 +86,7 @@ "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "跳過這個循環的其餘步驟,並繼續下一次的循環。", "CONTROLS_FLOW_STATEMENTS_WARNING": "警告:此區塊僅可用於循環內。", "CONTROLS_IF_TOOLTIP_1": "當值為 true 時,執行一些陳述式。", - "CONTROLS_IF_TOOLTIP_2": "當值為 true 時,執行第一個陳述式。否則,執行第二個陳述式。", + "CONTROLS_IF_TOOLTIP_2": "值為是(true)就執行第一塊陳述式,否則執行第二塊。", "CONTROLS_IF_TOOLTIP_3": "如果第一個值為 true,則執行第一個陳述式。否則,當第二個值為 true 時,則執行第二個陳述式。", "CONTROLS_IF_TOOLTIP_4": "如果第一個值為 true,則執行第一個陳述式。否則當第二個值為 true 時,則執行第二個陳述式。如果前幾個敘述都不為 ture,則執行最後一個陳述式。", "CONTROLS_IF_MSG_IF": "如果", @@ -163,7 +163,7 @@ "MATH_CHANGE_TITLE": "修改 %1 自 %2", "MATH_CHANGE_TOOLTIP": "將數字加到變數「%1」。", "MATH_ROUND_HELPURL": "https://zh.wikipedia.org/wiki/數值簡化", - "MATH_ROUND_TOOLTIP": "將數字無條件進位或無條件捨去。", + "MATH_ROUND_TOOLTIP": "上捨入或下捨入數字", "MATH_ROUND_OPERATOR_ROUND": "四捨五入", "MATH_ROUND_OPERATOR_ROUNDUP": "無條件進位", "MATH_ROUND_OPERATOR_ROUNDDOWN": "無條件捨去", diff --git a/msg/messages.js b/msg/messages.js index 37311dfa5..e8ffe4aff 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -166,6 +166,9 @@ Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists.'; /** @type {string} */ /// alert - Tells the user that the name they entered is already in use for another type. Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = 'A variable named "%1" already exists for another type: "%2".'; +/** @type {string} */ +/// alert - Tells the user that the name they entered is already in use as a parameter to a procedure, that the variable they are renaming also exists on. Renaming would create two parameters with the same name, which is not allowed. +Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_A_PARAMETER = 'A variable named "%1" already exists as a parameter in the procedure "%2".'; // Variable deletion. /** @type {string} */ diff --git a/package-lock.json b/package-lock.json index bdfa450c6..4fc6c75cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "blockly", - "version": "9.2.1", + "version": "9.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "blockly", - "version": "9.2.1", + "version": "9.3.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "jsdom": "20.0.3" + "jsdom": "21.1.1" }, "devDependencies": { "@blockly/block-test": "^3.0.0", @@ -28,9 +28,9 @@ "concurrently": "^7.4.0", "eslint": "^8.4.1", "eslint-config-google": "^0.14.0", - "eslint-plugin-jsdoc": "^39.3.6", - "google-closure-compiler": "^20221004.0.0", - "google-closure-deps": "^20221102.0.0", + "eslint-plugin-jsdoc": "^40.0.0", + "google-closure-compiler": "^20230206.0.0", + "google-closure-deps": "^20230206.0.0", "gulp": "^4.0.2", "gulp-clang-format": "^1.0.27", "gulp-concat": "^2.6.1", @@ -44,16 +44,16 @@ "gulp-sourcemaps": "^3.0.0", "gulp-umd": "^2.0.0", "http-server": "^14.0.0", - "js-green-licenses": "^3.0.0", + "js-green-licenses": "^4.0.0", "json5": "^2.2.0", "markdown-tables-to-json": "^0.1.7", "mocha": "^10.0.0", "patch-package": "^6.4.7", "readline-sync": "^1.4.10", - "rimraf": "^3.0.2", + "rimraf": "^4.0.7", "selenium-standalone": "^8.0.3", "through2": "^4.0.2", - "typescript": "^4.3.2", + "typescript": "^5.0.2", "webdriverio": "^8.0.5", "yargs": "^17.2.1" } @@ -165,28 +165,28 @@ } }, "node_modules/@blockly/block-test": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-3.0.1.tgz", - "integrity": "sha512-lXHwyAFiLNAmDS3BvBscy7S4YfKt8U8yMghop/j5G3nUz5gKWQGMtUJDq7Wm5ZpIFHghYDPxnhdpwhdCkuRchA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-3.0.8.tgz", + "integrity": "sha512-foW4fVKCrrmeImXNgVJZ+XjMENpOz3z3P/ob1IxixPnQ3QyO2Yjh0rfPDkSteJjto5k9Q+XhcvlW1w42gyjIKg==", "dev": true, "engines": { "node": ">=8.17.0" }, "peerDependencies": { - "blockly": "^9.0.0" + "blockly": "^9.2.0" } }, "node_modules/@blockly/dev-tools": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-5.0.2.tgz", - "integrity": "sha512-3h9nbpbrz8+YCbQlkpIJh1YXmlSmslxzibdPvc6VcgzXA+xzAc2a00Wy5f+ugQRq2394J8Cn/cKXqUKDLjykRA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-5.2.4.tgz", + "integrity": "sha512-7FF5PByhq9EhKeYty0GFZp8b7l3qWrEIiqyVTgp/xN7iI/9N6scsDVZfCWVDSmZHgiaTHkEcQW/697IRm69HDA==", "dev": true, "dependencies": { - "@blockly/block-test": "^3.0.1", - "@blockly/theme-dark": "^4.0.1", - "@blockly/theme-deuteranopia": "^3.0.1", - "@blockly/theme-highcontrast": "^3.0.1", - "@blockly/theme-tritanopia": "^3.0.2", + "@blockly/block-test": "^3.0.8", + "@blockly/theme-dark": "^4.0.7", + "@blockly/theme-deuteranopia": "^3.0.7", + "@blockly/theme-highcontrast": "^3.0.7", + "@blockly/theme-tritanopia": "^3.0.8", "chai": "^4.2.0", "dat.gui": "^0.7.7", "lodash.assign": "^4.2.0", @@ -202,9 +202,9 @@ } }, "node_modules/@blockly/theme-dark": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-4.0.1.tgz", - "integrity": "sha512-OIfdnt3kvPnEW/TmfLPUftcekwoQGmxg/12LajYUdW9aOLMQaen16Vw0+BB8Q8zKInpxT6JCBYECilYRLY+RpA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-4.0.7.tgz", + "integrity": "sha512-NegmW6DxvDISxonJ8gtp/CGxYZmtNYyjR2t7V5GzwnZhU1QV1aZVJk49f3CbFftQm3W93wHZ9HQn80oTbOCbiQ==", "dev": true, "engines": { "node": ">=8.17.0" @@ -214,9 +214,9 @@ } }, "node_modules/@blockly/theme-deuteranopia": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-3.0.1.tgz", - "integrity": "sha512-3zmkD3ERGAuKQjAeFFoNNAhfwmxFncXd3Mw5tHn64MlxguMJCKt7C4Siu6gRXGYpvukkpMUlbgklWyNz2okHng==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-3.0.7.tgz", + "integrity": "sha512-51NF9RqqiskCefMPwMO9JS5l+Q1ubyryx5XUwNV7Dl8LljmyaQzBy2xu6MVIG/yZDY1qR7oS2scsyOffb++oFQ==", "dev": true, "engines": { "node": ">=8.17.0" @@ -226,9 +226,9 @@ } }, "node_modules/@blockly/theme-highcontrast": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-3.0.1.tgz", - "integrity": "sha512-HuEHKq7n2zTV1gb19SGjyKlCYjZeZSITWPIQeD5wfEVleOOy8z6zjLRZ9D7QoiL4ooFefWkx1kauVsWbaTqN5g==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-3.0.7.tgz", + "integrity": "sha512-uwpDXhcXXaXxWT1xkWECUBD0ao1+hzK9iLf5FWktnSqfyj6galLVjB2mxRb3ZTaVuhjvw7/qhjYzVPqzL2NKgg==", "dev": true, "engines": { "node": ">=8.17.0" @@ -238,9 +238,9 @@ } }, "node_modules/@blockly/theme-modern": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-3.0.1.tgz", - "integrity": "sha512-rKB5NrAGFF+Vo4aIfk+zbXZYfKDULPMFNWkT5dS0cyMSNHvcy7Xgi3llq29YhTG/LLicOjitSc8cErcZsicjng==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-3.0.6.tgz", + "integrity": "sha512-A59AMr3hZRHugC3qGSpZ2gtGlQkuWtj2qj7B5jLbVoSKNJuPRJt1DKQElvriev5GhangjSmrQZULPhAAIEXLsQ==", "dev": true, "engines": { "node": ">=8.17.0" @@ -250,9 +250,9 @@ } }, "node_modules/@blockly/theme-tritanopia": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-3.0.2.tgz", - "integrity": "sha512-soKspGnVLk+EVuWm8HfRSmZoK5NoThpgIS9uvctSNUaEB3Ritvf/feuqu4AFBEjwAUUgkY1SfW70200ZIXRY8g==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-3.0.8.tgz", + "integrity": "sha512-17n3LAFwOJHkBeeVUYoRZ+ATSDpmOQuP41n9ZxDb0N3VbnjkFEVRT+saG3wQgcHD6F7KoVHkK2GChbmcYrU+Ig==", "dev": true, "engines": { "node": ">=8.17.0" @@ -275,16 +275,40 @@ "node": "^14 || ^16 || ^17 || ^18 || ^19" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", + "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -381,9 +405,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -496,59 +520,15 @@ "integrity": "sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg==", "dev": true }, - "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "dev": true, - "optional": true, - "dependencies": { - "jest-get-type": "^29.2.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "optional": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, - "optional": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@microsoft/api-documenter": { - "version": "7.19.25", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.19.25.tgz", - "integrity": "sha512-/yC6cG7QpjkDqHvoXt5SJJdB0Mdj0oYpaWgxdOV8uHRniZ9kZwxAEResswdS6QDCYoyqDD6jlh008HwXIcmXjA==", + "version": "7.19.26", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.19.26.tgz", + "integrity": "sha512-sFhYmO8k6CMFJ20D/LP1B7GdH+JfwmSKO/xTXnm63WA3+AX7g94G4TlKlc1FXdHFS2qhHnlm4qZUD3fgfs1vqg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.25.2", + "@microsoft/api-extractor-model": "7.25.3", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.53.2", + "@rushstack/node-core-library": "3.53.3", "@rushstack/ts-command-line": "4.13.1", "colors": "~1.2.1", "js-yaml": "~3.13.1", @@ -593,20 +573,20 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.33.7", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.33.7.tgz", - "integrity": "sha512-fQT2v/j/55DhvMFiopLtth66E7xTFNhnumMKgKY14SaG6qU/V1W0e4nOAgbA+SmLakQjAd1Evu06ofaVaxBPbA==", + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.34.4.tgz", + "integrity": "sha512-HOdcci2nT40ejhwPC3Xja9G+WSJmWhCUKKryRfQYsmE9cD+pxmBaKBKCbuS9jUcl6bLLb4Gz+h7xEN5r0QiXnQ==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.25.3", + "@microsoft/api-extractor-model": "7.26.4", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.53.3", - "@rushstack/rig-package": "0.3.17", - "@rushstack/ts-command-line": "4.13.1", + "@rushstack/node-core-library": "3.55.2", + "@rushstack/rig-package": "0.3.18", + "@rushstack/ts-command-line": "4.13.2", "colors": "~1.2.1", "lodash": "~4.17.15", - "resolve": "~1.17.0", + "resolve": "~1.22.1", "semver": "~7.3.0", "source-map": "~0.6.1", "typescript": "~4.8.4" @@ -616,17 +596,6 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.25.2.tgz", - "integrity": "sha512-+h1uCrLQXFAKMUdghhdDcnniDB+6UA/lS9ArlB4QZQ34UbLuXNy2oQ6fafFK8cKXU4mUPTF/yGRjv7JKD5L7eg==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.53.2" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/@microsoft/api-extractor-model": { "version": "7.25.3", "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.25.3.tgz", "integrity": "sha512-WWxBUq77p2iZ+5VF7Nmrm3y/UtqCh5bYV8ii3khwq3w99+fXWpvfsAhgSLsC7k8XDQc6De4ssMxH6He/qe1pzg==", @@ -637,27 +606,60 @@ "@rushstack/node-core-library": "3.53.3" } }, - "node_modules/@microsoft/api-extractor/node_modules/@rushstack/node-core-library": { - "version": "3.53.3", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.3.tgz", - "integrity": "sha512-H0+T5koi5MFhJUd5ND3dI3bwLhvlABetARl78L3lWftJVQEPyzcgTStvTTRiIM5mCltyTM8VYm6BuCtNUuxD0Q==", + "node_modules/@microsoft/api-extractor/node_modules/@microsoft/api-extractor-model": { + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.26.4.tgz", + "integrity": "sha512-PDCgCzXDo+SLY5bsfl4bS7hxaeEtnXj7XtuzEE+BtALp7B5mK/NrS2kHWU69pohgsRmEALycQdaQPXoyT2i5MQ==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "3.55.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/node-core-library": { + "version": "3.55.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.55.2.tgz", + "integrity": "sha512-SaLe/x/Q/uBVdNFK5V1xXvsVps0y7h1sN7aSJllQyFbugyOaxhNRF25bwEDnicARNEjJw0pk0lYnJQ9Kr6ev0A==", "dev": true, "dependencies": { - "@types/node": "12.20.24", "colors": "~1.2.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", - "resolve": "~1.17.0", + "resolve": "~1.22.1", "semver": "~7.3.0", "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@microsoft/api-extractor/node_modules/@types/node": { - "version": "12.20.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.13.2.tgz", + "integrity": "sha512-bCU8qoL9HyWiciltfzg7GqdfODUeda/JpI0602kbN5YH22rzTxyqYvv7aRLENCM7XCQ1VRs7nMkEqgJUOU8Sag==", + "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-extractor/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } }, "node_modules/@microsoft/api-extractor/node_modules/fs-extra": { "version": "7.0.1", @@ -682,18 +684,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@microsoft/api-extractor/node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@microsoft/api-extractor/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -792,9 +782,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "3.53.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.2.tgz", - "integrity": "sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA==", + "version": "3.53.3", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.3.tgz", + "integrity": "sha512-H0+T5koi5MFhJUd5ND3dI3bwLhvlABetARl78L3lWftJVQEPyzcgTStvTTRiIM5mCltyTM8VYm6BuCtNUuxD0Q==", "dev": true, "dependencies": { "@types/node": "12.20.24", @@ -858,27 +848,15 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.17.tgz", - "integrity": "sha512-nxvAGeIMnHl1LlZSQmacgcRV4y1EYtgcDIrw6KkeVjudOMonlxO482PhDj3LVZEp6L7emSf6YSO2s5JkHlwfZA==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.18.tgz", + "integrity": "sha512-SGEwNTwNq9bI3pkdd01yCaH+gAsHqs0uxfGvtw9b0LJXH52qooWXnrFTRRLG1aL9pf+M2CARdrA9HLHJys3jiQ==", "dev": true, "dependencies": { - "resolve": "~1.17.0", + "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" } }, - "node_modules/@rushstack/rig-package/node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@rushstack/ts-command-line": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.13.1.tgz", @@ -900,13 +878,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true, - "optional": true - }, "node_modules/@sindresorhus/is": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", @@ -995,12 +966,6 @@ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true }, - "node_modules/@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", - "dev": true - }, "node_modules/@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -1025,33 +990,6 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true, - "optional": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "optional": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -1094,34 +1032,12 @@ "@types/node": "*" } }, - "node_modules/@types/selenium-standalone": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@types/selenium-standalone/-/selenium-standalone-7.0.1.tgz", - "integrity": "sha512-zbKenL0fAXzPyiOaaFMrvFdMNhj5BgNJQq8bxiZfwQD9ID2J8bUG5xbcS3tQtlzIX/62z9nG5Vo45oaHWTbvbw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true, - "optional": true - }, - "node_modules/@types/ua-parser-js": { - "version": "0.7.36", - "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", - "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==", - "dev": true - }, "node_modules/@types/vinyl": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.6.tgz", @@ -1133,37 +1049,20 @@ } }, "node_modules/@types/which": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", - "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", "dev": true }, "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "dependencies": { "@types/node": "*" } }, - "node_modules/@types/yargs": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", - "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", - "dev": true, - "optional": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true, - "optional": true - }, "node_modules/@types/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", @@ -1175,18 +1074,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz", - "integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", + "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/type-utils": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/type-utils": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -1208,13 +1108,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1225,9 +1125,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1238,12 +1138,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1301,13 +1201,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz", - "integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", + "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1328,9 +1228,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1341,13 +1241,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1368,12 +1268,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1427,18 +1327,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz", - "integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", + "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -1453,13 +1353,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1470,9 +1370,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1483,13 +1383,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1510,12 +1410,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1557,23 +1457,198 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@wdio/globals": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.0.12.tgz", - "integrity": "sha512-6D/ZXBxHbANOfs1OKtk9g4O6xeGhAMvzvZnwtfkXQ+ywozfdv1oOzqZ/01wQwrRbmVlfLfIoMy9/kcXjtKP13A==", + "node_modules/@wdio/config": { + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.3.11.tgz", + "integrity": "sha512-sZ1SZkBEZWqSDHqrQxspsrc+OBqf3qyx2c4gVvAovOd1hnT4EcWhlJu1Asp3H0Mti115XstwQabOW4sSsdmVCw==", "dev": true, + "dependencies": { + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^4.2.2", + "glob": "^8.0.3", + "import-meta-resolve": "^2.1.0", + "read-pkg-up": "^9.1.0" + }, "engines": { "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/config/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/config/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "optionalDependencies": { - "expect-webdriverio": "^4.0.1", - "webdriverio": "8.0.12" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/config/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/@wdio/config/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/config/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/@wdio/config/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/config/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/@wdio/config/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/@wdio/config/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/@wdio/config/node_modules/read-pkg": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", + "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/config/node_modules/read-pkg-up": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", + "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^7.1.0", + "type-fest": "^2.5.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/config/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/@wdio/logger": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.0.0.tgz", - "integrity": "sha512-QEBPZoFQhWqqIYmhp8Wa+HhvMrH2Yy0xbD3MPOibkFwp9Tn8Si7oDxbnWqzcPiukLWcb4E/QlgE5f3IM5BrAPQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.1.0.tgz", + "integrity": "sha512-QRC5b7FF4JIYUCqggnVA0sZ80TwIUFN9JyBSbuGuMxaSLSLujSo7WfuSrnQXVvsRbnJ16wWwJWYigfLkxOW86Q==", "dev": true, "dependencies": { "chalk": "^5.1.2", @@ -1586,9 +1661,9 @@ } }, "node_modules/@wdio/logger/node_modules/chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -1598,30 +1673,33 @@ } }, "node_modules/@wdio/protocols": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.0.0.tgz", - "integrity": "sha512-iTfYOcli/98ubeTqxyP9+OBPQxfbB5cPK6Zv61C9Rr4qQkzx4GPQjn/AlK0r6Bn0dRy/9lGyb2Q3UBRCx85RSQ==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.3.11.tgz", + "integrity": "sha512-EXGuZC4Nvl8QPT6gQ9tpeH+TL9P5oRdQofaJA893OX37gU2OWiSNyA7AHr/0/UIHWFax4udpVQ6syTQsy6uWWA==", "dev": true }, "node_modules/@wdio/repl": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.0.0.tgz", - "integrity": "sha512-Qys/t/NioO+LlcDcD+4Agn0JJjIiO6fkqOJJDxv3QulGPCmQ5SaYX+BQyz1o9sGscfr8s/435d+3dkBSO1+3tQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.1.0.tgz", + "integrity": "sha512-96G4TzbYnRf95+GURo15FYt6iTYq85nbWU6YQedLRAV15RfSp4foKTbAnq++bKKMALNL6gdzTc+HGhQr3Q0sQg==", "dev": true, + "dependencies": { + "@types/node": "^18.0.0" + }, "engines": { "node": "^16.13 || >=18" } }, "node_modules/@wdio/selenium-standalone-service": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-8.0.11.tgz", - "integrity": "sha512-k2dT4AEmqVjYv1UmqoQHdQHqHJq+qkZfXyCKo7MeyG4XZ423ioo+otztATu0NiNT7UNSmBbunBis9nUBGWaoUg==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-8.3.11.tgz", + "integrity": "sha512-gRcsaH5KG49r3r3HCOUjG1Mh+1301YJaKgqPyTulaooH5Ia2boEGeI1ijT7F14PBuiuIuha6i3us7TPecgeuVw==", "dev": true, "dependencies": { - "@types/selenium-standalone": "^7.0.0", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", + "@types/node": "^18.0.0", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", "selenium-standalone": "^8.2.1" }, "engines": { @@ -1629,14 +1707,14 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.3.11.tgz", + "integrity": "sha512-sZ1SZkBEZWqSDHqrQxspsrc+OBqf3qyx2c4gVvAovOd1hnT4EcWhlJu1Asp3H0Mti115XstwQabOW4sSsdmVCw==", "dev": true, "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "decamelize": "^6.0.0", "deepmerge-ts": "^4.2.2", "glob": "^8.0.3", @@ -1648,9 +1726,9 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.3.0.tgz", + "integrity": "sha512-TTs3ETVOJtooTIY/u2+feeBnMBx2Hb4SEItN31r0pFncn37rnIZXE/buywLNf5wvZW9ukxoCup5hCnohOR27eQ==", "dev": true, "dependencies": { "@types/node": "^18.0.0" @@ -1660,13 +1738,13 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-BbgzxAu4AN99l9hwaRUvkvBJLeIxON7F6ts+vq4LASRiGVRErrwYGeO9H3ffYgpCAaYSvXnw2GtOf2SQGaPoLA==", "dev": true, "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", "import-meta-resolve": "^2.2.0", "p-iteration": "^1.1.8" }, @@ -1712,9 +1790,9 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -1731,9 +1809,9 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", + "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" @@ -1746,9 +1824,9 @@ } }, "node_modules/@wdio/selenium-standalone-service/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -1843,6 +1921,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.3.0.tgz", + "integrity": "sha512-TTs3ETVOJtooTIY/u2+feeBnMBx2Hb4SEItN31r0pFncn37rnIZXE/buywLNf5wvZW9ukxoCup5hCnohOR27eQ==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-BbgzxAu4AN99l9hwaRUvkvBJLeIxON7F6ts+vq4LASRiGVRErrwYGeO9H3ffYgpCAaYSvXnw2GtOf2SQGaPoLA==", + "dev": true, + "dependencies": { + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "import-meta-resolve": "^2.2.0", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -1867,9 +1972,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "bin": { "acorn": "bin/acorn" }, @@ -2158,13 +2263,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true, - "peer": true - }, "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -2276,26 +2374,6 @@ "node": ">=0.10.0" } }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "peer": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2372,6 +2450,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -2384,22 +2471,11 @@ "node": ">= 4.5.0" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true, - "peer": true + "node_modules/b4a": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.1.tgz", + "integrity": "sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA==", + "dev": true }, "node_modules/bach": { "version": "1.2.0", @@ -2504,16 +2580,6 @@ "node": ">= 0.8" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "peer": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -2580,160 +2646,51 @@ } }, "node_modules/blockly": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-9.0.0.tgz", - "integrity": "sha512-V8rAT3N4QJ5r2emMGAf8D/yhwmAEfMnu/JVXmcvmS6dFcWR8g8aVlYpjTjW3CH8FyAPTrav2JalLqSfdc8TPpg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-9.2.0.tgz", + "integrity": "sha512-rygZJupS5u4DMGGQ70gExH71c34vUEUjTVVBzhgVH7PCAK2RaitCNwr2yF6hGj/QTVodkjjEOdTzbHqLbuPipQ==", "dev": true, "peer": true, "dependencies": { - "jsdom": "15.2.1" - } - }, - "node_modules/blockly/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/blockly/node_modules/acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "peer": true, - "dependencies": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - } - }, - "node_modules/blockly/node_modules/acorn-globals/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/blockly/node_modules/acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/blockly/node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true, - "peer": true - }, - "node_modules/blockly/node_modules/data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "peer": true, - "dependencies": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - } - }, - "node_modules/blockly/node_modules/domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "peer": true, - "dependencies": { - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/blockly/node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "peer": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/blockly/node_modules/html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "peer": true, - "dependencies": { - "whatwg-encoding": "^1.0.1" + "jsdom": "20.0.3" } }, "node_modules/blockly/node_modules/jsdom": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", - "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "peer": true, "dependencies": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", - "xml-name-validator": "^3.0.0" + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.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.2", + "parse5": "^7.1.1", + "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": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=14" }, "peerDependencies": { "canvas": "^2.5.0" @@ -2744,194 +2701,6 @@ } } }, - "node_modules/blockly/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/blockly/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "peer": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/blockly/node_modules/parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", - "dev": true, - "peer": true - }, - "node_modules/blockly/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/blockly/node_modules/saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", - "dev": true, - "peer": true, - "dependencies": { - "xmlchars": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/blockly/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/blockly/node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "peer": true, - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/blockly/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/blockly/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/blockly/node_modules/w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", - "dev": true, - "peer": true, - "dependencies": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" - } - }, - "node_modules/blockly/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true, - "peer": true - }, - "node_modules/blockly/node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "peer": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/blockly/node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true, - "peer": true - }, - "node_modules/blockly/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "peer": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/blockly/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/blockly/node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true, - "peer": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2954,13 +2723,6 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true, - "peer": true - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -3134,13 +2896,6 @@ "node": ">=8" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "peer": true - }, "node_modules/chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -3416,9 +3171,9 @@ } }, "node_modules/closure-calculate-chunks": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/closure-calculate-chunks/-/closure-calculate-chunks-3.0.3.tgz", - "integrity": "sha512-xtDmQORvSXfgT+6Xkde1RYTHsowCwqyHL92WdG4ZJKJ4bpu+A9yWK32kr4gInZEKRSAS0QrCrkXQJq4bOD5cJA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/closure-calculate-chunks/-/closure-calculate-chunks-3.1.1.tgz", + "integrity": "sha512-Ne/UCDBxiPsco9o+xB0BxFrAdn+G4eljNaj6zLELAbrrGpI2o1l3PPF8yuQ93mLG5Jbm8H73f+n4mbh3S8O8vA==", "dev": true, "dependencies": { "acorn": "8.x", @@ -3426,7 +3181,7 @@ "graphlib": "2.x", "open": "7.x", "resolve": "1.x", - "sigma": "1.x", + "sigma": "1.2.1", "temp": "0.x", "yargs": "16.x" }, @@ -3548,12 +3303,12 @@ } }, "node_modules/commander": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", - "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14" } }, "node_modules/comment-parser": { @@ -3834,12 +3589,16 @@ "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "peer": true }, "node_modules/cssstyle": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "peer": true, "dependencies": { "cssom": "~0.3.6" }, @@ -3850,7 +3609,9 @@ "node_modules/cssstyle/node_modules/cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "peer": true }, "node_modules/d": { "version": "1.0.1", @@ -3862,19 +3623,6 @@ "type": "^1.0.1" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/dat.gui": { "version": "0.7.7", "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.7.tgz", @@ -3885,6 +3633,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "peer": true, "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", @@ -3984,9 +3734,9 @@ } }, "node_modules/decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==" + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, "node_modules/decode-uri-component": { "version": "0.2.2", @@ -4141,21 +3891,21 @@ } }, "node_modules/devtools": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.0.11.tgz", - "integrity": "sha512-qDe9RBgbDQNhVCE2GgNFUYeOQ9BDrTz3HxMVhv/1djyILkBd/dRoYUVgPsiIIWwtsoe/8gAh05sbYkwL1uTJvQ==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.3.11.tgz", + "integrity": "sha512-Wevpd4fZqCveNJv4qSpT+dER5UARLVffpeSEBLBqtrvrNZ6e39x2jWgb838Kf6okuIHWWBXq0IJuRpMda50mXw==", "dev": true, "dependencies": { - "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@types/node": "^18.0.0", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "chrome-launcher": "^0.15.0", - "edge-paths": "^2.1.0", + "edge-paths": "^3.0.5", "import-meta-resolve": "^2.1.0", - "puppeteer-core": "19.4.0", + "puppeteer-core": "19.7.1", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", "uuid": "^9.0.0", @@ -4166,223 +3916,11 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1078443", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1078443.tgz", - "integrity": "sha512-a/rOMs0PrCtcJ6RKPSK5JdFqQoitF5ZeKr+YscKYpuwkzPoFr470CU8+jrej0hpVgRpqg+K0wfAkWiGB7MkhHg==", + "version": "0.0.1103684", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1103684.tgz", + "integrity": "sha512-44Qr4zFQkzW8r4WdDOSuQoxIzPDczY/K1RDfyxzEsiG2nSzbTojDW3becX5+HrDw3gENG8jY6ffbHZ2/Ix5LSA==", "dev": true }, - "node_modules/devtools/node_modules/@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/devtools/node_modules/@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "dependencies": { - "@types/node": "^18.0.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/devtools/node_modules/@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/devtools/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/devtools/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/devtools/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/devtools/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/devtools/node_modules/locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "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/devtools/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/devtools/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/devtools/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/devtools/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/devtools/node_modules/read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/devtools/node_modules/read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/devtools/node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/devtools/node_modules/which": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", @@ -4398,28 +3936,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/devtools/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/diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", - "dev": true, - "optional": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4503,12 +4019,6 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -4543,25 +4053,20 @@ "node": ">=0.10.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "peer": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/edge-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.2.1.tgz", - "integrity": "sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", "dev": true, "dependencies": { - "@types/which": "^1.3.2", + "@types/which": "^2.0.1", "which": "^2.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" } }, "node_modules/emoji-regex": { @@ -4750,13 +4255,13 @@ } }, "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -4775,7 +4280,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -4818,9 +4323,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.6.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", - "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.0.0.tgz", + "integrity": "sha512-LOPyIu1vAVvGPkye3ci0moj0iNf3f8bmin6do2DYDj+77NRXWnkmhKRy8swWsatUs3mB5jYPWPUsFg9pyfEiyA==", "dev": true, "dependencies": { "@es-joy/jsdoccomment": "~0.36.1", @@ -4909,9 +4414,9 @@ } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -5036,6 +4541,15 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", @@ -5185,41 +4699,6 @@ "node": ">=0.10.0" } }, - "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "dev": true, - "optional": true, - "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/expect-webdriverio": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.0.1.tgz", - "integrity": "sha512-+FhdO0w/HI0ur4OnVphuGPU/E3rXlLqfSjiABfMgd1jw+X2tQxGU63bCUA2GlocWl5/ZuVmV/ulEd8pYgniWYg==", - "dev": true, - "optional": true, - "dependencies": { - "expect": "^29.3.1", - "jest-matcher-utils": "^29.3.1" - }, - "engines": { - "node": ">=16 || >=18 || >=20" - }, - "optionalDependencies": { - "@wdio/globals": "^8.0.0-alpha.505", - "webdriverio": "^8.0.0-alpha.505" - } - }, "node_modules/ext": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", @@ -5326,16 +4805,6 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "peer": true - }, "node_modules/fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -5357,6 +4826,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", + "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -5564,6 +5039,21 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", @@ -5621,16 +5111,6 @@ "node": ">=0.10.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -5741,19 +5221,18 @@ "dev": true }, "node_modules/gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.0.2.tgz", + "integrity": "sha512-TjtV2AJOZoMQqRYoy5eM8cCQogYwazWNYLQ72QB0kwa6vHHruYkGmhhyrlzbmgNHK1dNnuP2WSH81urfzyN2Og==", "dev": true, "dependencies": { - "abort-controller": "^3.0.0", "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" + "node-fetch": "^2.6.7" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/get-caller-file": { @@ -5812,16 +5291,6 @@ "node": ">=0.10.0" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -6164,9 +5633,9 @@ } }, "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6223,13 +5692,13 @@ } }, "node_modules/google-closure-compiler": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20221004.0.0.tgz", - "integrity": "sha512-OKENLrZFF2o3FZ/E4zdTc9NeuAUh1fdwbQxT0sibI19aR62sgNUBo2mLU6sc4Gcm0cQ2gwfB7qX1xnapOIkbaA==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20230206.0.0.tgz", + "integrity": "sha512-gGscQOcO/75AlHyw78v87u0nGKJHWqOrQ224Ks91HH1iISgF+xZ8GYosU/8s5VD66x3VD0tJKXM2rIoGOA1ycA==", "dev": true, "dependencies": { "chalk": "4.x", - "google-closure-compiler-java": "^20221004.0.0", + "google-closure-compiler-java": "^20230206.0.0", "minimist": "1.x", "vinyl": "2.x", "vinyl-sourcemaps-apply": "^0.2.0" @@ -6241,21 +5710,21 @@ "node": ">=10" }, "optionalDependencies": { - "google-closure-compiler-linux": "^20221004.0.0", - "google-closure-compiler-osx": "^20221004.0.0", - "google-closure-compiler-windows": "^20221004.0.0" + "google-closure-compiler-linux": "^20230206.0.0", + "google-closure-compiler-osx": "^20230206.0.0", + "google-closure-compiler-windows": "^20230206.0.0" } }, "node_modules/google-closure-compiler-java": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20221004.0.0.tgz", - "integrity": "sha512-CygLEB40HxtK0VtP6klv2Xm08w4HQNYX/DTgLV7CP74r8LiQMUByRFleaG/Hv5xQG1JzPNiW0GOAiAubDSdr5A==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20230206.0.0.tgz", + "integrity": "sha512-OcnDf29yx4JNU13HpptADI2ckl9hEchktSHs2XSLQ/xStUAJQGQOl96to5IYh2VuFgn3Ssaw6M3c6At2pJr7wQ==", "dev": true }, "node_modules/google-closure-compiler-linux": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20221004.0.0.tgz", - "integrity": "sha512-B6sca3Lmw3cYXdFzdU0iQpk8L9VEo1ecC1aM7Gl9lgWhIicqqEZebsgnUe5TQ3uHBfQoKjV9fdFG8mt8X/oqSQ==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20230206.0.0.tgz", + "integrity": "sha512-06N6w2elsnZMMA4Gf/vN2A3XzWvu+gUTrBczaw0KQL48GgdLq6OgAXrcopbGdi/K8Gz1WAcG0qf2ccG8dSqYNg==", "cpu": [ "x32", "x64" @@ -6267,9 +5736,9 @@ ] }, "node_modules/google-closure-compiler-osx": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20221004.0.0.tgz", - "integrity": "sha512-z5V7BvaMauPga8DMTt9u6RGcjBdLAuv4gL2Ebw5NIQRTAHVkEVzCd3kiMX7CVCGhmWdS/1r3jZcCg4BswGia6w==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20230206.0.0.tgz", + "integrity": "sha512-lJ/Y4HTk+KdL6PhLmmalP/3DdzGK0mS0+htuFP6y4t9+QXiUKnpHWx/VDQ3Fwm2fWEzqDxfhX3R+wC9lBvFiAg==", "cpu": [ "x32", "x64", @@ -6282,9 +5751,9 @@ ] }, "node_modules/google-closure-compiler-windows": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20221004.0.0.tgz", - "integrity": "sha512-JSAWilVa7d65QJYKUr+DmklwKmjkAce6BMD6smqJfdL2dv5OSJ2ydGy73euoBJ4Tka8iQPoaOP+BjLrhIuvqKg==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20230206.0.0.tgz", + "integrity": "sha512-4KPr7XPiOs8g4Ao3T+70egf14avCEne26XF4Mur4Fg5511ym1uEN+NlEyjBOAmfUFfaA7BYDsA8iBzDIetKrnw==", "cpu": [ "x32", "x64" @@ -6296,9 +5765,9 @@ ] }, "node_modules/google-closure-deps": { - "version": "20221102.0.0", - "resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20221102.0.0.tgz", - "integrity": "sha512-6AOcHk8u5DNY/uhJLyHj0M4GLTkqAhscH7iH66QUxSiUlrg55PWdyaWQa4Jg15p4xUWNPf8NFBe6vIdwzwi0Hw==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20230206.0.0.tgz", + "integrity": "sha512-MT0JDygFjCTavsOGfRRE1o3teF/ZZD1a8NbeVlGW0oM3OTY2xkOpoPMvSely4khfFV4i4qqjmlMvtwD8cT7adg==", "dev": true, "dependencies": { "minimatch": "^3.0.4", @@ -6337,9 +5806,9 @@ } }, "node_modules/got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -6822,12 +6291,12 @@ } }, "node_modules/gulp-replace": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.3.tgz", - "integrity": "sha512-HcPHpWY4XdF8zxYkDODHnG2+7a3nD/Y8Mfu3aBgMiCFDW3X2GiOKXllsAmILcxe3KZT2BXoN18WrpEFm48KfLQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.4.tgz", + "integrity": "sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==", "dev": true, "dependencies": { - "@types/node": "^14.14.41", + "@types/node": "*", "@types/vinyl": "^2.0.4", "istextorbinary": "^3.0.0", "replacestream": "^4.0.3", @@ -6837,12 +6306,6 @@ "node": ">=10" } }, - "node_modules/gulp-replace/node_modules/@types/node": { - "version": "14.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.0.tgz", - "integrity": "sha512-0GeIl2kmVMXEnx8tg1SlG6Gg8vkqirrW752KqolYo1PHevhhZN3bhJ67qHj+bQaINhX0Ra3TlWwRvMCd9iEfNQ==", - "dev": true - }, "node_modules/gulp-series": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/gulp-series/-/gulp-series-1.0.2.tgz", @@ -7135,31 +6598,6 @@ "node": ">= 0.10" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "peer": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -7310,9 +6748,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-proxy": { @@ -7369,22 +6807,6 @@ "node": ">=12" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -7410,19 +6832,6 @@ "node": ">= 6" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -7545,16 +6954,6 @@ "node": ">=0.10.0" } }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -7626,9 +7025,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -7854,13 +7253,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true, - "peer": true - }, "node_modules/is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -7942,13 +7334,6 @@ "node": ">=0.10.0" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true, - "peer": true - }, "node_modules/istextorbinary": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", @@ -7965,111 +7350,6 @@ "url": "https://bevry.me/fund" } }, - "node_modules/jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "dev": true, - "optional": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true, - "optional": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "dev": true, - "optional": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, - "optional": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "optional": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, - "optional": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jju": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", @@ -8077,15 +7357,15 @@ "dev": true }, "node_modules/js-green-licenses": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-green-licenses/-/js-green-licenses-3.0.1.tgz", - "integrity": "sha512-dKyO14U6LaDzJ5gNlvP/v1vkTW7TTXEKNxMHnkxqdYStcYVEJlfubfqbEageVzV41PWu7felyNbwawoEJ/RpYQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-green-licenses/-/js-green-licenses-4.0.0.tgz", + "integrity": "sha512-kcgTOaZmpDpINcRAOKKhjHtBN6zibMVTC8qfPUOpowQtI/6fUgdmwJLJ0ycCb0pUO3ZYKn++56sy8IlG60p5mg==", "dev": true, "dependencies": { - "gaxios": "^4.0.0", + "gaxios": "^5.0.0", "meow": "^9.0.0", "npm-package-arg": "^8.0.0", - "package-json": "^6.0.0", + "package-json": "^7.0.0", "semver": "^7.3.2", "spdx-correct": "^3.0.0", "spdx-satisfies": "^5.0.0", @@ -8095,7 +7375,7 @@ "jsgl": "build/src/cli.js" }, "engines": { - "node": ">= 10.x" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/js-sdsl": { @@ -8122,13 +7402,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true, - "peer": true - }, "node_modules/jsdoc-type-pratt-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", @@ -8139,17 +7412,16 @@ } }, "node_modules/jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.1.tgz", + "integrity": "sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==", "dependencies": { "abab": "^2.0.6", - "acorn": "^8.8.1", + "acorn": "^8.8.2", "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", @@ -8158,7 +7430,8 @@ "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.2", - "parse5": "^7.1.1", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", @@ -8166,8 +7439,8 @@ "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", "xml-name-validator": "^4.0.0" }, "engines": { @@ -8182,6 +7455,73 @@ } } }, + "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": { + "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": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "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": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -8194,13 +7534,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "peer": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -8213,17 +7546,10 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "peer": true - }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -8244,22 +7570,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "peer": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/just-curry-it": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-5.2.1.tgz", @@ -8306,9 +7616,9 @@ } }, "node_modules/ky": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/ky/-/ky-0.32.2.tgz", - "integrity": "sha512-eBJeF6IXNwX5rksdwBrE2rIJrU2d84GoTvdM7OmmTIwUVXEMd72wIwvT+nyhrqtv7AzbSNsWz7yRsHgVhj1uog==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.2.tgz", + "integrity": "sha512-f6oS2rKUcPu5FzdqCDbFpmzis/JlqFZw8uIHm/jf8Kc3vtnW+VDhuashOAKyBZv8bFiZFZUMNxTC0JtahEvujA==", "dev": true, "engines": { "node": ">=14.16" @@ -8642,13 +7952,6 @@ "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", "dev": true }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true, - "peer": true - }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -9168,15 +8471,18 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", + "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==", "dev": true, "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mkdirp-classic": { @@ -9186,9 +8492,9 @@ "dev": true }, "node_modules/mocha": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", - "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { "ansi-colors": "4.1.1", @@ -9543,16 +8849,6 @@ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9878,178 +9174,21 @@ } }, "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", + "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", "dev": true, "dependencies": { - "got": "^9.6.0", + "got": "^11.8.2", "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", - "semver": "^6.2.0" + "semver": "^7.3.5" }, "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json/node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" + "node": ">=12" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json/node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/package-json/node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "node_modules/package-json/node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/package-json/node_modules/got/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json/node_modules/got/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/package-json/node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "node_modules/package-json/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/package-json/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json/node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/package-json/node_modules/responselike/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/parent-module": { @@ -10115,9 +9254,9 @@ } }, "node_modules/parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dependencies": { "entities": "^4.4.0" }, @@ -10135,16 +9274,16 @@ } }, "node_modules/patch-package": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.0.tgz", - "integrity": "sha512-tC3EqJmo74yKqfsMzELaFwxOAu6FH6t+FzFOsnWAuARm7/n2xB5AOeOueE221eM9gtMuIKMKpF9tBy/X2mNP0Q==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", "dev": true, "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "cross-spawn": "^6.0.5", "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^7.0.1", + "fs-extra": "^9.0.0", "is-ci": "^2.0.0", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", @@ -10180,26 +9319,18 @@ } }, "node_modules/patch-package/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==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/patch-package/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": ">=10" } }, "node_modules/patch-package/node_modules/path-key": { @@ -10262,15 +9393,6 @@ "node": ">=6" } }, - "node_modules/patch-package/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/patch-package/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -10396,13 +9518,6 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true, - "peer": true - }, "node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", @@ -10478,13 +9593,6 @@ "node": ">=0.10.0" } }, - "node_modules/pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true, - "peer": true - }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -10573,43 +9681,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, - "optional": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -10631,6 +9702,15 @@ "node": ">=0.8" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10695,59 +9775,65 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "engines": { "node": ">=6" } }, "node_modules/puppeteer-core": { - "version": "19.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.4.0.tgz", - "integrity": "sha512-gG/jxseleZStinBn86x8r7trjcE4jcjx1hIQWOpACQhquHYMuKnrWxkzg+EDn8sN3wUtF/Ry9mtJgjM49oUOFQ==", + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.1.tgz", + "integrity": "sha512-4b5Go25IA+0xrUIw0Qtqi4nxc0qwdu/C7VT1+tFPl1W27207YT+7bxfANC3PjXMlS6bcbzinCf5YfGqMl8tfyQ==", "dev": true, "dependencies": { "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1068969", + "devtools-protocol": "0.0.1094867", "extract-zip": "2.0.1", "https-proxy-agent": "5.0.1", "proxy-from-env": "1.1.0", "rimraf": "3.0.2", "tar-fs": "2.1.1", "unbzip2-stream": "1.4.3", - "ws": "8.10.0" + "ws": "8.11.0" }, "engines": { "node": ">=14.1.0" + }, + "peerDependencies": { + "chromium-bidi": "0.4.3", + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "chromium-bidi": { + "optional": true + }, + "typescript": { + "optional": true + } } }, "node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1068969", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1068969.tgz", - "integrity": "sha512-ATFTrPbY1dKYhPPvpjtwWKSK2mIwGmRwX54UASn9THEuIZCe2n9k3vVuMmt6jWeL+e5QaaguEv/pMyR+JQB7VQ==", + "version": "0.0.1094867", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", + "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==", "dev": true }, - "node_modules/puppeteer-core/node_modules/ws": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", - "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "node_modules/puppeteer-core/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "engines": { - "node": ">=10.0.0" + "dependencies": { + "glob": "^7.1.3" }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "bin": { + "rimraf": "bin.js" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/qs": { @@ -10790,6 +9876,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -10829,19 +9921,12 @@ "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true, - "optional": true - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -11067,12 +10152,12 @@ } }, "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", "dev": true, "dependencies": { - "rc": "^1.2.8" + "rc": "1.2.8" }, "engines": { "node": ">=6.0.0" @@ -11194,117 +10279,6 @@ "node": ">=0.8.0" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "peer": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "peer": true, - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dev": true, - "peer": true, - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "peer": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "peer": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "peer": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -11326,13 +10300,17 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11435,20 +10413,25 @@ "dev": true }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.1.2.tgz", + "integrity": "sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11525,12 +10508,12 @@ "dev": true }, "node_modules/selenium-standalone": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-8.2.4.tgz", - "integrity": "sha512-VXkiQFAmXGlcE6X5A9dakXbXuxJONqG/t39Cw4ylk7J+hxIYBk/yfJ0Tkh2P0X9QGRpcUfr0hgE0PHDil0nFiA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-8.3.0.tgz", + "integrity": "sha512-cQVWQGxumvPnyzFNtzFtBfDCbqBsdEnwiOwRyrAzeUqf5ltAp3Z3+2f6asSFbLUQJs2sFuF6PsEyNA+eOzXKxg==", "dev": true, "dependencies": { - "commander": "^9.0.0", + "commander": "^10.0.0", "cross-spawn": "^7.0.3", "debug": "^4.3.1", "fs-extra": "^10.0.0", @@ -11539,9 +10522,9 @@ "lodash.mapvalues": "^4.6.0", "lodash.merge": "^4.6.2", "minimist": "^1.2.5", - "mkdirp": "^1.0.4", + "mkdirp": "^2.1.3", "progress": "2.0.3", - "tar-stream": "2.2.0", + "tar-stream": "3.0.0", "which": "^2.0.2", "yauzl": "^2.10.0" }, @@ -11553,6 +10536,67 @@ "npm": ">=6.0.0" } }, + "node_modules/selenium-standalone/node_modules/bl": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", + "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "node_modules/selenium-standalone/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/selenium-standalone/node_modules/readable-stream": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", + "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/selenium-standalone/node_modules/tar-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.0.0.tgz", + "integrity": "sha512-O6OfUKBbQOqAhh6owTWmA730J/yZCYcpmZ1DBj2YX51ZQrt7d7NgzrR+CnO9wP6nt/viWZW2XeXLavX3/ZEbEg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.1", + "bl": "^6.0.0", + "streamx": "^2.12.5" + } + }, "node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -12061,32 +11105,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "peer": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -12096,29 +11114,6 @@ "node": "*" } }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -12206,16 +11201,6 @@ "node": ">=0.10.0" } }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stream-combiner": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", @@ -12302,6 +11287,16 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, + "node_modules/streamx": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.13.2.tgz", + "integrity": "sha512-+TWqixPhGDXEG9L/XczSbhfkmwAtGs3BJX5QNU6cvno+pOLKeszByWcnaTu6dg8efsTYqR8ZZuXWHhZfgrxMvA==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -12412,6 +11407,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", @@ -12641,15 +11648,6 @@ "node": ">=0.10.0" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -12734,6 +11732,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.1" }, @@ -12780,26 +11780,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "peer": true - }, "node_modules/type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", @@ -12846,22 +11826,22 @@ "dev": true }, "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true, "funding": [ { @@ -13076,18 +12056,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -13104,14 +12072,12 @@ "dev": true }, "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true, - "peer": true, "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/v8flags": { @@ -13163,28 +12129,6 @@ "node": ">= 0.10" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "peer": true - }, "node_modules/vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -13288,17 +12232,6 @@ "node": ">= 0.10" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", - "dev": true, - "peer": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -13311,21 +12244,21 @@ } }, "node_modules/webdriver": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.0.11.tgz", - "integrity": "sha512-UK1iLpNltIzOEScd45GOQ4qFTVFMmUwMYDNtVMhX6ASB9yl4Ir3Do66BZ7fyk5+NBvn2VnIx7qrap6FutSbxhQ==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.3.11.tgz", + "integrity": "sha512-1Dw8tN+c+LdnIXizEB+RrH9LbHGuTEDUtPqxT0fd80F+g/RqZvX3bv3ABD7ZVvvdE2ck6XbATnVX2/rYrQxSYQ==", "dev": true, "dependencies": { "@types/node": "^18.0.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "deepmerge-ts": "^4.2.2", "got": "^12.1.0", - "ky": "^0.32.1", + "ky": "^0.33.0", "ws": "^8.8.0" }, "engines": { @@ -13356,61 +12289,6 @@ "node": ">=14.16" } }, - "node_modules/webdriver/node_modules/@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriver/node_modules/@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "dependencies": { - "@types/node": "^18.0.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriver/node_modules/@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriver/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/webdriver/node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -13421,14 +12299,14 @@ } }, "node_modules/webdriver/node_modules/cacheable-request": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.3.tgz", - "integrity": "sha512-6BehRBOs7iurNjAYN9iPazTwFDaMQavJO8W1MEm3s2pH8q/tkPTtLDRUZaweWK87WFGf2Y5wLAlaCJlR5kOz3w==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.8.tgz", + "integrity": "sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==", "dev": true, "dependencies": { "@types/http-cache-semantics": "^4.0.1", "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.0", + "http-cache-semantics": "^4.1.1", "keyv": "^4.5.2", "mimic-response": "^4.0.0", "normalize-url": "^8.0.0", @@ -13438,34 +12316,6 @@ "node": ">=14.16" } }, - "node_modules/webdriver/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webdriver/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/webdriver/node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -13478,25 +12328,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webdriver/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/webdriver/node_modules/got": { "version": "12.5.3", "resolved": "https://registry.npmjs.org/got/-/got-12.5.3.tgz", @@ -13535,21 +12366,6 @@ "node": ">=10.19.0" } }, - "node_modules/webdriver/node_modules/locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "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/webdriver/node_modules/lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -13574,18 +12390,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webdriver/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/webdriver/node_modules/normalize-url": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", @@ -13607,80 +12411,6 @@ "node": ">=12.20" } }, - "node_modules/webdriver/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/webdriver/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/webdriver/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/webdriver/node_modules/read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webdriver/node_modules/read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/webdriver/node_modules/responselike": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", @@ -13696,97 +12426,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webdriver/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/webdriverio": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.0.12.tgz", - "integrity": "sha512-KCQ+ePhbNTvKP635bz11ADuq9oMjU99tUCgst6difwFPYUg43HYyx5b5CTGl9LrTMqwoJ5UWoIBxjtyS216n6w==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.3.11.tgz", + "integrity": "sha512-sN2jmkwSQj0r9IRLvpzfmLh/OvX3l4G+l+W26ksoLr+qxdOfRmoNfxc4CGMt/Uin515ajajqPWrxFFbdeL3uIQ==", "dev": true, "dependencies": { - "@types/aria-query": "^5.0.0", "@types/node": "^18.0.0", - "@wdio/config": "8.0.11", - "@wdio/globals": "8.0.12", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/repl": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/repl": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "8.0.11", - "devtools-protocol": "^0.0.1078443", + "devtools": "8.3.11", + "devtools-protocol": "^0.0.1103684", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^2.1.0", "is-plain-obj": "^4.1.0", "lodash.clonedeep": "^4.5.0", "lodash.zip": "^4.2.0", - "minimatch": "^5.0.0", - "puppeteer-core": "19.4.0", + "minimatch": "^7.0.0", + "puppeteer-core": "19.7.1", "query-selector-shadow-dom": "^1.0.0", "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "8.0.11" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriverio/node_modules/@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriverio/node_modules/@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "dependencies": { - "@types/node": "^18.0.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/webdriverio/node_modules/@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "dependencies": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" + "webdriver": "8.3.11" }, "engines": { "node": "^16.13 || >=18" @@ -13801,53 +12471,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/webdriverio/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webdriverio/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/webdriverio/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/webdriverio/node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -13860,117 +12483,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webdriverio/node_modules/locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "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/webdriverio/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.2.0.tgz", + "integrity": "sha512-rMRHmwySzopAQjmWW6TkAKCEDKNaY/HuV/c2YkWWuWnfkTwApt0V4hnYzzPnZ/5Gcd2+8MPncSyuOGPl3xPvcg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" - } - }, - "node_modules/webdriverio/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/webdriverio/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/webdriverio/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/webdriverio/node_modules/read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webdriverio/node_modules/read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webdriverio/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" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/webidl-conversions": { @@ -14015,6 +12540,8 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "peer": true, "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -14085,6 +12612,7 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, "engines": { "node": ">=10.0.0" }, @@ -14148,9 +12676,9 @@ } }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "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", @@ -14400,23 +12928,23 @@ } }, "@blockly/block-test": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-3.0.1.tgz", - "integrity": "sha512-lXHwyAFiLNAmDS3BvBscy7S4YfKt8U8yMghop/j5G3nUz5gKWQGMtUJDq7Wm5ZpIFHghYDPxnhdpwhdCkuRchA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-3.0.8.tgz", + "integrity": "sha512-foW4fVKCrrmeImXNgVJZ+XjMENpOz3z3P/ob1IxixPnQ3QyO2Yjh0rfPDkSteJjto5k9Q+XhcvlW1w42gyjIKg==", "dev": true, "requires": {} }, "@blockly/dev-tools": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-5.0.2.tgz", - "integrity": "sha512-3h9nbpbrz8+YCbQlkpIJh1YXmlSmslxzibdPvc6VcgzXA+xzAc2a00Wy5f+ugQRq2394J8Cn/cKXqUKDLjykRA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-5.2.4.tgz", + "integrity": "sha512-7FF5PByhq9EhKeYty0GFZp8b7l3qWrEIiqyVTgp/xN7iI/9N6scsDVZfCWVDSmZHgiaTHkEcQW/697IRm69HDA==", "dev": true, "requires": { - "@blockly/block-test": "^3.0.1", - "@blockly/theme-dark": "^4.0.1", - "@blockly/theme-deuteranopia": "^3.0.1", - "@blockly/theme-highcontrast": "^3.0.1", - "@blockly/theme-tritanopia": "^3.0.2", + "@blockly/block-test": "^3.0.8", + "@blockly/theme-dark": "^4.0.7", + "@blockly/theme-deuteranopia": "^3.0.7", + "@blockly/theme-highcontrast": "^3.0.7", + "@blockly/theme-tritanopia": "^3.0.8", "chai": "^4.2.0", "dat.gui": "^0.7.7", "lodash.assign": "^4.2.0", @@ -14426,37 +12954,37 @@ } }, "@blockly/theme-dark": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-4.0.1.tgz", - "integrity": "sha512-OIfdnt3kvPnEW/TmfLPUftcekwoQGmxg/12LajYUdW9aOLMQaen16Vw0+BB8Q8zKInpxT6JCBYECilYRLY+RpA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-4.0.7.tgz", + "integrity": "sha512-NegmW6DxvDISxonJ8gtp/CGxYZmtNYyjR2t7V5GzwnZhU1QV1aZVJk49f3CbFftQm3W93wHZ9HQn80oTbOCbiQ==", "dev": true, "requires": {} }, "@blockly/theme-deuteranopia": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-3.0.1.tgz", - "integrity": "sha512-3zmkD3ERGAuKQjAeFFoNNAhfwmxFncXd3Mw5tHn64MlxguMJCKt7C4Siu6gRXGYpvukkpMUlbgklWyNz2okHng==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-3.0.7.tgz", + "integrity": "sha512-51NF9RqqiskCefMPwMO9JS5l+Q1ubyryx5XUwNV7Dl8LljmyaQzBy2xu6MVIG/yZDY1qR7oS2scsyOffb++oFQ==", "dev": true, "requires": {} }, "@blockly/theme-highcontrast": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-3.0.1.tgz", - "integrity": "sha512-HuEHKq7n2zTV1gb19SGjyKlCYjZeZSITWPIQeD5wfEVleOOy8z6zjLRZ9D7QoiL4ooFefWkx1kauVsWbaTqN5g==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-3.0.7.tgz", + "integrity": "sha512-uwpDXhcXXaXxWT1xkWECUBD0ao1+hzK9iLf5FWktnSqfyj6galLVjB2mxRb3ZTaVuhjvw7/qhjYzVPqzL2NKgg==", "dev": true, "requires": {} }, "@blockly/theme-modern": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-3.0.1.tgz", - "integrity": "sha512-rKB5NrAGFF+Vo4aIfk+zbXZYfKDULPMFNWkT5dS0cyMSNHvcy7Xgi3llq29YhTG/LLicOjitSc8cErcZsicjng==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-3.0.6.tgz", + "integrity": "sha512-A59AMr3hZRHugC3qGSpZ2gtGlQkuWtj2qj7B5jLbVoSKNJuPRJt1DKQElvriev5GhangjSmrQZULPhAAIEXLsQ==", "dev": true, "requires": {} }, "@blockly/theme-tritanopia": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-3.0.2.tgz", - "integrity": "sha512-soKspGnVLk+EVuWm8HfRSmZoK5NoThpgIS9uvctSNUaEB3Ritvf/feuqu4AFBEjwAUUgkY1SfW70200ZIXRY8g==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-3.0.8.tgz", + "integrity": "sha512-17n3LAFwOJHkBeeVUYoRZ+ATSDpmOQuP41n9ZxDb0N3VbnjkFEVRT+saG3wQgcHD6F7KoVHkK2GChbmcYrU+Ig==", "dev": true, "requires": {} }, @@ -14471,16 +12999,31 @@ "jsdoc-type-pratt-parser": "~3.1.0" } }, + "@eslint-community/eslint-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", + "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -14557,9 +13100,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -14640,50 +13183,15 @@ } } }, - "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "dev": true, - "optional": true, - "requires": { - "jest-get-type": "^29.2.0" - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "optional": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, - "optional": true, - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, "@microsoft/api-documenter": { - "version": "7.19.25", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.19.25.tgz", - "integrity": "sha512-/yC6cG7QpjkDqHvoXt5SJJdB0Mdj0oYpaWgxdOV8uHRniZ9kZwxAEResswdS6QDCYoyqDD6jlh008HwXIcmXjA==", + "version": "7.19.26", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.19.26.tgz", + "integrity": "sha512-sFhYmO8k6CMFJ20D/LP1B7GdH+JfwmSKO/xTXnm63WA3+AX7g94G4TlKlc1FXdHFS2qhHnlm4qZUD3fgfs1vqg==", "dev": true, "requires": { - "@microsoft/api-extractor-model": "7.25.2", + "@microsoft/api-extractor-model": "7.25.3", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.53.2", + "@rushstack/node-core-library": "3.53.3", "@rushstack/ts-command-line": "4.13.1", "colors": "~1.2.1", "js-yaml": "~3.13.1", @@ -14721,57 +13229,71 @@ } }, "@microsoft/api-extractor": { - "version": "7.33.7", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.33.7.tgz", - "integrity": "sha512-fQT2v/j/55DhvMFiopLtth66E7xTFNhnumMKgKY14SaG6qU/V1W0e4nOAgbA+SmLakQjAd1Evu06ofaVaxBPbA==", + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.34.4.tgz", + "integrity": "sha512-HOdcci2nT40ejhwPC3Xja9G+WSJmWhCUKKryRfQYsmE9cD+pxmBaKBKCbuS9jUcl6bLLb4Gz+h7xEN5r0QiXnQ==", "dev": true, "requires": { - "@microsoft/api-extractor-model": "7.25.3", + "@microsoft/api-extractor-model": "7.26.4", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.53.3", - "@rushstack/rig-package": "0.3.17", - "@rushstack/ts-command-line": "4.13.1", + "@rushstack/node-core-library": "3.55.2", + "@rushstack/rig-package": "0.3.18", + "@rushstack/ts-command-line": "4.13.2", "colors": "~1.2.1", "lodash": "~4.17.15", - "resolve": "~1.17.0", + "resolve": "~1.22.1", "semver": "~7.3.0", "source-map": "~0.6.1", "typescript": "~4.8.4" }, "dependencies": { "@microsoft/api-extractor-model": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.25.3.tgz", - "integrity": "sha512-WWxBUq77p2iZ+5VF7Nmrm3y/UtqCh5bYV8ii3khwq3w99+fXWpvfsAhgSLsC7k8XDQc6De4ssMxH6He/qe1pzg==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.26.4.tgz", + "integrity": "sha512-PDCgCzXDo+SLY5bsfl4bS7hxaeEtnXj7XtuzEE+BtALp7B5mK/NrS2kHWU69pohgsRmEALycQdaQPXoyT2i5MQ==", "dev": true, "requires": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.53.3" + "@rushstack/node-core-library": "3.55.2" } }, "@rushstack/node-core-library": { - "version": "3.53.3", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.3.tgz", - "integrity": "sha512-H0+T5koi5MFhJUd5ND3dI3bwLhvlABetARl78L3lWftJVQEPyzcgTStvTTRiIM5mCltyTM8VYm6BuCtNUuxD0Q==", + "version": "3.55.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.55.2.tgz", + "integrity": "sha512-SaLe/x/Q/uBVdNFK5V1xXvsVps0y7h1sN7aSJllQyFbugyOaxhNRF25bwEDnicARNEjJw0pk0lYnJQ9Kr6ev0A==", "dev": true, "requires": { - "@types/node": "12.20.24", "colors": "~1.2.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", - "resolve": "~1.17.0", + "resolve": "~1.22.1", "semver": "~7.3.0", "z-schema": "~5.0.2" } }, - "@types/node": { - "version": "12.20.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true + "@rushstack/ts-command-line": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.13.2.tgz", + "integrity": "sha512-bCU8qoL9HyWiciltfzg7GqdfODUeda/JpI0602kbN5YH22rzTxyqYvv7aRLENCM7XCQ1VRs7nMkEqgJUOU8Sag==", + "dev": true, + "requires": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } }, "fs-extra": { "version": "7.0.1", @@ -14793,15 +13315,6 @@ "graceful-fs": "^4.1.6" } }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -14823,14 +13336,14 @@ } }, "@microsoft/api-extractor-model": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.25.2.tgz", - "integrity": "sha512-+h1uCrLQXFAKMUdghhdDcnniDB+6UA/lS9ArlB4QZQ34UbLuXNy2oQ6fafFK8cKXU4mUPTF/yGRjv7JKD5L7eg==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.25.3.tgz", + "integrity": "sha512-WWxBUq77p2iZ+5VF7Nmrm3y/UtqCh5bYV8ii3khwq3w99+fXWpvfsAhgSLsC7k8XDQc6De4ssMxH6He/qe1pzg==", "dev": true, "requires": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.53.2" + "@rushstack/node-core-library": "3.53.3" } }, "@microsoft/tsdoc": { @@ -14890,9 +13403,9 @@ } }, "@rushstack/node-core-library": { - "version": "3.53.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.2.tgz", - "integrity": "sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA==", + "version": "3.53.3", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.3.tgz", + "integrity": "sha512-H0+T5koi5MFhJUd5ND3dI3bwLhvlABetARl78L3lWftJVQEPyzcgTStvTTRiIM5mCltyTM8VYm6BuCtNUuxD0Q==", "dev": true, "requires": { "@types/node": "12.20.24", @@ -14949,24 +13462,13 @@ } }, "@rushstack/rig-package": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.17.tgz", - "integrity": "sha512-nxvAGeIMnHl1LlZSQmacgcRV4y1EYtgcDIrw6KkeVjudOMonlxO482PhDj3LVZEp6L7emSf6YSO2s5JkHlwfZA==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.18.tgz", + "integrity": "sha512-SGEwNTwNq9bI3pkdd01yCaH+gAsHqs0uxfGvtw9b0LJXH52qooWXnrFTRRLG1aL9pf+M2CARdrA9HLHJys3jiQ==", "dev": true, "requires": { - "resolve": "~1.17.0", + "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" - }, - "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } } }, "@rushstack/ts-command-line": { @@ -14992,13 +13494,6 @@ } } }, - "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true, - "optional": true - }, "@sindresorhus/is": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", @@ -15077,12 +13572,6 @@ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true }, - "@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", - "dev": true - }, "@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -15107,33 +13596,6 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true, - "optional": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "optional": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "optional": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -15176,34 +13638,12 @@ "@types/node": "*" } }, - "@types/selenium-standalone": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@types/selenium-standalone/-/selenium-standalone-7.0.1.tgz", - "integrity": "sha512-zbKenL0fAXzPyiOaaFMrvFdMNhj5BgNJQq8bxiZfwQD9ID2J8bUG5xbcS3tQtlzIX/62z9nG5Vo45oaHWTbvbw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true, - "optional": true - }, - "@types/ua-parser-js": { - "version": "0.7.36", - "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz", - "integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==", - "dev": true - }, "@types/vinyl": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.6.tgz", @@ -15215,37 +13655,20 @@ } }, "@types/which": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", - "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", "dev": true }, "@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "requires": { "@types/node": "*" } }, - "@types/yargs": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", - "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", - "dev": true, - "optional": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true, - "optional": true - }, "@types/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", @@ -15257,45 +13680,46 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz", - "integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", + "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/type-utils": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/type-utils": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" } }, "@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true }, "@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" } } @@ -15326,31 +13750,31 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz", - "integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", + "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -15359,12 +13783,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" } } @@ -15394,45 +13818,45 @@ } }, "@typescript-eslint/utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz", - "integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", + "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", "dev": true, "requires": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" } }, "@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -15441,12 +13865,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -15473,98 +13897,22 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@wdio/globals": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.0.12.tgz", - "integrity": "sha512-6D/ZXBxHbANOfs1OKtk9g4O6xeGhAMvzvZnwtfkXQ+ywozfdv1oOzqZ/01wQwrRbmVlfLfIoMy9/kcXjtKP13A==", + "@wdio/config": { + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.3.11.tgz", + "integrity": "sha512-sZ1SZkBEZWqSDHqrQxspsrc+OBqf3qyx2c4gVvAovOd1hnT4EcWhlJu1Asp3H0Mti115XstwQabOW4sSsdmVCw==", "dev": true, "requires": { - "expect-webdriverio": "^4.0.1", - "webdriverio": "8.0.12" - } - }, - "@wdio/logger": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.0.0.tgz", - "integrity": "sha512-QEBPZoFQhWqqIYmhp8Wa+HhvMrH2Yy0xbD3MPOibkFwp9Tn8Si7oDxbnWqzcPiukLWcb4E/QlgE5f3IM5BrAPQ==", - "dev": true, - "requires": { - "chalk": "^5.1.2", - "loglevel": "^1.6.0", - "loglevel-plugin-prefix": "^0.8.4", - "strip-ansi": "^6.0.0" + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^4.2.2", + "glob": "^8.0.3", + "import-meta-resolve": "^2.1.0", + "read-pkg-up": "^9.1.0" }, "dependencies": { - "chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", - "dev": true - } - } - }, - "@wdio/protocols": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.0.0.tgz", - "integrity": "sha512-iTfYOcli/98ubeTqxyP9+OBPQxfbB5cPK6Zv61C9Rr4qQkzx4GPQjn/AlK0r6Bn0dRy/9lGyb2Q3UBRCx85RSQ==", - "dev": true - }, - "@wdio/repl": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.0.0.tgz", - "integrity": "sha512-Qys/t/NioO+LlcDcD+4Agn0JJjIiO6fkqOJJDxv3QulGPCmQ5SaYX+BQyz1o9sGscfr8s/435d+3dkBSO1+3tQ==", - "dev": true - }, - "@wdio/selenium-standalone-service": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-8.0.11.tgz", - "integrity": "sha512-k2dT4AEmqVjYv1UmqoQHdQHqHJq+qkZfXyCKo7MeyG4XZ423ioo+otztATu0NiNT7UNSmBbunBis9nUBGWaoUg==", - "dev": true, - "requires": { - "@types/selenium-standalone": "^7.0.0", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "selenium-standalone": "^8.2.1" - }, - "dependencies": { - "@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - } - }, - "@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "requires": { - "@types/node": "^18.0.0" - } - }, - "@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - } - }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -15591,9 +13939,9 @@ } }, "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -15604,18 +13952,18 @@ } }, "locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", + "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, "requires": { "p-locate": "^6.0.0" } }, "minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -15676,6 +14024,223 @@ } } }, + "@wdio/logger": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.1.0.tgz", + "integrity": "sha512-QRC5b7FF4JIYUCqggnVA0sZ80TwIUFN9JyBSbuGuMxaSLSLujSo7WfuSrnQXVvsRbnJ16wWwJWYigfLkxOW86Q==", + "dev": true, + "requires": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + } + } + }, + "@wdio/protocols": { + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.3.11.tgz", + "integrity": "sha512-EXGuZC4Nvl8QPT6gQ9tpeH+TL9P5oRdQofaJA893OX37gU2OWiSNyA7AHr/0/UIHWFax4udpVQ6syTQsy6uWWA==", + "dev": true + }, + "@wdio/repl": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.1.0.tgz", + "integrity": "sha512-96G4TzbYnRf95+GURo15FYt6iTYq85nbWU6YQedLRAV15RfSp4foKTbAnq++bKKMALNL6gdzTc+HGhQr3Q0sQg==", + "dev": true, + "requires": { + "@types/node": "^18.0.0" + } + }, + "@wdio/selenium-standalone-service": { + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-8.3.11.tgz", + "integrity": "sha512-gRcsaH5KG49r3r3HCOUjG1Mh+1301YJaKgqPyTulaooH5Ia2boEGeI1ijT7F14PBuiuIuha6i3us7TPecgeuVw==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "selenium-standalone": "^8.2.1" + }, + "dependencies": { + "@wdio/config": { + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.3.11.tgz", + "integrity": "sha512-sZ1SZkBEZWqSDHqrQxspsrc+OBqf3qyx2c4gVvAovOd1hnT4EcWhlJu1Asp3H0Mti115XstwQabOW4sSsdmVCw==", + "dev": true, + "requires": { + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^4.2.2", + "glob": "^8.0.3", + "import-meta-resolve": "^2.1.0", + "read-pkg-up": "^9.1.0" + } + }, + "@wdio/types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.3.0.tgz", + "integrity": "sha512-TTs3ETVOJtooTIY/u2+feeBnMBx2Hb4SEItN31r0pFncn37rnIZXE/buywLNf5wvZW9ukxoCup5hCnohOR27eQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0" + } + }, + "@wdio/utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-BbgzxAu4AN99l9hwaRUvkvBJLeIxON7F6ts+vq4LASRiGVRErrwYGeO9H3ffYgpCAaYSvXnw2GtOf2SQGaPoLA==", + "dev": true, + "requires": { + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "import-meta-resolve": "^2.2.0", + "p-iteration": "^1.1.8" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true + }, + "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, + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "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, + "requires": { + "p-locate": "^6.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "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, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "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, + "requires": { + "p-limit": "^4.0.0" + } + }, + "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 + }, + "read-pkg": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", + "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", + "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", + "dev": true, + "requires": { + "find-up": "^6.3.0", + "read-pkg": "^7.1.0", + "type-fest": "^2.5.0" + } + }, + "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 + } + } + }, + "@wdio/types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.3.0.tgz", + "integrity": "sha512-TTs3ETVOJtooTIY/u2+feeBnMBx2Hb4SEItN31r0pFncn37rnIZXE/buywLNf5wvZW9ukxoCup5hCnohOR27eQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0" + } + }, + "@wdio/utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-BbgzxAu4AN99l9hwaRUvkvBJLeIxON7F6ts+vq4LASRiGVRErrwYGeO9H3ffYgpCAaYSvXnw2GtOf2SQGaPoLA==", + "dev": true, + "requires": { + "@wdio/logger": "8.1.0", + "@wdio/types": "8.3.0", + "import-meta-resolve": "^2.2.0", + "p-iteration": "^1.1.8" + } + }, "@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -15697,9 +14262,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" }, "acorn-globals": { "version": "7.0.1", @@ -15915,13 +14480,6 @@ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "dev": true }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true, - "peer": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -16004,23 +14562,6 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "peer": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "peer": true - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -16084,25 +14625,23 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "peer": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true, - "peer": true + "b4a": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.1.tgz", + "integrity": "sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA==", + "dev": true }, "bach": { "version": "1.2.0", @@ -16182,16 +14721,6 @@ "safe-buffer": "5.1.2" } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "peer": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -16245,289 +14774,49 @@ } }, "blockly": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-9.0.0.tgz", - "integrity": "sha512-V8rAT3N4QJ5r2emMGAf8D/yhwmAEfMnu/JVXmcvmS6dFcWR8g8aVlYpjTjW3CH8FyAPTrav2JalLqSfdc8TPpg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-9.2.0.tgz", + "integrity": "sha512-rygZJupS5u4DMGGQ70gExH71c34vUEUjTVVBzhgVH7PCAK2RaitCNwr2yF6hGj/QTVodkjjEOdTzbHqLbuPipQ==", "dev": true, "peer": true, "requires": { - "jsdom": "15.2.1" + "jsdom": "20.0.3" }, "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "peer": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "peer": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "peer": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true, - "peer": true - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true, - "peer": true - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "peer": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - } - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "peer": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "peer": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "peer": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, "jsdom": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", - "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "peer": true, "requires": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", - "xml-name-validator": "^3.0.0" + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.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.2", + "parse5": "^7.1.1", + "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": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "peer": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "peer": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", - "dev": true, - "peer": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "peer": true - }, - "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", - "dev": true, - "peer": true, - "requires": { - "xmlchars": "^2.1.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "peer": true - }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "peer": true, - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "peer": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "peer": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", - "dev": true, - "peer": true, - "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true, - "peer": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "peer": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true, - "peer": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "peer": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, - "peer": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true, - "peer": true } } }, @@ -16550,13 +14839,6 @@ "fill-range": "^7.0.1" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true, - "peer": true - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -16682,13 +14964,6 @@ } } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "peer": true - }, "chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -16909,9 +15184,9 @@ } }, "closure-calculate-chunks": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/closure-calculate-chunks/-/closure-calculate-chunks-3.0.3.tgz", - "integrity": "sha512-xtDmQORvSXfgT+6Xkde1RYTHsowCwqyHL92WdG4ZJKJ4bpu+A9yWK32kr4gInZEKRSAS0QrCrkXQJq4bOD5cJA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/closure-calculate-chunks/-/closure-calculate-chunks-3.1.1.tgz", + "integrity": "sha512-Ne/UCDBxiPsco9o+xB0BxFrAdn+G4eljNaj6zLELAbrrGpI2o1l3PPF8yuQ93mLG5Jbm8H73f+n4mbh3S8O8vA==", "dev": true, "requires": { "acorn": "8.x", @@ -16919,7 +15194,7 @@ "graphlib": "2.x", "open": "7.x", "resolve": "1.x", - "sigma": "1.x", + "sigma": "1.2.1", "temp": "0.x", "yargs": "16.x" }, @@ -17010,9 +15285,9 @@ } }, "commander": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", - "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true }, "comment-parser": { @@ -17245,12 +15520,16 @@ "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "peer": true }, "cssstyle": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "peer": true, "requires": { "cssom": "~0.3.6" }, @@ -17258,7 +15537,9 @@ "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "peer": true } } }, @@ -17272,16 +15553,6 @@ "type": "^1.0.1" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "peer": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "dat.gui": { "version": "0.7.7", "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.7.tgz", @@ -17292,6 +15563,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "peer": true, "requires": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", @@ -17365,9 +15638,9 @@ } }, "decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==" + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, "decode-uri-component": { "version": "0.2.2", @@ -17476,173 +15749,27 @@ "dev": true }, "devtools": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.0.11.tgz", - "integrity": "sha512-qDe9RBgbDQNhVCE2GgNFUYeOQ9BDrTz3HxMVhv/1djyILkBd/dRoYUVgPsiIIWwtsoe/8gAh05sbYkwL1uTJvQ==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.3.11.tgz", + "integrity": "sha512-Wevpd4fZqCveNJv4qSpT+dER5UARLVffpeSEBLBqtrvrNZ6e39x2jWgb838Kf6okuIHWWBXq0IJuRpMda50mXw==", "dev": true, "requires": { - "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@types/node": "^18.0.0", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "chrome-launcher": "^0.15.0", - "edge-paths": "^2.1.0", + "edge-paths": "^3.0.5", "import-meta-resolve": "^2.1.0", - "puppeteer-core": "19.4.0", + "puppeteer-core": "19.7.1", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", "uuid": "^9.0.0", "which": "^3.0.0" }, "dependencies": { - "@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - } - }, - "@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "requires": { - "@types/node": "^18.0.0" - } - }, - "@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - } - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true - }, - "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, - "requires": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - } - }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "dev": true, - "requires": { - "p-locate": "^6.0.0" - } - }, - "minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "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, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "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, - "requires": { - "p-limit": "^4.0.0" - } - }, - "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 - }, - "read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "requires": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - } - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "dev": true - }, "which": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", @@ -17651,28 +15778,15 @@ "requires": { "isexe": "^2.0.0" } - }, - "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 } } }, "devtools-protocol": { - "version": "0.0.1078443", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1078443.tgz", - "integrity": "sha512-a/rOMs0PrCtcJ6RKPSK5JdFqQoitF5ZeKr+YscKYpuwkzPoFr470CU8+jrej0hpVgRpqg+K0wfAkWiGB7MkhHg==", + "version": "0.0.1103684", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1103684.tgz", + "integrity": "sha512-44Qr4zFQkzW8r4WdDOSuQoxIzPDczY/K1RDfyxzEsiG2nSzbTojDW3becX5+HrDw3gENG8jY6ffbHZ2/Ix5LSA==", "dev": true }, - "diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", - "dev": true, - "optional": true - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -17748,12 +15862,6 @@ } } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -17787,24 +15895,13 @@ } } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "peer": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "edge-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.2.1.tgz", - "integrity": "sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", "dev": true, "requires": { - "@types/which": "^1.3.2", + "@types/which": "^2.0.1", "which": "^2.0.2" } }, @@ -17954,13 +16051,13 @@ } }, "eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -17979,7 +16076,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -18019,9 +16116,9 @@ "requires": {} }, "eslint-plugin-jsdoc": { - "version": "39.6.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", - "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.0.0.tgz", + "integrity": "sha512-LOPyIu1vAVvGPkye3ci0moj0iNf3f8bmin6do2DYDj+77NRXWnkmhKRy8swWsatUs3mB5jYPWPUsFg9pyfEiyA==", "dev": true, "requires": { "@es-joy/jsdoccomment": "~0.36.1", @@ -18075,9 +16172,9 @@ "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -18172,6 +16269,12 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, "exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", @@ -18294,33 +16397,6 @@ "homedir-polyfill": "^1.0.1" } }, - "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "dev": true, - "optional": true, - "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - } - }, - "expect-webdriverio": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.0.1.tgz", - "integrity": "sha512-+FhdO0w/HI0ur4OnVphuGPU/E3rXlLqfSjiABfMgd1jw+X2tQxGU63bCUA2GlocWl5/ZuVmV/ulEd8pYgniWYg==", - "dev": true, - "optional": true, - "requires": { - "@wdio/globals": "^8.0.0-alpha.505", - "expect": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "webdriverio": "^8.0.0-alpha.505" - } - }, "ext": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", @@ -18408,13 +16484,6 @@ "yauzl": "^2.10.0" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "peer": true - }, "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -18433,6 +16502,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-fifo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", + "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==", + "dev": true + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -18605,6 +16680,17 @@ "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { @@ -18644,13 +16730,6 @@ "for-in": "^1.0.1" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "peer": true - }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -18741,16 +16820,15 @@ "dev": true }, "gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.0.2.tgz", + "integrity": "sha512-TjtV2AJOZoMQqRYoy5eM8cCQogYwazWNYLQ72QB0kwa6vHHruYkGmhhyrlzbmgNHK1dNnuP2WSH81urfzyN2Og==", "dev": true, "requires": { - "abort-controller": "^3.0.0", "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" + "node-fetch": "^2.6.7" } }, "get-caller-file": { @@ -18791,16 +16869,6 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "peer": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -19082,9 +17150,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -19122,52 +17190,52 @@ } }, "google-closure-compiler": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20221004.0.0.tgz", - "integrity": "sha512-OKENLrZFF2o3FZ/E4zdTc9NeuAUh1fdwbQxT0sibI19aR62sgNUBo2mLU6sc4Gcm0cQ2gwfB7qX1xnapOIkbaA==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20230206.0.0.tgz", + "integrity": "sha512-gGscQOcO/75AlHyw78v87u0nGKJHWqOrQ224Ks91HH1iISgF+xZ8GYosU/8s5VD66x3VD0tJKXM2rIoGOA1ycA==", "dev": true, "requires": { "chalk": "4.x", - "google-closure-compiler-java": "^20221004.0.0", - "google-closure-compiler-linux": "^20221004.0.0", - "google-closure-compiler-osx": "^20221004.0.0", - "google-closure-compiler-windows": "^20221004.0.0", + "google-closure-compiler-java": "^20230206.0.0", + "google-closure-compiler-linux": "^20230206.0.0", + "google-closure-compiler-osx": "^20230206.0.0", + "google-closure-compiler-windows": "^20230206.0.0", "minimist": "1.x", "vinyl": "2.x", "vinyl-sourcemaps-apply": "^0.2.0" } }, "google-closure-compiler-java": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20221004.0.0.tgz", - "integrity": "sha512-CygLEB40HxtK0VtP6klv2Xm08w4HQNYX/DTgLV7CP74r8LiQMUByRFleaG/Hv5xQG1JzPNiW0GOAiAubDSdr5A==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20230206.0.0.tgz", + "integrity": "sha512-OcnDf29yx4JNU13HpptADI2ckl9hEchktSHs2XSLQ/xStUAJQGQOl96to5IYh2VuFgn3Ssaw6M3c6At2pJr7wQ==", "dev": true }, "google-closure-compiler-linux": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20221004.0.0.tgz", - "integrity": "sha512-B6sca3Lmw3cYXdFzdU0iQpk8L9VEo1ecC1aM7Gl9lgWhIicqqEZebsgnUe5TQ3uHBfQoKjV9fdFG8mt8X/oqSQ==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20230206.0.0.tgz", + "integrity": "sha512-06N6w2elsnZMMA4Gf/vN2A3XzWvu+gUTrBczaw0KQL48GgdLq6OgAXrcopbGdi/K8Gz1WAcG0qf2ccG8dSqYNg==", "dev": true, "optional": true }, "google-closure-compiler-osx": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20221004.0.0.tgz", - "integrity": "sha512-z5V7BvaMauPga8DMTt9u6RGcjBdLAuv4gL2Ebw5NIQRTAHVkEVzCd3kiMX7CVCGhmWdS/1r3jZcCg4BswGia6w==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20230206.0.0.tgz", + "integrity": "sha512-lJ/Y4HTk+KdL6PhLmmalP/3DdzGK0mS0+htuFP6y4t9+QXiUKnpHWx/VDQ3Fwm2fWEzqDxfhX3R+wC9lBvFiAg==", "dev": true, "optional": true }, "google-closure-compiler-windows": { - "version": "20221004.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20221004.0.0.tgz", - "integrity": "sha512-JSAWilVa7d65QJYKUr+DmklwKmjkAce6BMD6smqJfdL2dv5OSJ2ydGy73euoBJ4Tka8iQPoaOP+BjLrhIuvqKg==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20230206.0.0.tgz", + "integrity": "sha512-4KPr7XPiOs8g4Ao3T+70egf14avCEne26XF4Mur4Fg5511ym1uEN+NlEyjBOAmfUFfaA7BYDsA8iBzDIetKrnw==", "dev": true, "optional": true }, "google-closure-deps": { - "version": "20221102.0.0", - "resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20221102.0.0.tgz", - "integrity": "sha512-6AOcHk8u5DNY/uhJLyHj0M4GLTkqAhscH7iH66QUxSiUlrg55PWdyaWQa4Jg15p4xUWNPf8NFBe6vIdwzwi0Hw==", + "version": "20230206.0.0", + "resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20230206.0.0.tgz", + "integrity": "sha512-MT0JDygFjCTavsOGfRRE1o3teF/ZZD1a8NbeVlGW0oM3OTY2xkOpoPMvSely4khfFV4i4qqjmlMvtwD8cT7adg==", "dev": true, "requires": { "minimatch": "^3.0.4", @@ -19198,9 +17266,9 @@ } }, "got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, "requires": { "@sindresorhus/is": "^4.0.0", @@ -19631,24 +17699,16 @@ "dev": true }, "gulp-replace": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.3.tgz", - "integrity": "sha512-HcPHpWY4XdF8zxYkDODHnG2+7a3nD/Y8Mfu3aBgMiCFDW3X2GiOKXllsAmILcxe3KZT2BXoN18WrpEFm48KfLQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.4.tgz", + "integrity": "sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==", "dev": true, "requires": { - "@types/node": "^14.14.41", + "@types/node": "*", "@types/vinyl": "^2.0.4", "istextorbinary": "^3.0.0", "replacestream": "^4.0.3", "yargs-parser": ">=5.0.0-security.0" - }, - "dependencies": { - "@types/node": { - "version": "14.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.0.tgz", - "integrity": "sha512-0GeIl2kmVMXEnx8tg1SlG6Gg8vkqirrW752KqolYo1PHevhhZN3bhJ67qHj+bQaINhX0Ra3TlWwRvMCd9iEfNQ==", - "dev": true - } } }, "gulp-series": { @@ -19902,24 +17962,6 @@ "glogg": "^1.0.0" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "peer": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "peer": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -20030,9 +18072,9 @@ } }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-proxy": { @@ -20077,18 +18119,6 @@ "url-join": "^4.0.1" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "peer": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -20108,16 +18138,6 @@ "debug": "4" } }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "peer": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -20198,13 +18218,6 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true, - "peer": true - }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -20263,9 +18276,9 @@ } }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -20430,13 +18443,6 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true, - "peer": true - }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -20497,13 +18503,6 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true, - "peer": true - }, "istextorbinary": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", @@ -20514,94 +18513,6 @@ "textextensions": "^3.2.0" } }, - "jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - } - }, - "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true, - "optional": true - }, - "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - } - }, - "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, - "optional": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "optional": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - } - } - }, - "jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, - "optional": true, - "requires": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", - "dev": true, - "optional": true - } - } - }, "jju": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", @@ -20609,15 +18520,15 @@ "dev": true }, "js-green-licenses": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-green-licenses/-/js-green-licenses-3.0.1.tgz", - "integrity": "sha512-dKyO14U6LaDzJ5gNlvP/v1vkTW7TTXEKNxMHnkxqdYStcYVEJlfubfqbEageVzV41PWu7felyNbwawoEJ/RpYQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-green-licenses/-/js-green-licenses-4.0.0.tgz", + "integrity": "sha512-kcgTOaZmpDpINcRAOKKhjHtBN6zibMVTC8qfPUOpowQtI/6fUgdmwJLJ0ycCb0pUO3ZYKn++56sy8IlG60p5mg==", "dev": true, "requires": { - "gaxios": "^4.0.0", + "gaxios": "^5.0.0", "meow": "^9.0.0", "npm-package-arg": "^8.0.0", - "package-json": "^6.0.0", + "package-json": "^7.0.0", "semver": "^7.3.2", "spdx-correct": "^3.0.0", "spdx-satisfies": "^5.0.0", @@ -20645,13 +18556,6 @@ "argparse": "^2.0.1" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true, - "peer": true - }, "jsdoc-type-pratt-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", @@ -20659,17 +18563,16 @@ "dev": true }, "jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.1.tgz", + "integrity": "sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==", "requires": { "abab": "^2.0.6", - "acorn": "^8.8.1", + "acorn": "^8.8.2", "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", @@ -20678,7 +18581,8 @@ "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.2", - "parse5": "^7.1.1", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", @@ -20686,9 +18590,52 @@ "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "requires": { + "rrweb-cssom": "^0.6.0" + } + }, + "data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "requires": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + } + }, + "tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "requires": { + "punycode": "^2.3.0" + } + }, + "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==", + "requires": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "requires": {} + } } }, "json-buffer": { @@ -20703,13 +18650,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "peer": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -20722,17 +18662,10 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "peer": true - }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonfile": { @@ -20745,19 +18678,6 @@ "universalify": "^2.0.0" } }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "peer": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, "just-curry-it": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-5.2.1.tgz", @@ -20801,9 +18721,9 @@ } }, "ky": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/ky/-/ky-0.32.2.tgz", - "integrity": "sha512-eBJeF6IXNwX5rksdwBrE2rIJrU2d84GoTvdM7OmmTIwUVXEMd72wIwvT+nyhrqtv7AzbSNsWz7yRsHgVhj1uog==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.2.tgz", + "integrity": "sha512-f6oS2rKUcPu5FzdqCDbFpmzis/JlqFZw8uIHm/jf8Kc3vtnW+VDhuashOAKyBZv8bFiZFZUMNxTC0JtahEvujA==", "dev": true }, "last-run": { @@ -21104,13 +19024,6 @@ "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true, - "peer": true - }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -21528,9 +19441,9 @@ } }, "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", + "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==", "dev": true }, "mkdirp-classic": { @@ -21540,9 +19453,9 @@ "dev": true }, "mocha": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", - "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "requires": { "ansi-colors": "4.1.1", @@ -21827,13 +19740,6 @@ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "peer": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -22076,148 +19982,15 @@ "dev": true }, "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", + "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", "dev": true, "requires": { - "got": "^9.6.0", + "got": "^11.8.2", "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - } - } - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - } - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "semver": "^7.3.5" } }, "parent-module": { @@ -22265,9 +20038,9 @@ "dev": true }, "parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "requires": { "entities": "^4.4.0" } @@ -22279,16 +20052,16 @@ "dev": true }, "patch-package": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.0.tgz", - "integrity": "sha512-tC3EqJmo74yKqfsMzELaFwxOAu6FH6t+FzFOsnWAuARm7/n2xB5AOeOueE221eM9gtMuIKMKpF9tBy/X2mNP0Q==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", "dev": true, "requires": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "cross-spawn": "^6.0.5", "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^7.0.1", + "fs-extra": "^9.0.0", "is-ci": "^2.0.0", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", @@ -22314,23 +20087,15 @@ } }, "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, "path-key": { @@ -22375,12 +20140,6 @@ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, - "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 - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -22486,13 +20245,6 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true, - "peer": true - }, "picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", @@ -22549,13 +20301,6 @@ } } }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true, - "peer": true - }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -22626,33 +20371,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, - "optional": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "optional": true - } - } - }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -22665,6 +20383,12 @@ "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", "dev": true }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -22728,40 +20452,42 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" }, "puppeteer-core": { - "version": "19.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.4.0.tgz", - "integrity": "sha512-gG/jxseleZStinBn86x8r7trjcE4jcjx1hIQWOpACQhquHYMuKnrWxkzg+EDn8sN3wUtF/Ry9mtJgjM49oUOFQ==", + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.1.tgz", + "integrity": "sha512-4b5Go25IA+0xrUIw0Qtqi4nxc0qwdu/C7VT1+tFPl1W27207YT+7bxfANC3PjXMlS6bcbzinCf5YfGqMl8tfyQ==", "dev": true, "requires": { "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1068969", + "devtools-protocol": "0.0.1094867", "extract-zip": "2.0.1", "https-proxy-agent": "5.0.1", "proxy-from-env": "1.1.0", "rimraf": "3.0.2", "tar-fs": "2.1.1", "unbzip2-stream": "1.4.3", - "ws": "8.10.0" + "ws": "8.11.0" }, "dependencies": { "devtools-protocol": { - "version": "0.0.1068969", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1068969.tgz", - "integrity": "sha512-ATFTrPbY1dKYhPPvpjtwWKSK2mIwGmRwX54UASn9THEuIZCe2n9k3vVuMmt6jWeL+e5QaaguEv/pMyR+JQB7VQ==", + "version": "0.0.1094867", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", + "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==", "dev": true }, - "ws": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", - "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "requires": {} + "requires": { + "glob": "^7.1.3" + } } } }, @@ -22788,6 +20514,12 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -22818,18 +20550,11 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true } } }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true, - "optional": true - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -23005,12 +20730,12 @@ "dev": true }, "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", "dev": true, "requires": { - "rc": "^1.2.8" + "rc": "1.2.8" } }, "registry-url": { @@ -23109,95 +20834,6 @@ } } }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "peer": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "peer": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "peer": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "peer": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "peer": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "peer": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -23216,13 +20852,14 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-alpn": { @@ -23307,13 +20944,15 @@ "dev": true }, "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.1.2.tgz", + "integrity": "sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==", + "dev": true + }, + "rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" }, "run-parallel": { "version": "1.2.0", @@ -23376,12 +21015,12 @@ "dev": true }, "selenium-standalone": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-8.2.4.tgz", - "integrity": "sha512-VXkiQFAmXGlcE6X5A9dakXbXuxJONqG/t39Cw4ylk7J+hxIYBk/yfJ0Tkh2P0X9QGRpcUfr0hgE0PHDil0nFiA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-8.3.0.tgz", + "integrity": "sha512-cQVWQGxumvPnyzFNtzFtBfDCbqBsdEnwiOwRyrAzeUqf5ltAp3Z3+2f6asSFbLUQJs2sFuF6PsEyNA+eOzXKxg==", "dev": true, "requires": { - "commander": "^9.0.0", + "commander": "^10.0.0", "cross-spawn": "^7.0.3", "debug": "^4.3.1", "fs-extra": "^10.0.0", @@ -23390,11 +21029,57 @@ "lodash.mapvalues": "^4.6.0", "lodash.merge": "^4.6.2", "minimist": "^1.2.5", - "mkdirp": "^1.0.4", + "mkdirp": "^2.1.3", "progress": "2.0.3", - "tar-stream": "2.2.0", + "tar-stream": "3.0.0", "which": "^2.0.2", "yauzl": "^2.10.0" + }, + "dependencies": { + "bl": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", + "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "readable-stream": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", + "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } + }, + "tar-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.0.0.tgz", + "integrity": "sha512-O6OfUKBbQOqAhh6owTWmA730J/yZCYcpmZ1DBj2YX51ZQrt7d7NgzrR+CnO9wP6nt/viWZW2XeXLavX3/ZEbEg==", + "dev": true, + "requires": { + "b4a": "^1.6.1", + "bl": "^6.0.0", + "streamx": "^2.12.5" + } + } } }, "semver": { @@ -23821,49 +21506,12 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "peer": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "optional": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "optional": true - } - } - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -23936,13 +21584,6 @@ } } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", - "dev": true, - "peer": true - }, "stream-combiner": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", @@ -24030,6 +21671,16 @@ } } }, + "streamx": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.13.2.tgz", + "integrity": "sha512-+TWqixPhGDXEG9L/XczSbhfkmwAtGs3BJX5QNU6cvno+pOLKeszByWcnaTu6dg8efsTYqR8ZZuXWHhZfgrxMvA==", + "dev": true, + "requires": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -24112,6 +21763,12 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", @@ -24312,12 +21969,6 @@ } } }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -24390,6 +22041,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "peer": true, "requires": { "punycode": "^2.1.1" } @@ -24421,23 +22074,6 @@ "tslib": "^1.8.1" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "peer": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "peer": true - }, "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", @@ -24472,15 +22108,15 @@ "dev": true }, "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true }, "ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true }, "unbzip2-stream": { @@ -24652,15 +22288,6 @@ "requires-port": "^1.0.0" } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -24674,11 +22301,10 @@ "dev": true }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true, - "peer": true + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true }, "v8flags": { "version": "3.2.0", @@ -24720,27 +22346,6 @@ "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", "dev": true }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "peer": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "peer": true - } - } - }, "vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -24835,16 +22440,6 @@ "source-map": "^0.5.1" } }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "peer": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, "w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -24854,21 +22449,21 @@ } }, "webdriver": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.0.11.tgz", - "integrity": "sha512-UK1iLpNltIzOEScd45GOQ4qFTVFMmUwMYDNtVMhX6ASB9yl4Ir3Do66BZ7fyk5+NBvn2VnIx7qrap6FutSbxhQ==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.3.11.tgz", + "integrity": "sha512-1Dw8tN+c+LdnIXizEB+RrH9LbHGuTEDUtPqxT0fd80F+g/RqZvX3bv3ABD7ZVvvdE2ck6XbATnVX2/rYrQxSYQ==", "dev": true, "requires": { "@types/node": "^18.0.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.0.11", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "deepmerge-ts": "^4.2.2", "got": "^12.1.0", - "ky": "^0.32.1", + "ky": "^0.33.0", "ws": "^8.8.0" }, "dependencies": { @@ -24887,52 +22482,6 @@ "defer-to-connect": "^2.0.1" } }, - "@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - } - }, - "@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "requires": { - "@types/node": "^18.0.0" - } - }, - "@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - } - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -24940,55 +22489,26 @@ "dev": true }, "cacheable-request": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.3.tgz", - "integrity": "sha512-6BehRBOs7iurNjAYN9iPazTwFDaMQavJO8W1MEm3s2pH8q/tkPTtLDRUZaweWK87WFGf2Y5wLAlaCJlR5kOz3w==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.8.tgz", + "integrity": "sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==", "dev": true, "requires": { "@types/http-cache-semantics": "^4.0.1", "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.0", + "http-cache-semantics": "^4.1.1", "keyv": "^4.5.2", "mimic-response": "^4.0.0", "normalize-url": "^8.0.0", "responselike": "^3.0.0" } }, - "decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true - }, - "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, - "requires": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - } - }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, "got": { "version": "12.5.3", "resolved": "https://registry.npmjs.org/got/-/got-12.5.3.tgz", @@ -25018,15 +22538,6 @@ "resolve-alpn": "^1.2.0" } }, - "locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "dev": true, - "requires": { - "p-locate": "^6.0.0" - } - }, "lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -25039,15 +22550,6 @@ "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", "dev": true }, - "minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, "normalize-url": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", @@ -25060,53 +22562,6 @@ "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", "dev": true }, - "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, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "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, - "requires": { - "p-limit": "^4.0.0" - } - }, - "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 - }, - "read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "requires": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - } - }, "responselike": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", @@ -25115,87 +22570,42 @@ "requires": { "lowercase-keys": "^3.0.0" } - }, - "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 } } }, "webdriverio": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.0.12.tgz", - "integrity": "sha512-KCQ+ePhbNTvKP635bz11ADuq9oMjU99tUCgst6difwFPYUg43HYyx5b5CTGl9LrTMqwoJ5UWoIBxjtyS216n6w==", + "version": "8.3.11", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.3.11.tgz", + "integrity": "sha512-sN2jmkwSQj0r9IRLvpzfmLh/OvX3l4G+l+W26ksoLr+qxdOfRmoNfxc4CGMt/Uin515ajajqPWrxFFbdeL3uIQ==", "dev": true, "requires": { - "@types/aria-query": "^5.0.0", "@types/node": "^18.0.0", - "@wdio/config": "8.0.11", - "@wdio/globals": "8.0.12", - "@wdio/logger": "8.0.0", - "@wdio/protocols": "8.0.0", - "@wdio/repl": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", + "@wdio/config": "8.3.11", + "@wdio/logger": "8.1.0", + "@wdio/protocols": "8.3.11", + "@wdio/repl": "8.1.0", + "@wdio/types": "8.3.0", + "@wdio/utils": "8.3.0", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "8.0.11", - "devtools-protocol": "^0.0.1078443", + "devtools": "8.3.11", + "devtools-protocol": "^0.0.1103684", "grapheme-splitter": "^1.0.2", "import-meta-resolve": "^2.1.0", "is-plain-obj": "^4.1.0", "lodash.clonedeep": "^4.5.0", "lodash.zip": "^4.2.0", - "minimatch": "^5.0.0", - "puppeteer-core": "19.4.0", + "minimatch": "^7.0.0", + "puppeteer-core": "19.7.1", "query-selector-shadow-dom": "^1.0.0", "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "8.0.11" + "webdriver": "8.3.11" }, "dependencies": { - "@wdio/config": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.0.11.tgz", - "integrity": "sha512-LR8n6TJfDzVtDmuge4EjOHiJKae73ZyvEwTQq3tokovRIbIMaVkfsRV9iqEZiRgohy14ehAREwNgn67j77ucYA==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "@wdio/utils": "8.0.11", - "decamelize": "^6.0.0", - "deepmerge-ts": "^4.2.2", - "glob": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "read-pkg-up": "^9.1.0" - } - }, - "@wdio/types": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.0.11.tgz", - "integrity": "sha512-54xbajB7tqWmYPXFI0ALupPauwLyVtPSZSG/R/DPlY25p+Ygw4jwH64s+Jh1V3TZYnktfv4cIt1Bw/M35cBgOQ==", - "dev": true, - "requires": { - "@types/node": "^18.0.0" - } - }, - "@wdio/utils": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.0.11.tgz", - "integrity": "sha512-4nIYt1KP4IVIYfnld+Kbh/l85o7VK4roAEIfiHV374utPpspzV+eli4ANX2fEOGVUVJMVNBCN/sCsL8u3DsPpw==", - "dev": true, - "requires": { - "@wdio/logger": "8.0.0", - "@wdio/types": "8.0.11", - "import-meta-resolve": "^2.2.0", - "p-iteration": "^1.1.8" - } - }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -25205,111 +22615,20 @@ "balanced-match": "^1.0.0" } }, - "decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", - "dev": true - }, - "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, - "requires": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - } - }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, "is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true }, - "locate-path": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", - "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", - "dev": true, - "requires": { - "p-locate": "^6.0.0" - } - }, "minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.2.0.tgz", + "integrity": "sha512-rMRHmwySzopAQjmWW6TkAKCEDKNaY/HuV/c2YkWWuWnfkTwApt0V4hnYzzPnZ/5Gcd2+8MPncSyuOGPl3xPvcg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } - }, - "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, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "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, - "requires": { - "p-limit": "^4.0.0" - } - }, - "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 - }, - "read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", - "dev": true, - "requires": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - } - }, - "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 } } }, @@ -25345,6 +22664,8 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "peer": true, "requires": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -25397,6 +22718,7 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, "requires": {} }, "xml-name-validator": { @@ -25434,9 +22756,9 @@ "dev": true }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "requires": { "cliui": "^8.0.1", diff --git a/package.json b/package.json index 457a92b23..f17a4235b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "9.2.1", + "version": "9.3.0", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" @@ -49,7 +49,7 @@ "publish:beta": "npm ci && gulp publishBeta", "recompile": "gulp recompile", "release": "gulp gitCreateRC", - "start": "npm run deps && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir 'build/src' --declarationDir 'build/declarations'\" \"http-server ./ -s -o /tests/playground.html -c-1\"", + "start": "npm run build && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir 'build/src' --declarationDir 'build/declarations'\" \"http-server ./ -s -o /tests/playground.html -c-1\"", "tsc": "gulp tsc", "test": "gulp test", "test:generators": "gulp testGenerators", @@ -83,14 +83,14 @@ "concurrently": "^7.4.0", "eslint": "^8.4.1", "eslint-config-google": "^0.14.0", - "eslint-plugin-jsdoc": "^39.3.6", - "google-closure-compiler": "^20221004.0.0", - "google-closure-deps": "^20221102.0.0", + "eslint-plugin-jsdoc": "^40.0.0", + "google-closure-compiler": "^20230206.0.0", + "google-closure-deps": "^20230206.0.0", "gulp": "^4.0.2", "gulp-clang-format": "^1.0.27", "gulp-concat": "^2.6.1", - "gulp-header": "^2.0.9", "gulp-gzip": "^1.4.2", + "gulp-header": "^2.0.9", "gulp-insert": "^0.5.0", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", @@ -99,20 +99,20 @@ "gulp-sourcemaps": "^3.0.0", "gulp-umd": "^2.0.0", "http-server": "^14.0.0", - "js-green-licenses": "^3.0.0", + "js-green-licenses": "^4.0.0", "json5": "^2.2.0", "markdown-tables-to-json": "^0.1.7", "mocha": "^10.0.0", "patch-package": "^6.4.7", "readline-sync": "^1.4.10", - "rimraf": "^3.0.2", + "rimraf": "^4.0.7", "selenium-standalone": "^8.0.3", "through2": "^4.0.2", - "typescript": "^4.3.2", + "typescript": "^5.0.2", "webdriverio": "^8.0.5", "yargs": "^17.2.1" }, "dependencies": { - "jsdom": "20.0.3" + "jsdom": "21.1.1" } } diff --git a/scripts/gulpfiles/build_tasks.js b/scripts/gulpfiles/build_tasks.js index 5538abc92..e16e8656e 100644 --- a/scripts/gulpfiles/build_tasks.js +++ b/scripts/gulpfiles/build_tasks.js @@ -23,7 +23,7 @@ const clangFormatter = require('gulp-clang-format'); const closureCompiler = require('google-closure-compiler').gulp(); const closureDeps = require('google-closure-deps'); const argv = require('yargs').argv; -const rimraf = require('rimraf'); +const {rimraf} = require('rimraf'); const {BUILD_DIR, DEPS_FILE, RELEASE_DIR, TEST_DEPS_FILE, TSC_OUTPUT_DIR, TYPINGS_BUILD_DIR} = require('./config'); const {getPackageJson} = require('./helper_tasks'); @@ -34,11 +34,6 @@ const {posixPath} = require('../helpers'); // Build // //////////////////////////////////////////////////////////// -/** - * Directory in which core/ can be found after passing through tsc. - */ -const CORE_DIR = path.join(TSC_OUTPUT_DIR, 'core'); - /** * Suffix to add to compiled output files. */ @@ -104,49 +99,47 @@ const NAMESPACE_PROPERTY = '__namespace__'; const chunks = [ { name: 'blockly', - entry: posixPath((argv.compileTs) ? - path.join(TSC_OUTPUT_DIR, CORE_DIR, 'main.js') : - path.join(CORE_DIR, 'main.js')), + entry: path.join(TSC_OUTPUT_DIR, 'core', 'main.js'), exports: 'module$build$src$core$blockly', reexport: 'Blockly', }, { name: 'blocks', - entry: 'blocks/blocks.js', + entry: path.join(TSC_OUTPUT_DIR, 'blocks', 'blocks.js'), exports: 'module$exports$Blockly$libraryBlocks', reexport: 'Blockly.libraryBlocks', }, { name: 'javascript', - entry: 'generators/javascript/all.js', + entry: path.join(TSC_OUTPUT_DIR, 'generators', 'javascript', 'all.js'), exports: 'module$exports$Blockly$JavaScript', reexport: 'Blockly.JavaScript', reexportOnly: 'javascriptGenerator', }, { name: 'python', - entry: 'generators/python/all.js', + entry: path.join(TSC_OUTPUT_DIR, 'generators', 'python', 'all.js'), exports: 'module$exports$Blockly$Python', reexport: 'Blockly.Python', reexportOnly: 'pythonGenerator', }, { name: 'php', - entry: 'generators/php/all.js', + entry: path.join(TSC_OUTPUT_DIR, 'generators', 'php', 'all.js'), exports: 'module$exports$Blockly$PHP', reexport: 'Blockly.PHP', reexportOnly: 'phpGenerator', }, { name: 'lua', - entry: 'generators/lua/all.js', + entry: path.join(TSC_OUTPUT_DIR, 'generators', 'lua', 'all.js'), exports: 'module$exports$Blockly$Lua', reexport: 'Blockly.Lua', reexportOnly: 'luaGenerator', }, { name: 'dart', - entry: 'generators/dart/all.js', + entry: path.join(TSC_OUTPUT_DIR, 'generators', 'dart', 'all.js'), exports: 'module$exports$Blockly$Dart', reexport: 'Blockly.Dart', reexportOnly: 'dartGenerator', @@ -261,7 +254,7 @@ const JSCOMP_OFF = [ * When adding additional items to this list it may be helpful to * search the compiler source code * (https://github.com/google/closure-compiler/) for the JSC_* - * disagnostic name (omitting the JSC_ prefix) to find the corresponding + * diagnostic name (omitting the JSC_ prefix) to find the corresponding * DiagnosticGroup. */ 'checkTypes', @@ -309,76 +302,81 @@ function buildJavaScript(done) { * * Prerequisite: buildJavaScript. */ -function buildDeps(done) { +function buildDeps() { const roots = [ path.join(TSC_OUTPUT_DIR, 'closure', 'goog', 'base.js'), TSC_OUTPUT_DIR, - 'blocks', - 'generators', + 'tests/mocha', ]; - const testRoots = [ - ...roots, - 'tests/mocha' - ]; + /** Maximum buffer size, in bytes for child process stdout/stderr. */ + const MAX_BUFFER_SIZE = 10 * 1024 * 1024; /** - * Extracts lines that contain the specified keyword. - * @param {string} text output text - * @param {string} keyword extract lines with this keyword - * @returns {string} modified text + * Filter a string to extract lines containing (or not containing) the + * specified target string. + * + * @param {string} text Text to filter. + * @param {string} target String to search for. + * @param {boolean?} exclude If true, extract only non-matching lines. + * @returns {string} Filtered text. */ - function extractOutputs(text, keyword) { + function filter(text, target, exclude) { return text.split('\n') - .filter((line) => line.includes(keyword)) + .filter((line) => Boolean(line.match(target)) !== Boolean(exclude)) .join('\n'); } - function filterErrors(text) { - return text.split('\n') - .filter( - (line) => !/^WARNING /.test(line) || - !(/Missing type declaration./.test(line) || - /illegal use of unknown JSDoc tag/.test(line))) - .join('\n'); + /** + * Log unexpected diagnostics, after removing expected warnings. + * + * @param {string} text Standard error output from closure-make-deps + */ + function log(text) { + for (const line of text.split('\n')) { + if (line && + !/^WARNING .*: Bounded generic semantics are currently/.test(line) && + !/^WARNING .*: Missing type declaration/.test(line) && + !/^WARNING .*: illegal use of unknown JSDoc tag/.test(line)) { + console.error(line); + } + } } - new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const args = roots.map(root => `--root '${root}' `).join(''); exec( - `closure-make-deps ${args}`, + `closure-make-deps ${args}`, {maxBuffer: MAX_BUFFER_SIZE}, (error, stdout, stderr) => { - console.warn(filterErrors(stderr)); if (error) { + // Remove warnings from stack trace to show only errors. + error.stack = filter(error.stack, /^WARNING/, true); + // Due to some race condition, the stderr parameter is + // often badly truncated if an error is non-null, so the + // error message might not actually be shown to the user. + // Print a helpful message to the user to help them find + // out what the problem is. + error.stack += ` + +If you do not see an helpful diagnostic from closure-make-deps in the +error message above, try running: + + npx closure-make-deps ${args} 2>&1 |grep -v WARNING`; reject(error); } else { - fs.writeFileSync(DEPS_FILE, stdout); + log(stderr); + // Anything not about mocha goes in DEPS_FILE. + fs.writeFileSync(DEPS_FILE, filter(stdout, 'tests/mocha', true)); + // Anything about mocha does in TEST_DEPS_FILE. + fs.writeFileSync(TEST_DEPS_FILE, filter(stdout, 'tests/mocha')); resolve(); } }); - }).then(() => new Promise((resolve, reject) => { - // Filter out the entries that are already in deps.js. - const testArgs = - testRoots.map(root => `--root '${root}' `).join(''); - exec( - `closure-make-deps ${testArgs}`, - (error, stdout, stderr) => { - console.warn(filterErrors(stderr)); - if (error) { - reject(error); - } else { - fs.writeFileSync(TEST_DEPS_FILE, - extractOutputs(stdout, 'tests/mocha')); - resolve(); - } - }); - })).then(() => { - done(); }); } /** - * This task regenrates msg/json/en.js and msg/json/qqq.js from + * This task regenerates msg/json/en.js and msg/json/qqq.js from * msg/messages.js. */ function generateMessages(done) { @@ -684,14 +682,13 @@ function buildAdvancedCompilationTest() { } const srcs = [ - TSC_OUTPUT_DIR + '/closure/goog/base_minimal.js', - TSC_OUTPUT_DIR + '/closure/goog/goog.js', - TSC_OUTPUT_DIR + '/core/**/*.js', - 'blocks/**/*.js', - 'generators/**/*.js', + TSC_OUTPUT_DIR + '/**/*.js', 'tests/compile/main.js', 'tests/compile/test_blocks.js', ]; + const ignore = [ + TSC_OUTPUT_DIR + '/closure/goog/base.js', // Use base_minimal.js only. + ]; // Closure Compiler options. const options = { @@ -700,7 +697,7 @@ function buildAdvancedCompilationTest() { entry_point: './tests/compile/main.js', js_output_file: 'main_compressed.js', }; - return gulp.src(srcs, {base: './'}) + return gulp.src(srcs, {base: './', ignore}) .pipe(stripApacheLicense()) .pipe(gulp.sourcemaps.init()) .pipe(compile(options)) @@ -712,12 +709,12 @@ function buildAdvancedCompilationTest() { /** * This task cleans the build directory (by deleting it). */ -function cleanBuildDir(done) { +function cleanBuildDir() { // Sanity check. if (BUILD_DIR === '.' || BUILD_DIR === '/') { - throw new Error(`Refusing to rm -rf ${BUILD_DIR}`); + return Promise.reject(`Refusing to rm -rf ${BUILD_DIR}`); } - rimraf(BUILD_DIR, done); + return rimraf(BUILD_DIR); } /** @@ -726,7 +723,8 @@ function cleanBuildDir(done) { function format() { return gulp.src([ 'core/**/*.js', 'core/**/*.ts', - 'blocks/**/*.js', 'blocks/**/*.ts' + 'blocks/**/*.js', 'blocks/**/*.ts', + '.eslintrc.js' ], {base: '.'}) .pipe(clangFormatter.format('file', clangFormat)) .pipe(gulp.dest('.')); @@ -740,7 +738,7 @@ exports.deps = gulp.series(exports.tsc, buildDeps); exports.minify = gulp.series(exports.deps, buildCompiled); exports.build = gulp.parallel(exports.minify, exports.langfiles); -// Manually-invokable targets, with prequisites where required. +// Manually-invokable targets, with prerequisites where required. exports.format = format; exports.messages = generateMessages; // Generate msg/json/en.json et al. exports.buildAdvancedCompilationTest = diff --git a/scripts/gulpfiles/cleanup_tasks.js b/scripts/gulpfiles/cleanup_tasks.js index 5b4a933fb..88e3d7330 100644 --- a/scripts/gulpfiles/cleanup_tasks.js +++ b/scripts/gulpfiles/cleanup_tasks.js @@ -81,6 +81,6 @@ function sortRequires() { }; module.exports = { - // Manually-invokable targets, with prequisites where required. + // Manually-invokable targets, with prerequisites where required. sortRequires: sortRequires }; diff --git a/scripts/gulpfiles/config.js b/scripts/gulpfiles/config.js index 5f3cad99d..674432dde 100644 --- a/scripts/gulpfiles/config.js +++ b/scripts/gulpfiles/config.js @@ -38,6 +38,9 @@ exports.TYPINGS_BUILD_DIR = path.join(exports.BUILD_DIR, 'declarations'); // Matches the value in tsconfig.json: outDir exports.TSC_OUTPUT_DIR = path.join(exports.BUILD_DIR, 'src'); +// Directory for files generated by compiling test code. +exports.TEST_TSC_OUTPUT_DIR = path.join(exports.BUILD_DIR, 'tests'); + // Directory in which to assemble (and from which to publish) the // blockly npm package. exports.RELEASE_DIR = 'dist'; diff --git a/scripts/gulpfiles/git_tasks.js b/scripts/gulpfiles/git_tasks.js index eb3a825c0..f21180e84 100644 --- a/scripts/gulpfiles/git_tasks.js +++ b/scripts/gulpfiles/git_tasks.js @@ -112,7 +112,8 @@ const updateGithubPages = gulp.series( packageTasks.cleanReleaseDir, buildTasks.build, function(done) { - execSync('git add build/msg/* dist/*_compressed.js*', {stdio: 'inherit'}); + // The build and dist directories are normally gitignored, so we have to force add. + execSync('git add -f build/msg/* dist/*_compressed.js*', {stdio: 'inherit'}); execSync('git commit -am "Rebuild"', {stdio: 'inherit'}); execSync('git push ' + upstream_url + ' gh-pages --force', {stdio: 'inherit'}); diff --git a/scripts/gulpfiles/license_tasks.js b/scripts/gulpfiles/license_tasks.js index 8e2a4017d..ddf9b6f28 100644 --- a/scripts/gulpfiles/license_tasks.js +++ b/scripts/gulpfiles/license_tasks.js @@ -17,6 +17,6 @@ function checkLicenses() { }; module.exports = { - // Manually-invokable targets, with prequisites where required. + // Manually-invokable targets, with prerequisites where required. checkLicenses: checkLicenses }; diff --git a/scripts/gulpfiles/package_tasks.js b/scripts/gulpfiles/package_tasks.js index d5fba6258..38a5b5f9a 100644 --- a/scripts/gulpfiles/package_tasks.js +++ b/scripts/gulpfiles/package_tasks.js @@ -18,7 +18,7 @@ gulp.replace = require('gulp-replace'); const path = require('path'); const fs = require('fs'); -const rimraf = require('rimraf'); +const {rimraf} = require('rimraf'); const build = require('./build_tasks'); const {getPackageJson} = require('./helper_tasks'); const {BUILD_DIR, RELEASE_DIR, TYPINGS_BUILD_DIR} = require('./config'); @@ -346,7 +346,10 @@ function packageDTS() { 'typings/msg/*.d.ts', ]; return gulp.src(handwrittenSrcs, {base: 'typings'}) - .pipe(gulp.src(`${TYPINGS_BUILD_DIR}/**/*.d.ts`)) + .pipe(gulp.src(`${TYPINGS_BUILD_DIR}/**/*.d.ts`, {ignore: [ + `${TYPINGS_BUILD_DIR}/blocks/**/*`, + `${TYPINGS_BUILD_DIR}/generators/**/*`, + ]})) .pipe(gulp.replace('AnyDuringMigration', 'any')) .pipe(gulp.dest(RELEASE_DIR)); }; @@ -354,12 +357,12 @@ function packageDTS() { /** * This task cleans the release directory (by deleting it). */ -function cleanReleaseDir(done) { +function cleanReleaseDir() { // Sanity check. if (RELEASE_DIR === '.' || RELEASE_DIR === '/') { - throw new Error(`Refusing to rm -rf ${RELEASE_DIR}`); + return Promise.reject(`Refusing to rm -rf ${RELEASE_DIR}`); } - rimraf(RELEASE_DIR, done); + return rimraf(RELEASE_DIR); } /** diff --git a/scripts/gulpfiles/release_tasks.js b/scripts/gulpfiles/release_tasks.js index 58717985c..5a0eb9f0e 100644 --- a/scripts/gulpfiles/release_tasks.js +++ b/scripts/gulpfiles/release_tasks.js @@ -102,7 +102,7 @@ function checkReleaseDir(done) { // Check with the user that the version number is correct, then login and publish to npm. function loginAndPublish_(done, isBeta) { const { version } = getPackageJson(); - if(readlineSync.keyInYN(`You are about to publish blockly with the version number:${version}. Do you want to continue?`)) { + if (readlineSync.keyInYN(`You are about to publish blockly with the version number:${version}. Do you want to continue?`)) { execSync(`npm login --registry https://wombat-dressing-room.appspot.com`, {stdio: 'inherit'}); execSync(`npm publish --registry https://wombat-dressing-room.appspot.com ${isBeta ? '--tag beta' : ''}`, {cwd: RELEASE_DIR, stdio: 'inherit'}); done(); @@ -129,7 +129,7 @@ function updateBetaVersion(done) { const blocklyVersions = JSON.parse(execSync('npm view blockly versions --json').toString()); const re = new RegExp(/-beta\.(\d)/); const latestBetaVersion = execSync('npm show blockly version --tag beta').toString().trim(); - while(!isValid) { + while (!isValid) { newVersion = readlineSync.question(`What is the new beta version? (latest beta version: ${latestBetaVersion})`); const existsOnNpm = blocklyVersions.indexOf(newVersion) > -1; const isFormatted = newVersion.search(re) > -1; diff --git a/scripts/gulpfiles/test_tasks.js b/scripts/gulpfiles/test_tasks.js index 68fb63963..921be874d 100644 --- a/scripts/gulpfiles/test_tasks.js +++ b/scripts/gulpfiles/test_tasks.js @@ -17,8 +17,7 @@ const path = require('path'); const {execSync} = require('child_process'); const rimraf = require('rimraf'); -const buildTasks = require('./build_tasks'); -const {BUILD_DIR, RELEASE_DIR} = require('./config'); +const {RELEASE_DIR, TEST_TSC_OUTPUT_DIR} = require('./config'); const {runMochaTestsInBrowser} = require('../../tests/mocha/webdriver.js'); const {runGeneratorsInBrowser} = require('../../tests/generators/webdriver.js'); @@ -31,84 +30,100 @@ const BOLD_GREEN = '\x1b[1;32m'; const BOLD_RED = '\x1b[1;31m'; const ANSI_RESET = '\x1b[0m'; -class Tester { - constructor(tasks = []) { - this.successCount = 0; - this.failCount = 0; - this.tasks = tasks; - } +let successCount = 0; +let failCount = 0; +let firstErr; +const results = {}; - /** - * Run all tests in sequence. - */ - async runAll() { - for (const task of this.tasks) { - await this.runTestTask(task) - } - this.reportTestResult(); - } - - /** - * Create a Gulp task to run all tests. - */ - asTask() { - return this.runAll.bind(this); - } - - /** - * Run an arbitrary Gulp task as a test. - * @param {function} task Any Gulp task. - * @return {Promise} Asynchronous result. - */ - async runTestTask(task) { - const id = task.name; +/** + * Run an arbitrary Gulp task as a test. + * @param {function} task Any Gulp task. + * @return {Promise} Asynchronous result. + */ +function runTestTask(id, task) { + return new Promise((resolve) => { console.log('======================================='); console.log(`== ${id}`); + + // Turn any task into a Promise! + const asyncTask = new Promise((resolve, reject) => { + asyncDone(task, (error, result) => { + if (error) reject(error); + resolve(result); + }); + }); + if (process.env.CI) console.log('::group::'); - - try { - try { - await new Promise((resolve, reject) => { - asyncDone(task, (error, result) => { - if (error) reject(error); - resolve(result); - }); - }); - } finally { + asyncTask + .then((result) => { + successCount++; if (process.env.CI) console.log('::endgroup::'); - } - this.successCount++; - console.log(`${BOLD_GREEN}SUCCESS:${ANSI_RESET} ${id}`); - } catch (error) { - this.failCount++; - console.error(error.message); - console.log(`${BOLD_RED}FAILED:${ANSI_RESET} ${id}`); - } - } + console.log(`${BOLD_GREEN}SUCCESS:${ANSI_RESET} ${id}`); + results[id] = {success: true}; + resolve(result); + }) + .catch((err) => { + failCount++; + if (!firstErr) { + // Save the first error so we can use it in the stack trace later. + firstErr = err; + } + console.error(err.message); + if (process.env.CI) console.log('::endgroup::'); + console.log(`${BOLD_RED}FAILED:${ANSI_RESET} ${id}`); + results[id] = {success: false, message: err.message}; + // Always continue. + resolve(err); + }); + }); +} - /** - * Print test results. - */ - reportTestResult() { - console.log('======================================='); - // Check result. - if (this.failCount === 0) { - console.log( - `${BOLD_GREEN}All ${this.successCount} tests passed.${ANSI_RESET}`); - } else { - console.log( - `${BOLD_RED}Failures in ${this.failCount} test groups.${ANSI_RESET}`); +function createSummary() { + let summary = '# Test Summary\n\n'; + summary += '|Test Name|Passed?|Error message|\n'; + summary += '|---------|-------|-------------|\n'; + for (const test in results) { + summary += `|${test}|${results[test].success + ? ':white_check_mark:' : ':x:'}|${results[test].message ?? ''}|\n`; + } + summary += `\n\n## Total: ${successCount} passed. ${failCount} failed.`; + return summary; +} + +/** + * Print test results and fail the task if needed. + */ +function reportTestResult() { + console.log('======================================='); + if (process.env.CI && process.env.GITHUB_STEP_SUMMARY) { + try { + fs.writeFileSync(process.env.GITHUB_STEP_SUMMARY, createSummary()); + } catch(e) { + // Don't fail CI just because we couldn't write the summary. + console.log('Failed to write job summary', e); } } -}; + // Check result. + if (failCount === 0) { + console.log( + `${BOLD_GREEN}All ${successCount} tests passed.${ANSI_RESET}`); + return Promise.resolve(); + } + console.log( + `${BOLD_RED}Failures in ${failCount} test groups.${ANSI_RESET}`); + return Promise.reject(firstErr || + 'Unspecified test failures, see above. The following stack trace is unlikely to be useful.'); +} /** * Helper method for running test command. * @param {string} command Command line to run. * @return {Promise} Asynchronous result. */ -async function runTestCommand(command) { - execSync(command, {stdio: 'inherit'}); +async function runTestCommand(id, command) { + return runTestTask(id, async() => { + return execSync(command, {stdio: 'inherit'}); + }); } /** @@ -121,7 +136,7 @@ function eslint() { console.log('Skip linting.'); return Promise.resolve(); } - return runTestCommand('eslint .'); + return runTestCommand('eslint', 'eslint .'); } /** @@ -130,7 +145,7 @@ function eslint() { * @return {Promise} Asynchronous result. */ function build() { - return runTestCommand('npm run package -- --verbose --debug'); + return runTestCommand('build', 'npm run package -- --verbose --debug'); } /** @@ -138,7 +153,7 @@ function build() { * @return {Promise} Asynchronous result. */ function renamings() { - return runTestCommand('node tests/migration/validate-renamings.js'); + return runTestCommand('renamings', 'node tests/migration/validate-renamings.js'); } /** @@ -172,17 +187,23 @@ function compareSize(file, expected) { const stat = fs.statSync(name); const size = stat.size; + if (!compare) { + const message = `Failed: Previous size of ${name} is undefined.`; + console.log(`${BOLD_RED}${message}${ANSI_RESET}`); + return 1; + } + if (size > compare) { const message = `Failed: ` + `Size of ${name} has grown more than 10%. ${size} vs ${expected}`; console.log(`${BOLD_RED}${message}${ANSI_RESET}`); return 1; - } else { - const message = - `Size of ${name} at ${size} compared to previous ${expected}`; - console.log(`${BOLD_GREEN}${message}${ANSI_RESET}`); - return 0; } + + const message = + `Size of ${name} at ${size} compared to previous ${expected}`; + console.log(`${BOLD_GREEN}${message}${ANSI_RESET}`); + return 0; } /** @@ -203,31 +224,33 @@ function zippingFiles() { * @return {Promise} Asynchronous result. */ async function metadata() { - // Zipping the compressed files. - await zippingFiles(); - // Read expected size from script. - const contents = fs.readFileSync('tests/scripts/check_metadata.sh') - .toString(); - const pattern = /^readonly (?[A-Z_]+)=(?\d+)$/gm; - const matches = contents.matchAll(pattern); - const expected = {}; - for (const match of matches) { - expected[match.groups.key] = match.groups.value; - } + return runTestTask('metadata', async () => { + // Zipping the compressed files. + await zippingFiles(); + // Read expected size from script. + const contents = fs.readFileSync('tests/scripts/check_metadata.sh') + .toString(); + const pattern = /^readonly (?[A-Z_]+)=(?\d+)$/gm; + const matches = contents.matchAll(pattern); + const expected = {}; + for (const match of matches) { + expected[match.groups.key] = match.groups.value; + } - // Check the sizes of the files. - let failed = 0; - failed += compareSize('blockly_compressed.js', - expected.BLOCKLY_SIZE_EXPECTED); - failed += compareSize('blocks_compressed.js', - expected.BLOCKS_SIZE_EXPECTED); - failed += compareSize('blockly_compressed.js.gz', - expected.BLOCKLY_GZ_SIZE_EXPECTED); - failed += compareSize('blocks_compressed.js.gz', - expected.BLOCKS_GZ_SIZE_EXPECTED); - if (failed > 0) { - throw new Error('Unexpected growth was detected.'); - } + // Check the sizes of the files. + let failed = 0; + failed += compareSize('blockly_compressed.js', + expected.BLOCKLY_SIZE_EXPECTED); + failed += compareSize('blocks_compressed.js', + expected.BLOCKS_SIZE_EXPECTED); + failed += compareSize('blockly_compressed.js.gz', + expected.BLOCKLY_GZ_SIZE_EXPECTED); + failed += compareSize('blocks_compressed.js.gz', + expected.BLOCKS_GZ_SIZE_EXPECTED); + if (failed > 0) { + throw new Error('Unexpected growth was detected.'); + } + }); } /** @@ -235,13 +258,15 @@ async function metadata() { * @return {Promise} Asynchronous result. */ async function mocha() { - const result = await runMochaTestsInBrowser().catch(e => { - throw e; + return runTestTask('mocha', async () => { + const result = await runMochaTestsInBrowser().catch(e => { + throw e; + }); + if (result) { + throw new Error('Mocha tests failed'); + } + console.log('Mocha tests passed'); }); - if (result) { - throw new Error('Mocha tests failed'); - } - console.log('Mocha tests passed'); } /** @@ -297,25 +322,27 @@ function checkResult(suffix) { * @return {Promise} Asynchronous result. */ async function generators() { - // Clean up. - rimraf.sync(OUTPUT_DIR); - fs.mkdirSync(OUTPUT_DIR); + return runTestTask('generators', async () => { + // Clean up. + rimraf.sync(OUTPUT_DIR); + fs.mkdirSync(OUTPUT_DIR); - await runGeneratorsInBrowser(OUTPUT_DIR).catch(() => {}); + await runGeneratorsInBrowser(OUTPUT_DIR); - const generatorSuffixes = ['js', 'py', 'dart', 'lua', 'php']; - let failed = 0; - generatorSuffixes.forEach((suffix) => { - failed += checkResult(suffix); + const generatorSuffixes = ['js', 'py', 'dart', 'lua', 'php']; + let failed = 0; + generatorSuffixes.forEach((suffix) => { + failed += checkResult(suffix); + }); + + if (failed === 0) { + console.log(`${BOLD_GREEN}All generator tests passed.${ANSI_RESET}`); + } else { + console.log( + `${BOLD_RED}Failures in ${failed} generator tests.${ANSI_RESET}`); + throw new Error('Generator tests failed.'); + } }); - - if (failed === 0) { - console.log(`${BOLD_GREEN}All generator tests passed.${ANSI_RESET}`); - } else { - console.log( - `${BOLD_RED}Failures in ${failed} generator tests.${ANSI_RESET}`); - throw new Error('Generator tests failed.'); - } } /** @@ -323,29 +350,53 @@ async function generators() { * @return {Promise} Asynchronous result. */ function node() { - return runTestCommand('mocha tests/node --config tests/node/.mocharc.js'); + return runTestCommand('node', 'mocha tests/node --config tests/node/.mocharc.js'); } /** * Attempt advanced compilation of a Blockly app. - * @return {Promise} Asynchronous result. + * @returns {Promise} Async result. */ function advancedCompile() { - const compilePromise = runTestCommand('npm run test:compile:advanced'); - return compilePromise.then(runCompileCheckInBrowser); + return runTestCommand('advanced_compile', 'npm run test:compile:advanced'); +} + +/** + * Attempt advanced compilation of a Blockly app and make sure it runs in the browser. + * Should be run after the `advancedCompile` test. + * @return {Promise} Asynchronous result. + */ +function advancedCompileInBrowser() { + return runTestTask('advanced_compile_in_browser', runCompileCheckInBrowser); +} + +/** + * Verify the built Blockly type definitions compile with the supported + * TypeScript examples included in `./tests/typescript`. + * @returns {Promise} Asynchronous result. + */ +function typeDefinitions() { + return runTestCommand('type_definitions', + `tsc -p ./tests/typescript/tsconfig.json -outDir ${TEST_TSC_OUTPUT_DIR}`); } // Run all tests in sequence. -const test = new Tester([ +const tasks = [ eslint, + // Build must run before the remaining tasks build, renamings, metadata, mocha, generators, node, + typeDefinitions, + // Make sure these two are in series with each other advancedCompile, -]).asTask(); + advancedCompileInBrowser +]; + +const test = gulp.series(...tasks, reportTestResult); module.exports = { diff --git a/scripts/migration/js2ts b/scripts/migration/js2ts new file mode 100755 index 000000000..324a75086 --- /dev/null +++ b/scripts/migration/js2ts @@ -0,0 +1,154 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); + +const filenames = process.argv.slice(2); // Trim off node and script name. + +////////////////////////////////////////////////////////////////////// +// Load deps files via require (since they're executalbe .js files). +////////////////////////////////////////////////////////////////////// + +/** + * Dictionary mapping goog.module ID to absolute pathname of the file + * containing the goog.declareModuleId for that ID. + * @type {!Object} + */ +const modulePaths = {}; + +/** Absolute path of repository root. */ +const repoPath = path.resolve(__dirname, '..', '..'); + +/** + * Absolute path of directory containing base.js (the version used as + * input to tsc, not the one output by it). + * @type {string} + */ +const closurePath = path.resolve(repoPath, 'closure', 'goog'); + +globalThis.goog = {}; + +/** + * Stub version of addDependency that store mappings in modulePaths. + * @param {string} relPath The path to the js file. + * @param {!Array} provides An array of strings with + * the names of the objects this file provides. + * @param {!Array} _requires An array of strings with + * the names of the objects this file requires (unused). + * @param {boolean|!Object=} opt_loadFlags Parameters indicating + * how the file must be loaded. The boolean 'true' is equivalent + * to {'module': 'goog'} for backwards-compatibility. Valid properties + * and values include {'module': 'goog'} and {'lang': 'es6'}. + */ +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; + + // There should be only one "provide" from an ESM, but... + for (const moduleId of provides) { + // Store absolute path to source file (i.e., treating relPath + // relative to closure/goog/, not build/src/closure/goog/). + modulePaths[moduleId] = path.resolve(closurePath, relPath); + } +}; + +// Load deps files relative to this script's location. +require(path.resolve(__dirname, '../../build/deps.js')); +require(path.resolve(__dirname, '../../build/deps.mocha.js')); + +////////////////////////////////////////////////////////////////////// +// Process files mentioned on the command line. +////////////////////////////////////////////////////////////////////// + +/** RegExp matching goog.require statements. */ +const requireRE = + /(?:const\s+(?:([$\w]+)|(\{[^}]*\}))\s+=\s+)?goog.require(Type)?\('([^']+)'\);/mg; + +for (const filename of filenames) { + let contents = null; + try { + contents = String(fs.readFileSync(filename)); + } catch (e) { + console.error(`error while reading ${filename}: ${e.message}`); + continue; + } + console.log(`Converting ${filename} to TypeScript...`); + + // Remove "use strict". + 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); + contents = contents.replace( + /^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; + } + const relativePath = + path.relative(path.dirname(path.resolve(filename)), importPath); + if (name) { + return `import${type} * as ${name} from '${relativePath}';`; + } else if (names) { + 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. + } + }); + // Add 'export' to existing declarations where appropriate. + for (const {exportName, declRE} of easyExports) { + contents = contents.replace(declRE, '$1export $2'); + } + + // Write converted file with new extension. + const newFilename = filename.replace(/.js$/, '.ts'); + fs.writeFileSync(newFilename, contents); + console.log(`Wrote ${newFilename}.`); +} diff --git a/scripts/migration/renamings.json5 b/scripts/migration/renamings.json5 index 2c33d67ef..308ea2bce 100644 --- a/scripts/migration/renamings.json5 +++ b/scripts/migration/renamings.json5 @@ -1422,11 +1422,25 @@ }, ], - 'develop': [ - // New renamings go here! + '9.2.0': [ { oldName: 'Blockly.TouchGesture', newName: 'Blockly.Gesture', - }, - ] + }, + ], + + '9.3.0': [ + { + oldName: 'Blockly.Xml', + exports: { + textToDom: { + newModule: 'Blockly.utils.xml', + }, + }, + } + ], + + 'develop': [ + // New renamings go here! + ], } diff --git a/tests/bootstrap.js b/tests/bootstrap.js index d872ab269..0b422464a 100644 --- a/tests/bootstrap.js +++ b/tests/bootstrap.js @@ -20,22 +20,16 @@ * * See tests/playground.html for example usage. * - * Exception: for speed and compatibility reasons, if this is - * script is loaded in Internet Explorer or from a host other than - * localhost, blockly_compressed.js (et al.) will be loaded - * instead. IE 11 doesn't understand modern JavaScript, and - * because of the sequential, non-parallel module loading carried - * out by thedeubg module loader can be painfully tedious over a - * slow network connection. (This can be overridden by the page - * if desired.) - * - * (Note also that this file eschews certain modern JS constructs, - * like template literals, for compatibility with IE 11.) + * Exception: for speed, if this is script is from a host other + * than localhost, blockly_compressed.js (et al.) will be loaded + * instead. Because of the sequential, non-parallel module loading + * carried out by the debug module loader, loading can be painfully + * tedious over a slow network connection. (This can be overridden + * by the page if desired.) * * The bootstrap code will consult a BLOCKLY_BOOTSTRAP_OPTIONS * global variable to determine what to load. This must be set * before loading this script. See documentation inline below. - * */ 'use strict'; @@ -108,7 +102,7 @@ // the named export corresponding to the mentioned global variable // will be imported. // - // Exception: in compressed mode, the UMD wrapeprs generated by + // Exception: in compressed mode, the UMD wrappers generated by // chunkWrapper() in scripts/gulpfiles/build_tasks.js already pull // out the desired named export - so in that case the entries here // are treated identically to those in namedImports. @@ -156,7 +150,7 @@ // Disable loading of closure/goog/deps.js (which doesn't exist). window.CLOSURE_NO_DEPS = true; // Load the Closure Library's base.js (the only part of the - // libary we use, mainly for goog.require / goog.provide / + // library we use, mainly for goog.require / goog.provide / // goog.module). document.write( `` diff --git a/tests/bootstrap_helper.js b/tests/bootstrap_helper.js index 4a22dadcb..f70d52101 100644 --- a/tests/bootstrap_helper.js +++ b/tests/bootstrap_helper.js @@ -10,7 +10,7 @@ * This is loaded, via goog.bootstrap(), after the other top-level * Blockly modules. It simply calls goog.require() for each of them, * to force the debug module loader to finish loading them before any - * non-module scripts (like msg/messages.js) that might have + * non-module scripts (like msg/en.js) that might have * undeclared dependencies on them. */ @@ -21,20 +21,6 @@ // Force debug module loader to finish loading all modules. for (const require of info.requires) { goog.require(require); - - // This is a kludge to work around an issue where attempting to - // load Blockly.libraryBlocks (blocks/blocks.js) fails if the - // Blockly global variable is not defined. - // - // This is apparently because the debug module loader fails to - // load Blockly.libraryBlocks.lists (blocks/lists.js) and - // .procedures (blocks/procedures.js) first, despite they both - // being required from blocks.js, and that is apparently because - // they both depend on Blockly.Xml which the debug loader seems - // to think has not been loaded yet even though it has. - if (require === 'Blockly') { - window.Blockly = goog.module.get('Blockly'); - } } } diff --git a/tests/generators/golden/generated.js b/tests/generators/golden/generated.js index 2778376c2..f8ac5651a 100644 --- a/tests/generators/golden/generated.js +++ b/tests/generators/golden/generated.js @@ -1338,9 +1338,9 @@ function listsGetSortCompare(type, direction) { 'NUMERIC': function(a, b) { return Number(a) - Number(b); }, 'TEXT': function(a, b) { - return a.toString() > b.toString() ? 1 : -1; }, + return String(a) > String(b) ? 1 : -1; }, 'IGNORE_CASE': function(a, b) { - return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; }, + return String(a).toLowerCase() > String(b).toLowerCase() ? 1 : -1; }, }; var compare = compareFuncs[type]; return function(a, b) { return compare(a, b) * direction; }; diff --git a/tests/generators/index.html b/tests/generators/index.html index c93e966d9..fba4d370f 100644 --- a/tests/generators/index.html +++ b/tests/generators/index.html @@ -121,7 +121,7 @@ function fromXml(filename, xmlText, opt_append) { demoWorkspace.clear(); } try { - var xmlDoc = Blockly.Xml.textToDom(xmlText); + var xmlDoc = Blockly.utils.xml.textToDom(xmlText); if (opt_append) { Blockly.Xml.appendDomToWorkspace(xmlDoc, demoWorkspace); } else { diff --git a/tests/generators/webdriver.js b/tests/generators/webdriver.js index 202850746..a422323ec 100644 --- a/tests/generators/webdriver.js +++ b/tests/generators/webdriver.js @@ -66,6 +66,10 @@ async function runGeneratorsInBrowser(outputDir) { console.log('Starting webdriverio...'); const browser = await webdriverio.remote(options); + + // Increase the script timeouts to 2 minutes to allow the generators to finish. + await browser.setTimeout({ 'script': 120000 }) + console.log('Loading url: ' + url); await browser.url(url); diff --git a/tests/mocha/.eslintrc.json b/tests/mocha/.eslintrc.json index 99dda9b38..a35932d7b 100644 --- a/tests/mocha/.eslintrc.json +++ b/tests/mocha/.eslintrc.json @@ -14,7 +14,7 @@ "prefer-rest-params": ["off"], "no-invalid-this": ["off"] }, - "extends": "../../.eslintrc.json", + "extends": "../../.eslintrc.js", "parserOptions": { "sourceType": "module" } diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index d25eb1d86..093c8ebba 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -299,7 +299,7 @@ suite('Blocks', function() { setup(function() { this.blocks = createTestBlocks(this.workspace, true); }); - + test('Don\'t heal', function() { this.blocks.B.dispose(false); assertDisposedNoheal(this.blocks); @@ -313,11 +313,11 @@ suite('Blocks', function() { test('Heal with bad checks', function() { const blocks = this.blocks; - + // A and C can't connect, but both can connect to B. blocks.A.inputList[0].connection.setCheck('type1'); blocks.C.outputConnection.setCheck('type2'); - + // Each block has only one input, but the types don't work. blocks.B.dispose(true); assertDisposedHealFailed(blocks); @@ -362,7 +362,7 @@ suite('Blocks', function() { setup(function() { this.blocks = createTestBlocks(this.workspace, false); }); - + test('Don\'t heal', function() { this.blocks.B.dispose(); assertDisposedNoheal(this.blocks); @@ -378,10 +378,10 @@ suite('Blocks', function() { // A and C can't connect, but both can connect to B. blocks.A.nextConnection.setCheck('type1'); blocks.C.previousConnection.setCheck('type2'); - + // The types don't work. blocks.B.dispose(true); - + assertDisposedHealFailed(blocks); }); @@ -506,7 +506,7 @@ suite('Blocks', function() { suite('Deserialization', function() { setup(function() { this.deserializationHelper = function(text) { - const dom = Blockly.Xml.textToDom(text); + const dom = Blockly.utils.xml.textToDom(text); Blockly.Xml.appendDomToWorkspace(dom, this.workspace); this.assertConnectionsEmpty(); this.clock.runAll(); @@ -616,7 +616,7 @@ suite('Blocks', function() { chai.assert.equal(this.getInputs().length, 0); }); test('Collapsed Multi-Row Middle', function() { - Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom( + Blockly.Xml.appendDomToWorkspace(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -735,7 +735,7 @@ suite('Blocks', function() { }); suite('setCollapsed', function() { test('Stack', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); this.clock.runAll(); @@ -751,7 +751,7 @@ suite('Blocks', function() { chai.assert.equal(this.getNext().length, 1); }); test('Multi-Stack', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -776,7 +776,7 @@ suite('Blocks', function() { chai.assert.equal(this.getNext().length, 3); }); test('Row', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); this.clock.runAll(); @@ -792,7 +792,7 @@ suite('Blocks', function() { chai.assert.equal(this.getInputs().length, 1); }); test('Multi-Row', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -816,7 +816,7 @@ suite('Blocks', function() { chai.assert.equal(this.getInputs().length, 3); }); test('Multi-Row Middle', function() { - let block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + let block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -843,7 +843,7 @@ suite('Blocks', function() { test('Multi-Row Double Collapse', function() { // Collapse middle -> Collapse top -> // Uncollapse top -> Uncollapse middle - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -876,7 +876,7 @@ suite('Blocks', function() { chai.assert.equal(this.getInputs().length, 3); }); test('Statement', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); this.clock.runAll(); @@ -892,7 +892,7 @@ suite('Blocks', function() { chai.assert.equal(this.getNext().length, 2); }); test('Multi-Statement', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -917,7 +917,7 @@ suite('Blocks', function() { chai.assert.equal(this.getNext().length, 6); }); test('Multi-Statement Middle', function() { - let block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + let block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -943,7 +943,7 @@ suite('Blocks', function() { chai.assert.equal(this.getNext().length, 6); }); test('Multi-Statement Double Collapse', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -979,7 +979,7 @@ suite('Blocks', function() { }); suite('Setting Parent Block', function() { setup(function() { - this.printBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.printBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1112,48 +1112,45 @@ suite('Blocks', function() { suite('Add Connections Programmatically', function() { test('Output', function() { const block = createRenderedBlock(this.workspace, 'empty_block'); - // this.workspace.newBlock('empty_block'); - // block.initSvg(); - // block.render(); block.setOutput(true); + this.clock.runAll(); + this.clock.runAll(); chai.assert.equal(this.getOutputs().length, 1); }); test('Value', function() { - const block = this.workspace.newBlock('empty_block'); - block.initSvg(); - block.render(); + const block = createRenderedBlock(this.workspace, 'empty_block'); block.appendValueInput('INPUT'); + this.clock.runAll(); chai.assert.equal(this.getInputs().length, 1); }); test('Previous', function() { - const block = this.workspace.newBlock('empty_block'); - block.initSvg(); - block.render(); + const block = createRenderedBlock(this.workspace, 'empty_block'); block.setPreviousStatement(true); + this.clock.runAll(); + this.clock.runAll(); chai.assert.equal(this.getPrevious().length, 1); }); test('Next', function() { - const block = this.workspace.newBlock('empty_block'); - block.initSvg(); - block.render(); + const block = createRenderedBlock(this.workspace, 'empty_block'); block.setNextStatement(true); + this.clock.runAll(); + this.clock.runAll(); chai.assert.equal(this.getNext().length, 1); }); test('Statement', function() { - const block = this.workspace.newBlock('empty_block'); - block.initSvg(); - block.render(); + const block = createRenderedBlock(this.workspace, 'empty_block'); block.appendStatementInput('STATEMENT'); + this.clock.runAll(); chai.assert.equal(this.getNext().length, 1); }); }); @@ -1181,7 +1178,7 @@ suite('Blocks', function() { }); suite('Headless', function() { setup(function() { - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); }); @@ -1214,7 +1211,7 @@ suite('Blocks', function() { comments: true, scrollbars: true, }); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); }); @@ -1281,7 +1278,7 @@ suite('Blocks', function() { suite('Getting/Setting Field (Values)', function() { setup(function() { this.workspace = Blockly.inject('blocklyDiv'); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( 'test' ), this.workspace); }); @@ -1349,7 +1346,7 @@ suite('Blocks', function() { }); test('Has Icon', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); block.setCommentText('test text'); @@ -1359,7 +1356,7 @@ suite('Blocks', function() { chai.assert.isFalse(block.comment.isVisible()); }); test('Child Has Icon', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1374,7 +1371,7 @@ suite('Blocks', function() { chai.assert.isFalse(childBlock.comment.isVisible()); }); test('Next Block Has Icon', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1719,8 +1716,10 @@ suite('Blocks', function() { test('Add Input', function() { const blockA = createRenderedBlock(this.workspace, 'empty_block'); blockA.setCollapsed(true); - assertCollapsed(blockA); + blockA.appendDummyInput('NAME'); + + this.clock.runAll(); assertCollapsed(blockA); chai.assert.isNotNull(blockA.getInput('NAME')); }); @@ -1794,20 +1793,20 @@ suite('Blocks', function() { const blockA = createRenderedBlock(this.workspace, 'variable_block'); blockA.setCollapsed(true); - assertCollapsed(blockA, 'x'); - const variable = this.workspace.getVariable('x', ''); this.workspace.renameVariableById(variable.getId(), 'y'); + + this.clock.runAll(); assertCollapsed(blockA, 'y'); }); test('Coalesce, Different Case', function() { const blockA = createRenderedBlock(this.workspace, 'variable_block'); blockA.setCollapsed(true); - assertCollapsed(blockA, 'x'); - const variable = this.workspace.createVariable('y'); this.workspace.renameVariableById(variable.getId(), 'X'); + + this.clock.runAll(); assertCollapsed(blockA, 'X'); }); }); @@ -1829,25 +1828,6 @@ suite('Blocks', function() { chai.assert.isFalse(blockB.disabled); chai.assert.isFalse(blockB.getSvgRoot().classList.contains('blocklyDisabled')); }); - test('Children of Collapsed Block Should Not Update', function() { - const blockA = createRenderedBlock(this.workspace, 'statement_block'); - const blockB = createRenderedBlock(this.workspace, 'stack_block'); - blockA.getInput('STATEMENT').connection - .connect(blockB.previousConnection); - - // Disable the block and collapse it. - blockA.setEnabled(false); - blockA.setCollapsed(true); - - const blockUpdateDisabled = sinon.stub(blockB, 'updateDisabled'); - - // Enable the block before expanding it. - blockA.setEnabled(true); - - // For performance reasons updateDisabled should not be called - // on children of collapsed blocks. - sinon.assert.notCalled(blockUpdateDisabled); - }); test('Disabled Children of Collapsed Blocks Should Stay Disabled', function() { const blockA = createRenderedBlock(this.workspace, 'statement_block'); const blockB = createRenderedBlock(this.workspace, 'stack_block'); @@ -1873,7 +1853,7 @@ suite('Blocks', function() { suite('Style', function() { suite('Headless', function() { setup(function() { - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); }); @@ -1894,7 +1874,7 @@ suite('Blocks', function() { suite('Rendered', function() { setup(function() { this.workspace = Blockly.inject('blocklyDiv', {}); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); this.workspace.setTheme(new Blockly.Theme('test', { @@ -2046,7 +2026,7 @@ suite('Blocks', function() { // Create mocha test cases for each toString test. toStringTests.forEach(function(t) { test(t.name, function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(t.xml), + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(t.xml), this.workspace); chai.assert.equal(block.toString(), t.toString); }); diff --git a/tests/mocha/blocks/procedures_test.js b/tests/mocha/blocks/procedures_test.js index 0e5e944c3..e792e0e81 100644 --- a/tests/mocha/blocks/procedures_test.js +++ b/tests/mocha/blocks/procedures_test.js @@ -7,28 +7,1041 @@ goog.declareModuleId('Blockly.test.procedures'); import * as Blockly from '../../../build/src/core/blockly.js'; -import {assertCallBlockStructure, assertDefBlockStructure, createProcDefBlock, createProcCallBlock} from '../test_helpers/procedures.js'; +import {assertCallBlockStructure, assertDefBlockStructure, createProcDefBlock, createProcCallBlock, MockProcedureModel} from '../test_helpers/procedures.js'; import {runSerializationTestSuite} from '../test_helpers/serialization.js'; import {createGenUidStubWithReturns, sharedTestSetup, sharedTestTeardown, workspaceTeardown} from '../test_helpers/setup_teardown.js'; +import {defineRowBlock} from '../test_helpers/block_definitions.js'; suite('Procedures', function() { setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); + sharedTestSetup.call(this, {fireEventsNow: false}); + this.workspace = Blockly.inject('blocklyDiv', {}); this.workspace.createVariable('preCreatedVar', '', 'preCreatedVarId'); this.workspace.createVariable( 'preCreatedTypedVar', 'type', 'preCreatedTypedVarId'); + defineRowBlock(); }); + teardown(function() { sharedTestTeardown.call(this); }); + suite('renaming procedures', function() { + test('callers are updated to have the new name', function() { + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + + defBlock.setFieldValue('new name', 'NAME'); + + chai.assert.equal( + callBlock.getFieldValue('NAME'), + 'new name', + 'Expected the procedure block to be renamed'); + }); + + test( + 'setting an illegal name results in both the ' + + 'procedure and the caller getting the legal name', + function() { + createProcDefBlock(this.workspace, undefined, undefined, 'procA'); + const defBlockB = + createProcDefBlock(this.workspace, undefined, undefined, 'procB'); + const callBlockB = + createProcCallBlock(this.workspace, undefined, 'procB'); + + defBlockB.setFieldValue('procA', 'NAME'); + + chai.assert.notEqual( + defBlockB.getFieldValue('NAME'), + 'procA', + 'Expected the procedure def block to have a legal name'); + chai.assert.notEqual( + callBlockB.getFieldValue('NAME'), + 'procA', + 'Expected the procedure call block to have a legal name'); + }); + }); + + suite('adding procedure parameters', function() { + test( + 'the mutator flyout updates to avoid parameter name conflicts', + function() { + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const origFlyoutParamName = + mutatorWorkspace.getFlyout().getWorkspace().getTopBlocks(true)[0] + .getFieldValue('NAME'); + Blockly.serialization.blocks.append( + { + 'type': 'procedures_mutatorarg', + 'fields': { + 'NAME': origFlyoutParamName, + }, + }, + mutatorWorkspace); + this.clock.runAll(); + + const newFlyoutParamName = + mutatorWorkspace.getFlyout().getWorkspace().getTopBlocks(true)[0] + .getFieldValue('NAME'); + chai.assert.notEqual( + newFlyoutParamName, + origFlyoutParamName, + 'Expected the flyout param to have updated to not conflict'); + }); + + test('adding a parameter to the procedure updates procedure defs', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to contain the name of the new param'); + }); + + test('adding a parameter to the procedure updates procedure callers', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + chai.assert.isNotNull( + callBlock.getInput('ARG0'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME0'), + 'param1', + 'Expected the params field to match the name of the new param'); + }); + + test('undoing adding a procedure parameter removes it', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + this.workspace.undo(); + + chai.assert.isFalse( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to not contain the name of the new param'); + }); + + test( + 'undoing and redoing adding a procedure parameter maintains ' + + 'the same state', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect( + paramBlock.previousConnection); + this.clock.runAll(); + + this.workspace.undo(); + this.workspace.undo(/* redo= */ true); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to contain the name of the new param'); + }); + }); + + suite('deleting procedure parameters', function() { + test('deleting a parameter from the procedure updates procedure defs', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + paramBlock.checkAndDelete(); + this.clock.runAll(); + + chai.assert.isFalse( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to not contain the name of the new param'); + }); + + test('deleting a parameter from the procedure udpates procedure callers', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + paramBlock.checkAndDelete(); + this.clock.runAll(); + + chai.assert.isNull( + callBlock.getInput('ARG0'), + 'Expected the param input to not exist'); + }); + + test('undoing deleting a procedure parameter adds it', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + paramBlock.checkAndDelete(); + this.clock.runAll(); + + this.workspace.undo(); + + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to contain the name of the new param'); + }); + + test('undoing and redoing deleting a procedure parameter maintains ' + + 'the same state', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + paramBlock.checkAndDelete(); + this.clock.runAll(); + + this.workspace.undo(); + this.workspace.undo(/* redo= */ true); + + chai.assert.isFalse( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to not contain the name of the new param'); + }); + }); + + suite('renaming procedure parameters', function() { + test('defs are updated for parameter renames', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + paramBlock.setFieldValue('new name', 'NAME'); + this.clock.runAll(); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('new name'), + 'Expected the params field to contain the new name of the param'); + }); + + test('defs are updated for parameter renames when two params exist', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock1 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock1.setFieldValue('param1', 'NAME'); + const paramBlock2 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock2.setFieldValue('param2', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock1.previousConnection); + paramBlock1.nextConnection.connect(paramBlock2.previousConnection); + this.clock.runAll(); + + paramBlock1.setFieldValue('new name', 'NAME'); + this.clock.runAll(); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('new name'), + 'Expected the params field to contain the new name of the param'); + }); + + test('callers are updated for parameter renames', function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + paramBlock.setFieldValue('new name', 'NAME'); + this.clock.runAll(); + + chai.assert.isNotNull( + callBlock.getInput('ARG0'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME0'), + 'new name', + 'Expected the params field to match the name of the new param'); + }); + + test( + 'variables associated with procedure parameters are not renamed', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + + paramBlock.setFieldValue('param2', 'NAME'); + this.clock.runAll(); + + chai.assert.isNotNull( + this.workspace.getVariable('param1', ''), + 'Expected the old variable to continue to exist'); + }); + + test( + 'renaming a variable associated with a parameter updates procedure defs', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + defBlock.mutator.setVisible(false); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'new name'); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('new name'), + 'Expected the params field to contain the new name of the param'); + }); + + test( + 'renaming a variable associated with a parameter updates mutator parameters', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'new name'); + + chai.assert.equal( + paramBlock.getFieldValue('NAME'), + 'new name', + 'Expected the params field to contain the new name of the param'); + }); + + test( + 'renaming a variable associated with a parameter updates procedure callers', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + defBlock.mutator.setVisible(false); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'new name'); + + chai.assert.isNotNull( + callBlock.getInput('ARG0'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME0'), + 'new name', + 'Expected the params field to match the name of the new param'); + }); + + test( + 'coalescing a variable associated with a parameter updates procedure defs', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + defBlock.mutator.setVisible(false); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'preCreatedVar'); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('preCreatedVar'), + 'Expected the params field to contain the new name of the param'); + }); + + test( + 'coalescing a variable associated with a parameter updates mutator parameters', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'preCreatedVar'); + + chai.assert.equal( + paramBlock.getFieldValue('NAME'), + 'preCreatedVar', + 'Expected the params field to contain the new name of the param'); + }); + + test( + 'coalescing a variable associated with a parameter updates procedure callers', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection + .connect(paramBlock.previousConnection); + this.clock.runAll(); + defBlock.mutator.setVisible(false); + + const variable = this.workspace.getVariable('param1', ''); + this.workspace.renameVariableById(variable.getId(), 'preCreatedVar'); + + chai.assert.isNotNull( + callBlock.getInput('ARG0'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME0'), + 'preCreatedVar', + 'Expected the params field to match the name of the new param'); + }); + + test.skip( + 'renaming a variable such that you get a parameter ' + + 'conflict does... something!', + function() { + + }); + + test( + 'undoing renaming a procedure parameter reverts the change', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + Blockly.Events.setGroup(true); + paramBlock.setFieldValue('n', 'NAME'); + this.clock.runAll(); + paramBlock.setFieldValue('ne', 'NAME'); + this.clock.runAll(); + paramBlock.setFieldValue('new', 'NAME'); + this.clock.runAll(); + Blockly.Events.setGroup(false); + + this.workspace.undo(); + this.clock.runAll(); + + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('param1'), + 'Expected the params field to contain the old name of the param'); + }); + + test( + 'undoing and redoing renaming a procedure maintains the same state', + function() { + // Create a stack of container, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock.setFieldValue('param1', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock.previousConnection); + this.clock.runAll(); + Blockly.Events.setGroup(true); + paramBlock.setFieldValue('n', 'NAME'); + this.clock.runAll(); + paramBlock.setFieldValue('ne', 'NAME'); + this.clock.runAll(); + paramBlock.setFieldValue('new', 'NAME'); + this.clock.runAll(); + Blockly.Events.setGroup(false); + + this.workspace.undo(); + this.workspace.undo(/* redo= */ true); + + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('new'), + 'Expected the params field to contain the new name of the param'); + }); + }); + + suite('reordering procedure parameters', function() { + test('reordering procedure parameters updates procedure blocks', function() { + // Create a stack of container, parameter, parameter. + const defBlock = createProcDefBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock1 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock1.setFieldValue('param1', 'NAME'); + const paramBlock2 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock2.setFieldValue('param2', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock1.previousConnection); + paramBlock1.nextConnection.connect(paramBlock2.previousConnection); + this.clock.runAll(); + + // Reorder the parameters. + paramBlock2.previousConnection.disconnect(); + paramBlock1.previousConnection.disconnect(); + containerBlock.getInput('STACK').connection.connect(paramBlock2.previousConnection); + paramBlock2.nextConnection.connect(paramBlock1.previousConnection); + this.clock.runAll(); + + chai.assert.isNotNull( + defBlock.getField('PARAMS'), + 'Expected the params field to exist'); + chai.assert.isTrue( + defBlock.getFieldValue('PARAMS').includes('param2, param1'), + 'Expected the params field order to match the parameter order'); + }); + + test('reordering procedure parameters updates caller blocks', function() { + // Create a stack of container, parameter, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock1 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock1.setFieldValue('param1', 'NAME'); + const paramBlock2 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock2.setFieldValue('param2', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock1.previousConnection); + paramBlock1.nextConnection.connect(paramBlock2.previousConnection); + this.clock.runAll(); + + // Reorder the parameters. + paramBlock2.previousConnection.disconnect(); + paramBlock1.previousConnection.disconnect(); + containerBlock.getInput('STACK').connection.connect(paramBlock2.previousConnection); + paramBlock2.nextConnection.connect(paramBlock1.previousConnection); + this.clock.runAll(); + + chai.assert.isNotNull( + callBlock.getInput('ARG0'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME0'), + 'param2', + 'Expected the params field to match the name of the second param'); + chai.assert.isNotNull( + callBlock.getInput('ARG1'), + 'Expected the param input to exist'); + chai.assert.equal( + callBlock.getFieldValue('ARGNAME1'), + 'param1', + 'Expected the params field to match the name of the first param'); + }); + + test( + 'reordering procedure parameters reorders the blocks ' + + 'attached to caller inputs', + function() { + // Create a stack of container, parameter, parameter. + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.mutator.setVisible(true); + const mutatorWorkspace = defBlock.mutator.getWorkspace(); + const containerBlock = mutatorWorkspace.getTopBlocks()[0]; + const paramBlock1 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock1.setFieldValue('param1', 'NAME'); + const paramBlock2 = mutatorWorkspace.newBlock('procedures_mutatorarg'); + paramBlock2.setFieldValue('param2', 'NAME'); + containerBlock.getInput('STACK').connection.connect(paramBlock1.previousConnection); + paramBlock1.nextConnection.connect(paramBlock2.previousConnection); + this.clock.runAll(); + + // Add args to the parameter inputs on the caller. + const block1 = this.workspace.newBlock('text'); + const block2 = this.workspace.newBlock('text'); + callBlock.getInput('ARG0').connection + .connect(block1.outputConnection); + callBlock.getInput('ARG1').connection + .connect(block2.outputConnection); + + // Reorder the parameters. + paramBlock2.previousConnection.disconnect(); + paramBlock1.previousConnection.disconnect(); + containerBlock.getInput('STACK').connection.connect(paramBlock2.previousConnection); + paramBlock2.nextConnection.connect(paramBlock1.previousConnection); + this.clock.runAll(); + + chai.assert.equal( + callBlock.getInputTargetBlock('ARG0'), + block2, + 'Expected the second block to be in the first slot'); + chai.assert.equal( + callBlock.getInputTargetBlock('ARG1'), + block1, + 'Expected the first block to be in the second slot'); + }); + }); + + suite('enabling and disabling procedure blocks', function() { + test( + 'if a procedure definition is disabled, the procedure caller ' + + 'is also disabled', + function() { + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + + defBlock.setEnabled(false); + this.clock.runAll(); + + chai.assert.isFalse( + callBlock.isEnabled(), + 'Expected the caller block to be disabled'); + }); + + test( + 'if a procedure definition is enabled, the procedure caller ' + + 'is also enabled', + function() { + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + defBlock.setEnabled(false); + this.clock.runAll(); + + defBlock.setEnabled(true); + this.clock.runAll(); + + chai.assert.isTrue( + callBlock.isEnabled(), + 'Expected the caller block to be enabled'); + }); + + test( + 'if a procedure caller block was already disabled before ' + + 'its definition was disabled, it is not reenabled', + function() { + const defBlock = createProcDefBlock(this.workspace); + const callBlock = createProcCallBlock(this.workspace); + this.clock.runAll(); + callBlock.setEnabled(false); + this.clock.runAll(); + defBlock.setEnabled(false); + this.clock.runAll(); + + defBlock.setEnabled(true); + this.clock.runAll(); + + chai.assert.isFalse( + callBlock.isEnabled(), + 'Expected the caller block to continue to be disabled'); + }); + }); + + suite('deleting procedure blocks', function() { + test( + 'when the procedure definition block is deleted, all of its ' + + 'associated callers are deleted as well', + function() { + const defBlock = createProcDefBlock(this.workspace); + const callBlock1 = createProcCallBlock(this.workspace); + const callBlock2 = createProcCallBlock(this.workspace); + + this.clock.runAll(); + defBlock.dispose(); + this.clock.runAll(); + + chai.assert.isTrue( + callBlock1.disposed, 'Expected the first caller to be disposed'); + chai.assert.isTrue( + callBlock2.disposed, 'Expected the second caller to be disposed'); + }); + }); + + suite('caller blocks creating new def blocks', function() { + setup(function() { + this.TEST_VAR_ID = 'test-id'; + this.genUidStub = createGenUidStubWithReturns(this.TEST_VAR_ID); + }); + + suite('xml', function() { + test('callers without defs create new defs', function() { + const callBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(` + + + ` + ), this.workspace); + this.clock.runAll(); + assertDefBlockStructure( + this.workspace.getBlocksByType('procedures_defreturn')[0], true); + assertCallBlockStructure(callBlock, [], [], 'do something'); + }); + + test('callers without mutations create unnamed defs', function() { + const callBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( + '' + ), this.workspace); + this.clock.runAll(); + assertDefBlockStructure( + this.workspace.getBlocksByType('procedures_defreturn')[0], true); + assertCallBlockStructure(callBlock, [], [], 'unnamed'); + }); + + test('callers with missing args create new defs', function() { + const defBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(` + + do something + + + + + `), this.workspace); + const callBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( + '' + + ' ' + + '' + ), this.workspace); + this.clock.runAll(); + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure(callBlock, [], [], 'do something2'); + }); + + test('callers with mismatched args create new defs', function() { + const defBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(` + + do something + + + + + `), this.workspace); + const callBlock = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(` + + + + + + `), this.workspace); + this.clock.runAll(); + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure( + callBlock, ['y'], [this.TEST_VAR_ID], 'do something2'); + }); + + test.skip( + 'callers whose defs are deserialized later do not create defs', + function() { + Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom(` + + + + + + + + do something + + + + + + `), this.workspace); + this.clock.runAll(); + const defBlock = + this.workspace.getBlocksByType('procedures_defreturn')[0]; + const callBlock = + this.workspace.getBlocksByType('procedures_callreturn')[0]; + // TODO: Currently the callers are creating variables with different + // IDs than those serialized to XML, so these assertions fail. + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure(callBlock, ['x'], ['arg'], 'do something'); + }); + }); + + suite('json', function() { + test('callers without defs create new defs', function() { + const callBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_callreturn', + 'extraState': { + 'name': 'do something', + }, + }, this.workspace, {recordUndo: true}); + this.clock.runAll(); + assertDefBlockStructure( + this.workspace.getBlocksByType('procedures_defreturn')[0], true); + assertCallBlockStructure(callBlock, [], [], 'do something'); + }); + + test('callers without extra state create unamed defs', function() { + // recordUndo must be true to trigger change listener. + const callBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_callreturn', + }, this.workspace, {recordUndo: true}); + this.clock.runAll(); + assertDefBlockStructure( + this.workspace.getBlocksByType('procedures_defreturn')[0], true); + assertCallBlockStructure(callBlock, [], [], 'unnamed'); + }); + + test('callers with missing args create new defs', function() { + const defBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_defreturn', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': 'arg', + }, + ], + }, + }, this.workspace); + const callBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_callreturn', + 'extraState': { + 'name': 'do something', + }, + }, this.workspace, {recordUndo: true}); + this.clock.runAll(); + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure(callBlock, [], [], 'do something2'); + }); + + test('callers with mismatched args create new defs', function() { + const defBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_defreturn', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': 'arg', + }, + ], + }, + }, this.workspace); + const callBlock = Blockly.serialization.blocks.append({ + 'type': 'procedures_callreturn', + 'extraState': { + 'name': 'do something', + 'params': ['y'], + }, + }, this.workspace, {recordUndo: true}); + this.clock.runAll(); + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure( + callBlock, ['y'], [this.TEST_VAR_ID], 'do something2'); + }); + + test.skip( + 'callers whose defs are deserialized later do not create defs', + function() { + Blockly.serialization.workspaces.load({ + 'blocks': { + 'languageVersion': 0, + 'blocks': [ + { + 'type': 'procedures_callreturn', + 'extraState': { + 'params': ['x'], + }, + }, + { + 'type': 'procedures_defreturn', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': 'arg', + }, + ], + }, + }, + ], + }, + }, this.workspace); + this.clock.runAll(); + const defBlock = + this.workspace.getBlocksByType('procedures_defreturn')[0]; + const callBlock = + this.workspace.getBlocksByType('procedures_callreturn')[0]; + // TODO: Currently the callers are creating variables with different + // IDs than those serialized to JSON, so these assertions fail. + assertDefBlockStructure(defBlock, true, ['x'], ['arg']); + assertCallBlockStructure(callBlock, ['x'], ['arg'], 'do something'); + }); + }); + }); + + suite('definition block context menu', function() { + test('the context menu includes an option for creating the caller', function() { + const def = Blockly.serialization.blocks.append({ + 'type': 'procedures_defnoreturn', + 'fields': { + 'NAME': 'test name', + }, + }, this.workspace); + + const options = []; + def.customContextMenu(options); + + chai.assert.isTrue( + options[0].text.includes('test name'), + 'Expected the context menu to have an option to create the caller'); + }); + + test('the context menu includes an option for each parameter', function() { + const def = Blockly.serialization.blocks.append({ + 'type': 'procedures_defnoreturn', + 'fields': { + 'NAME': 'test name', + }, + 'extraState': { + 'params': [ + { + 'name': 'testParam1', + 'id': 'varId1', + 'paramId': 'paramId1', + }, + { + 'name': 'testParam2', + 'id': 'varId2', + 'paramId': 'paramId2', + }, + ], + }, + }, this.workspace); + + const options = []; + def.customContextMenu(options); + + chai.assert.isTrue( + options[1].text.includes('testParam1'), + 'Expected the context menu to have an option to create the first param'); + chai.assert.isTrue( + options[2].text.includes('testParam2'), + 'Expected the context menu to have an option to create the second param'); + }); + }); + suite('allProcedures', function() { test('Only Procedures', function() { - const noReturnBlock = new Blockly.Block(this.workspace, 'procedures_defnoreturn'); + const noReturnBlock = this.workspace.newBlock('procedures_defnoreturn'); noReturnBlock.setFieldValue('no return', 'NAME'); - const returnBlock = new Blockly.Block(this.workspace, 'procedures_defreturn'); + const returnBlock = this.workspace.newBlock('procedures_defreturn'); returnBlock.setFieldValue('return', 'NAME'); const allProcedures = Blockly.Procedures.allProcedures(this.workspace); @@ -40,14 +1053,15 @@ suite('Procedures', function() { chai.assert.lengthOf(allProcedures[1], 1); chai.assert.equal(allProcedures[1][0][0], 'return'); }); + test('Multiple Blocks', function() { - const noReturnBlock = new Blockly.Block(this.workspace, 'procedures_defnoreturn'); + const noReturnBlock = this.workspace.newBlock('procedures_defnoreturn'); noReturnBlock.setFieldValue('no return', 'NAME'); - const returnBlock = new Blockly.Block(this.workspace, 'procedures_defreturn'); + const returnBlock = this.workspace.newBlock('procedures_defreturn'); returnBlock.setFieldValue('return', 'NAME'); - const returnBlock2 = new Blockly.Block(this.workspace, 'procedures_defreturn'); + const returnBlock2 = this.workspace.newBlock('procedures_defreturn'); returnBlock2.setFieldValue('return2', 'NAME'); - const _ = new Blockly.Block(this.workspace, 'controls_if'); + const _ = this.workspace.newBlock('controls_if'); const allProcedures = Blockly.Procedures.allProcedures(this.workspace); chai.assert.lengthOf(allProcedures, 2); @@ -59,8 +1073,9 @@ suite('Procedures', function() { chai.assert.equal(allProcedures[1][0][0], 'return'); chai.assert.equal(allProcedures[1][1][0], 'return2'); }); + test('No Procedures', function() { - const _ = new Blockly.Block(this.workspace, 'controls_if'); + const _ = this.workspace.newBlock('controls_if'); const allProcedures = Blockly.Procedures.allProcedures(this.workspace); chai.assert.lengthOf(allProcedures, 2); chai.assert.lengthOf(allProcedures[0], 0, 'No procedures_defnoreturn blocks expected'); @@ -69,132 +1084,35 @@ suite('Procedures', function() { }); suite('isNameUsed', function() { - test('No Blocks', function() { + test('returns false if no blocks or models exists', function() { chai.assert.isFalse( - Blockly.Procedures.isNameUsed('name1', this.workspace) - ); + Blockly.Procedures.isNameUsed('proc name', this.workspace)); }); - }); - suite('Enable/Disable', function() { - setup(function() { - const toolbox = document.getElementById('toolbox-categories'); - this.workspaceSvg = Blockly.inject('blocklyDiv', {toolbox: toolbox}); + test('returns true if an associated block exists', function() { + createProcDefBlock(this.workspace, false, [], 'proc name'); + chai.assert.isTrue( + Blockly.Procedures.isNameUsed('proc name', this.workspace)); }); - teardown(function() { - workspaceTeardown.call(this, this.workspaceSvg); - sinon.restore(); + + test('return false if an associated block does not exist', function() { + createProcDefBlock(this.workspace, false, [], 'proc name'); + chai.assert.isFalse( + Blockly.Procedures.isNameUsed('other proc name', this.workspace)); }); - suite('Inherited disabled', function() { - setup(function() { - const dom = Blockly.Xml.textToDom( - '' + - '' + - 'bar' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - 'foo' + - '' + - '' + - 'baz' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - ''); - Blockly.Events.disable(); - Blockly.Xml.appendDomToWorkspace(dom, this.workspaceSvg); - Blockly.Events.enable(); - this.barDef = this.workspaceSvg.getBlockById('bar-def'); - this.fooDef = this.workspaceSvg.getBlockById('foo-def'); - this.bazDef = this.workspaceSvg.getBlockById('baz-def'); + test('returns true if an associated procedure model exists', function() { + this.workspace.getProcedureMap() + .add(new MockProcedureModel().setName('proc name')); + chai.assert.isTrue( + Blockly.Procedures.isNameUsed('proc name', this.workspace)); + }); - this.barCalls = [ - this.workspaceSvg.getBlockById('bar-c1'), - this.workspaceSvg.getBlockById('bar-c2')]; - this.fooCalls = [ - this.workspaceSvg.getBlockById('foo-c1'), - this.workspaceSvg.getBlockById('foo-c2')]; - this.bazCall = this.workspaceSvg.getBlockById('baz-c1'); - }); - test('Nested caller', function() { - this.barDef.setEnabled(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isFalse(this.barCalls[i].isEnabled(), - 'Callers are disabled when their definition is disabled ' + - '(bar call ' + i + ')'); - } - chai.assert.isTrue(this.fooCalls[0].isEnabled(), - 'Callers in definitions are disabled by inheritance'); - chai.assert.isTrue(this.fooCalls[0].getInheritedDisabled(), - 'Callers in definitions are disabled by inheritance'); - - this.fooDef.setEnabled(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isFalse(this.fooCalls[i].isEnabled(), - 'Callers are disabled when their definition is disabled ' + - '(foo call ' + i + ')'); - } - - this.barDef.setEnabled(true); - - for (let i = 0; i < 2; i++) { - chai.assert.isTrue(this.barCalls[i].isEnabled(), - 'Callers are reenabled with their definition ' + - '(bar call ' + i + ')'); - } - chai.assert.isFalse(this.fooCalls[0].isEnabled(), - 'Nested disabled callers remain disabled'); - chai.assert.isFalse(this.fooCalls[0].getInheritedDisabled(), - 'Nested disabled callers remain disabled, not by inheritance'); - }); - test('Caller in return', function() { - this.bazDef.setEnabled(false); - - chai.assert.isFalse(this.bazCall.isEnabled(), - 'Caller is disabled with its definition'); - - chai.assert.isTrue(this.barCalls[1].isEnabled(), - 'Caller in the return is disabled by inheritance'); - chai.assert.isTrue(this.barCalls[1].getInheritedDisabled(), - 'Caller in the return is disabled by inheritance'); - - this.barDef.setEnabled(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isFalse(this.barCalls[i].isEnabled(), - 'Callers are disabled when their definition is disabled ' + - '(bar call ' + i + ')'); - } - - this.bazDef.setEnabled(true); - - chai.assert.isFalse(this.barCalls[1].isEnabled(), - 'Caller in return remains disabled'); - chai.assert.isFalse(this.barCalls[1].getInheritedDisabled(), - 'Caller in return remains disabled, not by inheritance'); - }); + test('returns false if an associated procedure model exists', function() { + this.workspace.getProcedureMap() + .add(new MockProcedureModel().setName('proc name')); + chai.assert.isFalse( + Blockly.Procedures.isNameUsed('other proc name', this.workspace)); }); }); @@ -202,25 +1120,37 @@ suite('Procedures', function() { function assertDefAndCallBlocks(workspace, noReturnNames, returnNames, hasCallers) { const allProcedures = Blockly.Procedures.allProcedures(workspace); const defNoReturnBlocks = allProcedures[0]; - chai.assert.lengthOf(defNoReturnBlocks, noReturnNames.length); + chai.assert.lengthOf( + defNoReturnBlocks, + noReturnNames.length, + `Expected the number of no return blocks to be ${noReturnNames.length}`); for (let i = 0; i < noReturnNames.length; i++) { const expectedName = noReturnNames[i]; chai.assert.equal(defNoReturnBlocks[i][0], expectedName); if (hasCallers) { const callers = Blockly.Procedures.getCallers(expectedName, workspace); - chai.assert.lengthOf(callers, 1); + chai.assert.lengthOf( + callers, + 1, + `Expected there to be one caller of the ${expectedName} block`); } } const defReturnBlocks = allProcedures[1]; - chai.assert.lengthOf(defReturnBlocks, returnNames.length); + chai.assert.lengthOf( + defReturnBlocks, + returnNames.length, + `Expected the number of return blocks to be ${returnNames.length}`); for (let i = 0; i < returnNames.length; i++) { const expectedName = returnNames[i]; chai.assert.equal(defReturnBlocks[i][0], expectedName); if (hasCallers) { const callers = Blockly.Procedures.getCallers(expectedName, workspace); - chai.assert.lengthOf(callers, 1); + chai.assert.lengthOf( + callers, + 1, + `Expected there to be one caller of the ${expectedName} block`); } } @@ -232,147 +1162,69 @@ suite('Procedures', function() { const blocks = workspace.getAllBlocks(false); chai.assert.lengthOf(blocks, expectedCount); } + suite('no name renamed to unnamed', function() { test('defnoreturn and defreturn', function() { - const xml = Blockly.Xml.textToDom(` + const xml = Blockly.utils.xml.textToDom(` `); Blockly.Xml.domToWorkspace(xml, this.workspace); + this.clock.runAll(); + assertDefAndCallBlocks( this.workspace, ['unnamed'], ['unnamed2'], false); }); + test('defreturn and defnoreturn', function() { - const xml = Blockly.Xml.textToDom(` + const xml = Blockly.utils.xml.textToDom(` `); Blockly.Xml.domToWorkspace(xml, this.workspace); + this.clock.runAll(); + assertDefAndCallBlocks( this.workspace, ['unnamed2'], ['unnamed'], false); }); - test('callnoreturn (no def in xml)', function() { - const xml = Blockly.Xml.textToDom(` - - - `); - Blockly.Xml.domToWorkspace(xml, this.workspace); - assertDefAndCallBlocks( - this.workspace, ['unnamed'], [], true); - }); + test('callreturn (no def in xml)', function() { - const xml = Blockly.Xml.textToDom(` + const xml = Blockly.utils.xml.textToDom(` `); Blockly.Xml.domToWorkspace(xml, this.workspace); + this.clock.runAll(); assertDefAndCallBlocks( this.workspace, [], ['unnamed'], true); }); + test('callnoreturn and callreturn (no def in xml)', function() { - const xml = Blockly.Xml.textToDom(` + const xml = Blockly.utils.xml.textToDom(` - - + + `); Blockly.Xml.domToWorkspace(xml, this.workspace); + this.clock.runAll(); assertDefAndCallBlocks( this.workspace, ['unnamed'], ['unnamed2'], true); }); + test('callreturn and callnoreturn (no def in xml)', function() { - const xml = Blockly.Xml.textToDom(` + const xml = Blockly.utils.xml.textToDom(` `); Blockly.Xml.domToWorkspace(xml, this.workspace); + this.clock.runAll(); assertDefAndCallBlocks( this.workspace, ['unnamed2'], ['unnamed'], true); }); }); - suite('caller param mismatch', function() { - setup(function() { - this.TEST_VAR_ID = 'test-id'; - this.genUidStub = createGenUidStubWithReturns(this.TEST_VAR_ID); - }); - - test('callreturn with missing args', function() { - const defBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - do something - - - - - `), this.workspace); - const callBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure(callBlock, [], [], 'do something2'); - }); - test('callreturn with bad args', function() { - const defBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - do something - - - - - `), this.workspace); - const callBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - - - - - `), this.workspace); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure( - callBlock, ['y'], [this.TEST_VAR_ID], 'do something2'); - }); - test('callnoreturn with missing args', function() { - const defBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - do something - - - - - `), this.workspace); - const callBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ), this.workspace); - assertDefBlockStructure(defBlock, false, ['x'], ['arg']); - assertCallBlockStructure(callBlock, [], [], 'do something2'); - }); - test('callnoreturn with bad args', function() { - const defBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - do something - - - - - `), this.workspace); - const callBlock = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(` - - - - - - `), this.workspace); - assertDefBlockStructure(defBlock, false, ['x'], ['arg']); - assertCallBlockStructure( - callBlock, ['y'], [this.TEST_VAR_ID], 'do something2'); - }); - }); }); suite('getDefinition - Modified cases', function() { @@ -404,14 +1256,14 @@ suite('Procedures', function() { test('Custom procedure block', function() { // Do not require procedures to be the built-in procedures. - const defBlock = new Blockly.Block(this.workspace, 'new_proc'); + const defBlock = this.workspace.newBlock('new_proc'); const def = Blockly.Procedures.getDefinition('test', this.workspace); chai.assert.equal(def, defBlock); }); test('Stacked procedures', function() { - const blockA = new Blockly.Block(this.workspace, 'nested_proc'); - const blockB = new Blockly.Block(this.workspace, 'nested_proc'); + const blockA = this.workspace.newBlock('nested_proc'); + const blockB = this.workspace.newBlock('nested_proc'); blockA.name = 'a'; blockB.name = 'b'; blockA.nextConnection.connect(blockB.previousConnection); @@ -431,7 +1283,7 @@ suite('Procedures', function() { suite(testSuite.title, function() { suite('Structure', function() { setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); + this.defBlock = this.workspace.newBlock(testSuite.defType); this.defBlock.setFieldValue('proc name', 'NAME'); }); test('Definition block', function() { @@ -439,36 +1291,28 @@ suite('Procedures', function() { }); test('Call block', function() { - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); + this.callBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.callType, + }, this.workspace, {recordUndo: true}); this.callBlock.setFieldValue('proc name', 'NAME'); + this.clock.runAll(); assertCallBlockStructure(this.callBlock); }); }); - suite('isNameUsed', function() { - setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); - this.defBlock.setFieldValue('proc name', 'NAME'); - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); - this.callBlock.setFieldValue('proc name', 'NAME'); - }); - test('True', function() { - chai.assert.isTrue( - Blockly.Procedures.isNameUsed('proc name', this.workspace)); - }); - test('False', function() { - chai.assert.isFalse( - Blockly.Procedures.isNameUsed('unused proc name', this.workspace)); - }); - }); suite('rename', function() { setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); - this.defBlock.setFieldValue('proc name', 'NAME'); - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); - this.callBlock.setFieldValue('proc name', 'NAME'); + this.defBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.defType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); + this.callBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.callType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); sinon.stub(this.defBlock.getField('NAME'), 'resizeEditor_'); }); test('Simple, Programmatic', function() { @@ -566,7 +1410,7 @@ suite('Procedures', function() { defInput.htmlInput_.value = ''; defInput.onHtmlInputChange_(null); - const newDefBlock = new Blockly.Block(this.workspace, testSuite.defType); + const newDefBlock = this.workspace.newBlock(testSuite.defType); newDefBlock.setFieldValue('new name', 'NAME'); chai.assert.equal( this.defBlock.getFieldValue('NAME'), @@ -578,11 +1422,18 @@ suite('Procedures', function() { }); suite('getCallers', function() { setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); - this.defBlock.setFieldValue('proc name', 'NAME'); - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); - this.callBlock.setFieldValue('proc name', 'NAME'); + this.defBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.defType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); + this.callBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.callType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); }); test('Simple', function() { const callers = @@ -591,9 +1442,9 @@ suite('Procedures', function() { chai.assert.equal(callers[0], this.callBlock); }); test('Multiple Callers', function() { - const caller2 = new Blockly.Block(this.workspace, testSuite.callType); + const caller2 = this.workspace.newBlock(testSuite.callType); caller2.setFieldValue('proc name', 'NAME'); - const caller3 = new Blockly.Block(this.workspace, testSuite.callType); + const caller3 = this.workspace.newBlock(testSuite.callType); caller3.setFieldValue('proc name', 'NAME'); const callers = @@ -604,9 +1455,9 @@ suite('Procedures', function() { chai.assert.equal(callers[2], caller3); }); test('Multiple Procedures', function() { - const def2 = new Blockly.Block(this.workspace, testSuite.defType); + const def2 = this.workspace.newBlock(testSuite.defType); def2.setFieldValue('proc name2', 'NAME'); - const caller2 = new Blockly.Block(this.workspace, testSuite.callType); + const caller2 = this.workspace.newBlock(testSuite.callType); caller2.setFieldValue('proc name2', 'NAME'); const callers = @@ -632,9 +1483,9 @@ suite('Procedures', function() { test('Multiple Workspaces', function() { const workspace = new Blockly.Workspace(); try { - const def2 = new Blockly.Block(workspace, testSuite.defType); + const def2 = workspace.newBlock(testSuite.defType); def2.setFieldValue('proc name', 'NAME'); - const caller2 = new Blockly.Block(workspace, testSuite.callType); + const caller2 = workspace.newBlock(testSuite.callType); caller2.setFieldValue('proc name', 'NAME'); let callers = @@ -652,11 +1503,18 @@ suite('Procedures', function() { }); suite('getDefinition', function() { setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); - this.defBlock.setFieldValue('proc name', 'NAME'); - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); - this.callBlock.setFieldValue('proc name', 'NAME'); + this.defBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.defType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); + this.callBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.callType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); }); test('Simple', function() { const def = @@ -664,9 +1522,9 @@ suite('Procedures', function() { chai.assert.equal(def, this.defBlock); }); test('Multiple Procedures', function() { - const def2 = new Blockly.Block(this.workspace, testSuite.defType); + const def2 = this.workspace.newBlock(testSuite.defType); def2.setFieldValue('proc name2', 'NAME'); - const caller2 = new Blockly.Block(this.workspace, testSuite.callType); + const caller2 = this.workspace.newBlock(testSuite.callType); caller2.setFieldValue('proc name2', 'NAME'); const def = @@ -676,9 +1534,9 @@ suite('Procedures', function() { test('Multiple Workspaces', function() { const workspace = new Blockly.Workspace(); try { - const def2 = new Blockly.Block(workspace, testSuite.defType); + const def2 = workspace.newBlock(testSuite.defType); def2.setFieldValue('proc name', 'NAME'); - const caller2 = new Blockly.Block(workspace, testSuite.callType); + const caller2 = workspace.newBlock(testSuite.callType); caller2.setFieldValue('proc name', 'NAME'); let def = @@ -693,135 +1551,20 @@ suite('Procedures', function() { }); }); - suite('Enable/Disable', function() { - setup(function() { - const toolbox = document.getElementById('toolbox-categories'); - this.workspaceSvg = Blockly.inject('blocklyDiv', {toolbox: toolbox}); - }); - teardown(function() { - workspaceTeardown.call(this, this.workspaceSvg); - }); - const domText = (testSuite.defType === 'procedures_defreturn') ? - ('' + - '' + - 'bar' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '') : - ('' + - '' + - 'bar' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - ''); - setup(function() { - const dom = Blockly.Xml.textToDom(domText); - - Blockly.Xml.appendDomToWorkspace(dom, this.workspaceSvg); - this.barDef = this.workspaceSvg.getBlockById('bar-def'); - this.barCalls = [ - this.workspaceSvg.getBlockById('bar-c1'), - this.workspaceSvg.getBlockById('bar-c2'), - ]; - }); - - test('Set disabled updates callers', function() { - this.workspaceSvg.clearUndo(); - Blockly.Events.setGroup('g1'); - this.barDef.setEnabled(false); - Blockly.Events.setGroup(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isFalse(this.barCalls[i].isEnabled(), - 'Callers are disabled when their definition is disabled (call ' + - i + ')'); - } - const firedEvents = this.workspaceSvg.undoStack_; - chai.assert.equal(firedEvents.length, 3, - 'An event was fired for the definition and each caller'); - for (let i = 0; i < 3; i++) { - chai.assert.equal(firedEvents[i].group, 'g1', - 'Disable events are in the same group (event ' + i + ')'); - } - - this.workspaceSvg.clearUndo(); - Blockly.Events.setGroup('g2'); - this.barDef.setEnabled(true); - Blockly.Events.setGroup(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isTrue(this.barCalls[i].isEnabled(), - 'Callers are enabled when their definition is enabled (call ' + - i + ')'); - } - chai.assert.equal(firedEvents.length, 3, - 'An event was fired for the definition and each caller'); - for (let i = 0; i < 3; i++) { - chai.assert.equal(firedEvents[i].group, 'g2', - 'Enable events are in the same group (event ' + i + ')'); - } - }); - test('Set disabled updates callers while remembering old caller state', function() { - this.barCalls[0].setEnabled(false); - this.workspaceSvg.clearUndo(); - Blockly.Events.setGroup('g1'); - this.barDef.setEnabled(false); - Blockly.Events.setGroup(false); - - for (let i = 0; i < 2; i++) { - chai.assert.isFalse(this.barCalls[i].isEnabled(), - 'Callers are disabled when their definition is disabled (call ' + - i + ')'); - } - const firedEvents = this.workspaceSvg.undoStack_; - chai.assert.equal(firedEvents.length, 2, - 'An event was fired for the definition and the enabled caller'); - for (let i = 0; i < 2; i++) { - chai.assert.equal(firedEvents[i].group, 'g1', - 'Disable events are in the same group (event ' + i + ')'); - } - - this.workspaceSvg.clearUndo(); - Blockly.Events.setGroup('g2'); - this.barDef.setEnabled(true); - Blockly.Events.setGroup(false); - - chai.assert.isFalse(this.barCalls[0].isEnabled(), - 'Caller remains in disabled state when the definition is enabled'); - chai.assert.isTrue(this.barCalls[1].isEnabled(), - 'Caller returns to previous enabled state when the definition is enabled'); - chai.assert.equal(firedEvents.length, 2, - 'An event was fired for the definition and the enabled caller'); - for (let i = 0; i < 2; i++) { - chai.assert.equal(firedEvents[i].group, 'g2', - 'Enable events are in the same group (event ' + i + ')'); - } - }); - }); suite('Mutation', function() { setup(function() { - this.defBlock = new Blockly.Block(this.workspace, testSuite.defType); - this.defBlock.setFieldValue('proc name', 'NAME'); - this.callBlock = new Blockly.Block( - this.workspace, testSuite.callType); - this.callBlock.setFieldValue('proc name', 'NAME'); - this.findParentStub = sinon.stub(Blockly.Mutator, 'findParentWs') - .returns(this.workspace); - }); - teardown(function() { - this.findParentStub.restore(); + this.defBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.defType, + 'fields': { + 'NAME': 'proc name', + }, + }, this.workspace); + this.callBlock = Blockly.serialization.blocks.append({ + 'type': testSuite.callType, + 'extraState': { + 'name': 'proc name', + }, + }, this.workspace); }); suite('Composition', function() { suite('Statements', function() { @@ -846,7 +1589,7 @@ suite('Procedures', function() { chai.assert.isFalse(this.defBlock.hasStatements_); }); test('Saving Statements', function() { - const blockXml = Blockly.Xml.textToDom( + const blockXml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -868,29 +1611,32 @@ suite('Procedures', function() { }); suite('Untyped Arguments', function() { function createMutator(argArray) { - this.mutatorWorkspace = new Blockly.Workspace( - new Blockly.Options({ - parentWorkspace: this.workspace, - })); - this.containerBlock = this.defBlock.decompose(this.mutatorWorkspace); + this.defBlock.mutator.setVisible(true); + this.mutatorWorkspace = this.defBlock.mutator.getWorkspace(); + this.containerBlock = this.mutatorWorkspace.getTopBlocks()[0]; this.connection = this.containerBlock.getInput('STACK').connection; for (let i = 0; i < argArray.length; i++) { - this.argBlock = new Blockly.Block( - this.mutatorWorkspace, 'procedures_mutatorarg'); + this.argBlock = this.mutatorWorkspace.newBlock('procedures_mutatorarg'); this.argBlock.setFieldValue(argArray[i], 'NAME'); this.connection.connect(this.argBlock.previousConnection); this.connection = this.argBlock.nextConnection; } - this.defBlock.compose(this.containerBlock); + this.clock.runAll(); } function assertArgs(argArray) { - chai.assert.equal(this.defBlock.arguments_.length, argArray.length); + chai.assert.equal( + this.defBlock.getVars().length, + argArray.length, + 'Expected the def to have the right number of arguments'); for (let i = 0; i < argArray.length; i++) { - chai.assert.equal(this.defBlock.arguments_[i], argArray[i]); + chai.assert.equal(this.defBlock.getVars()[i], argArray[i]); } - chai.assert.equal(this.callBlock.arguments_.length, argArray.length); + chai.assert.equal( + this.callBlock.getVars().length, + argArray.length, + 'Expected the call to have the right number of arguments'); for (let i = 0; i < argArray.length; i++) { - chai.assert.equal(this.callBlock.arguments_[i], argArray[i]); + chai.assert.equal(this.callBlock.getVars()[i], argArray[i]); } } test('Simple Add Arg', function() { @@ -997,33 +1743,6 @@ suite('Procedures', function() { }); } }); - suite('Untyped Arguments', function() { - function assertArguments(argumentsArray) { - this.defBlock.arguments_ = argumentsArray; - const mutatorWorkspace = new Blockly.Workspace( - new Blockly.Options({ - parentWorkspace: this.workspace, - })); - this.defBlock.decompose(mutatorWorkspace); - const argBlocks = mutatorWorkspace.getBlocksByType('procedures_mutatorarg'); - chai.assert.equal(argBlocks.length, argumentsArray.length); - - for (let i = 0; i < argumentsArray.length; i++) { - const argString = argumentsArray[i]; - const argBlockValue = argBlocks[i].getFieldValue('NAME'); - chai.assert.equal(argBlockValue, argString); - } - } - test('Simple Single Arg', function() { - assertArguments.call(this, ['arg']); - }); - test('Multiple Args', function() { - assertArguments.call(this, ['arg1', 'arg2']); - }); - test('<>', function() { - assertArguments.call(this, ['<>']); - }); - }); }); }); /** @@ -1032,7 +1751,7 @@ suite('Procedures', function() { */ const testCases = [ { - title: 'Minimal definition', + title: 'XML - Minimal definition', xml: '', expectedXml: '' + ' do something' + @@ -1061,7 +1780,7 @@ suite('Procedures', function() { }, }, { - title: 'With vars definition', + title: 'XML - With vars definition', xml: '\n' + ' \n' + @@ -1086,7 +1805,7 @@ suite('Procedures', function() { }, }, { - title: 'With pre-created vars definition', + title: 'XML - With pre-created vars definition', xml: '\n' + ' \n' + @@ -1109,30 +1828,7 @@ suite('Procedures', function() { }, }, { - title: 'With pre-created typed vars definition', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - assertBlockStructure: - (block) => { - assertDefBlockStructure(block, testSuite.hasReturn, - ['preCreatedTypedVar'], ['preCreatedTypedVarId']); - }, - }, - { - title: 'No statements definition', + title: 'XML - No statements definition', xml: '\n' + ' \n' + @@ -1150,7 +1846,7 @@ suite('Procedures', function() { }, }, { - title: 'Minimal caller', + title: 'XML - Minimal caller', xml: '', expectedXml: '\n' + ' \n' + @@ -1179,7 +1875,7 @@ suite('Procedures', function() { }, }, { - title: 'With pre-created vars caller', + title: 'XML - With pre-created vars caller', xml: '\n' + ' \n' + @@ -1198,6 +1894,214 @@ suite('Procedures', function() { assertCallBlockStructure(block, ['preCreatedVar'], ['preCreatedVarId']); }, }, + { + title: 'JSON - Minimal definition', + json: { + 'type': testSuite.defType, + }, + expectedJson: { + 'type': testSuite.defType, + 'id': '1', + 'fields': { + 'NAME': 'unnamed', + }, + }, + assertBlockStructure: + (block) => { + assertDefBlockStructure(block, testSuite.hasReturn); + }, + }, + { + title: 'JSON - Common definition', + json: { + 'type': testSuite.defType, + 'fields': { + 'NAME': 'do something', + }, + }, + expectedJson: { + 'type': testSuite.defType, + 'id': '1', + 'fields': { + 'NAME': 'do something', + }, + }, + assertBlockStructure: + (block) => { + assertDefBlockStructure(block, testSuite.hasReturn); + }, + }, + { + title: 'JSON - With vars definition', + json: { + 'type': testSuite.defType, + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': 'arg1', + }, + { + 'name': 'y', + 'id': 'arg2', + }, + ], + }, + }, + expectedJson: { + 'type': testSuite.defType, + 'id': '1', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': 'arg1', + }, + { + 'name': 'y', + 'id': 'arg2', + }, + ], + }, + }, + assertBlockStructure: + (block) => { + assertDefBlockStructure( + block, testSuite.hasReturn, ['x', 'y'], ['arg1', 'arg2']); + }, + }, + { + title: 'JSON - With pre-created vars definition', + json: { + 'type': testSuite.defType, + 'extraState': { + 'params': [ + { + 'name': 'preCreatedVar', + 'id': 'preCreatedVarId', + }, + ], + }, + 'fields': { + 'NAME': 'do something', + }, + }, + expectedJson: { + 'type': testSuite.defType, + 'id': '1', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'params': [ + { + 'name': 'preCreatedVar', + 'id': 'preCreatedVarId', + }, + ], + }, + }, + assertBlockStructure: + (block) => { + assertDefBlockStructure(block, testSuite.hasReturn, + ['preCreatedVar'], ['preCreatedVarId']); + }, + }, + { + title: 'JSON - No statements definition', + json: { + 'type': 'procedures_defreturn', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'hasStatements': false, + }, + }, + expectedJson: { + 'type': 'procedures_defreturn', + 'id': '1', + 'fields': { + 'NAME': 'do something', + }, + 'extraState': { + 'hasStatements': false, + }, + }, + assertBlockStructure: + (block) => { + assertDefBlockStructure(block, true, [], [], false); + }, + }, + { + title: 'JSON - Minimal caller', + json: { + 'type': testSuite.callType, + }, + expectedJson: { + 'type': testSuite.callType, + 'id': '1', + 'extraState': { + 'name': 'unnamed', + }, + }, + assertBlockStructure: + (block) => { + assertCallBlockStructure(block); + }, + }, + { + title: 'JSON - Common caller', + json: { + 'type': testSuite.callType, + 'extraState': { + 'name': 'do something', + }, + }, + expectedJson: { + 'type': testSuite.callType, + 'id': '1', + 'extraState': { + 'name': 'do something', + }, + }, + assertBlockStructure: + (block) => { + assertCallBlockStructure(block); + }, + }, + { + title: 'JSON - With pre-created vars caller', + json: { + 'type': testSuite.callType, + 'extraState': { + 'name': 'do something', + 'params': [ + 'preCreatedVar', + ], + }, + }, + expectedJson: { + 'type': testSuite.callType, + 'id': '1', + 'extraState': { + 'name': 'do something', + 'params': [ + 'preCreatedVar', + ], + }, + }, + assertBlockStructure: + (block) => { + assertCallBlockStructure(block, ['preCreatedVar'], ['preCreatedVarId']); + }, + }, ]; runSerializationTestSuite(testCases); }); diff --git a/tests/mocha/blocks/variables_test.js b/tests/mocha/blocks/variables_test.js index 7de2b7368..f64275509 100644 --- a/tests/mocha/blocks/variables_test.js +++ b/tests/mocha/blocks/variables_test.js @@ -7,6 +7,8 @@ goog.declareModuleId('Blockly.test.variables'); import {sharedTestSetup, sharedTestTeardown} from '../test_helpers/setup_teardown.js'; +import {nameUsedWithConflictingParam} from '../../../build/src/core/variables.js'; +import {MockParameterModelWithVar, MockProcedureModel} from '../test_helpers/procedures.js'; suite('Variables', function() { @@ -139,4 +141,100 @@ suite('Variables', function() { chai.assert.equal(var3, result3); }); }); + + suite('renaming variables creating conflicts', function() { + suite('renaming variables creating parameter conflicts', function() { + test( + 'conflicts within legacy procedure blocks return the procedure name', + function() { + Blockly.serialization.blocks.append({ + 'type': 'procedures_defnoreturn', + 'extraState': { + 'params': [ + { + 'name': 'x', + 'id': '6l3P%Y!9EgA(Nh{E`Tl,', + }, + { + 'name': 'y', + 'id': 'l1EtlJe%z_M[O-@uPAQ8', + }, + ], + }, + 'fields': { + 'NAME': 'test name', + }, + }, this.workspace); + + chai.assert.equal( + 'test name', + nameUsedWithConflictingParam('x', 'y', this.workspace), + 'Expected the name of the procedure with the conflicting ' + + 'param to be returned'); + }); + + test( + 'if no legacy block has the old var name, no procedure ' + + 'name is returned', + function() { + Blockly.serialization.blocks.append({ + 'type': 'procedures_defnoreturn', + 'extraState': { + 'params': [ + { + 'name': 'definitely not x', + 'id': '6l3P%Y!9EgA(Nh{E`Tl,', + }, + { + 'name': 'y', + 'id': 'l1EtlJe%z_M[O-@uPAQ8', + }, + ], + }, + 'fields': { + 'NAME': 'test name', + }, + }, this.workspace); + + chai.assert.isNull( + nameUsedWithConflictingParam('x', 'y', this.workspace), + 'Expected there to be no conflict'); + }); + + test( + 'conflicts within procedure models return the procedure name', + function() { + this.workspace.getProcedureMap().add( + new MockProcedureModel('test name') + .insertParameter( + new MockParameterModelWithVar('x', this.workspace), 0) + .insertParameter( + new MockParameterModelWithVar('y', this.workspace), 0)); + + chai.assert.equal( + 'test name', + nameUsedWithConflictingParam('x', 'y', this.workspace), + 'Expected the name of the procedure with the conflicting ' + + 'param to be returned'); + }); + + test( + 'if no procedure model has the old var, no procedure ' + + 'name is returned', + function() { + this.workspace.getProcedureMap().add( + new MockProcedureModel('test name') + .insertParameter( + new MockParameterModelWithVar( + 'definitely not x', this.workspace), + 0) + .insertParameter( + new MockParameterModelWithVar('y', this.workspace), 0)); + + chai.assert.isNull( + nameUsedWithConflictingParam('x', 'y', this.workspace), + 'Expected there to be no conflict'); + }); + }); + }); }); diff --git a/tests/mocha/comment_deserialization_test.js b/tests/mocha/comment_deserialization_test.js index a37e98986..c8bf0594f 100644 --- a/tests/mocha/comment_deserialization_test.js +++ b/tests/mocha/comment_deserialization_test.js @@ -34,7 +34,7 @@ suite('Comment Deserialization', function() { scrollbars: true, trashcan: true, maxTrashcanContents: Infinity, - toolbox: Blockly.Xml.textToDom(toolboxXml), + toolbox: Blockly.utils.xml.textToDom(toolboxXml), }); }); teardown(function() { @@ -46,7 +46,7 @@ suite('Comment Deserialization', function() { this.workspace.clear(); }); function createBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); block.setCommentText('test text'); diff --git a/tests/mocha/comment_test.js b/tests/mocha/comment_test.js index e358d4fb1..96365ffab 100644 --- a/tests/mocha/comment_test.js +++ b/tests/mocha/comment_test.js @@ -25,7 +25,7 @@ suite('Comments', function() { comments: true, scrollbars: true, }); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); this.comment = new Blockly.Comment(this.block); diff --git a/tests/mocha/connection_checker_test.js b/tests/mocha/connection_checker_test.js index d86d48bfb..11b9545c1 100644 --- a/tests/mocha/connection_checker_test.js +++ b/tests/mocha/connection_checker_test.js @@ -341,4 +341,111 @@ suite('Connection checker', function() { chai.assert.isFalse(this.checker.doTypeChecks(this.con1, this.con2)); }); }); + suite('Dragging Checks', function() { + suite('Stacks', function() { + setup(function() { + this.workspace = Blockly.inject('blocklyDiv'); + // Load in three blocks: A and B are connected (next/prev); B is unmovable. + Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom(` + + + + + + + + `), this.workspace); + [this.blockA, this.blockB, this.blockC] = this.workspace.getAllBlocks(true); + this.checker = this.workspace.connectionChecker; + }); + + test('Connect a stack', function() { + // block C is not connected to block A; both are movable. + chai.assert.isTrue( + this.checker.doDragChecks( + this.blockC.nextConnection, this.blockA.previousConnection, 9000), + 'Should connect two compatible stack blocks'); + }); + + test('Do not splice into unmovable stack', function() { + // Try to connect blockC above blockB. It shouldn't work because B is not movable + // and is already connected to A's nextConnection. + chai.assert.isFalse( + this.checker.doDragChecks( + this.blockC.previousConnection, this.blockA.nextConnection, 9000), + 'Should not splice in a block above an unmovable block'); + }); + + test('Connect to bottom of unmovable stack', function() { + // Try to connect blockC below blockB. + // This is allowed even though B is not movable because it is on B's nextConnection. + chai.assert.isTrue( + this.checker.doDragChecks( + this.blockC.previousConnection, this.blockB.nextConnection, 9000), + 'Should connect below an unmovable stack block'); + }); + + test('Connect to unconnected unmovable block', function() { + this.blockB.previousConnection.disconnect(); + this.blockA.dispose(); + + // Try to connect blockC above blockB. + // This is allowed because we're not splicing into a stack. + chai.assert.isTrue( + this.checker.doDragChecks( + this.blockC.nextConnection, this.blockB.previousConnection, 9000), + 'Should connect above an unconnected unmovable block' + ); + }); + }); + suite('Rows', function() { + setup(function() { + this.workspace = Blockly.inject('blocklyDiv'); + // Load 3 blocks: A and B are connected (input/output); B is unmovable. + Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom(` + + + + + + + `), this.workspace); + [this.blockA, this.blockB, this.blockC] = this.workspace.getAllBlocks(true); + this.checker = this.workspace.connectionChecker; + }); + + test('Do not splice into unmovable block row', function() { + // Try to connect C's output to A's input. Should fail because + // A is already connected to B, which is unmovable. + const inputConnection = this.blockA.inputList[0].connection; + chai.assert.isFalse( + this.checker.doDragChecks(this.blockC.outputConnection, inputConnection, 9000), + 'Should not splice in a block before an unmovable block' + ); + }); + + test('Connect to end of unmovable block', function() { + // Make blockC unmovable + this.blockC.setMovable(false); + // Try to connect A's output to C's input. This is allowed. + const inputConnection = this.blockC.inputList[0].connection; + chai.assert.isTrue( + this.checker.doDragChecks(this.blockA.outputConnection, inputConnection, 9000), + 'Should connect to end of unmovable block' + ); + }); + + test('Connect to unconnected unmovable block', function() { + this.blockB.outputConnection.disconnect(); + this.blockA.dispose(); + + // Try to connect C's input to B's output. Allowed because B is now unconnected. + const inputConnection = this.blockC.inputList[0].connection; + chai.assert.isTrue( + this.checker.doDragChecks(inputConnection, this.blockB.outputConnection, 9000), + 'Should connect to unconnected unmovable block' + ); + }); + }); + }); }); diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index 878fcd006..f011a6ebd 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -109,21 +109,21 @@ suite('Connection', function() { suite('Add - No Block Connected', function() { // These are defined separately in each suite. function createRowBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStatementBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStackBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; @@ -131,7 +131,7 @@ suite('Connection', function() { test('Value', function() { const parent = createRowBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('INPUT').connection.setShadowDom(xml); @@ -161,7 +161,7 @@ suite('Connection', function() { test('Multiple Value', function() { const parent = createRowBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -209,7 +209,7 @@ suite('Connection', function() { test('Statement', function() { const parent = createStatementBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('NAME').connection.setShadowDom(xml); @@ -239,7 +239,7 @@ suite('Connection', function() { test('Multiple Statement', function() { const parent = createStatementBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -287,7 +287,7 @@ suite('Connection', function() { test('Next', function() { const parent = createStackBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.nextConnection.setShadowDom(xml); @@ -315,7 +315,7 @@ suite('Connection', function() { test('Multiple Next', function() { const parent = createStackBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -360,7 +360,7 @@ suite('Connection', function() { suite('Add - With Block Connected', function() { // These are defined separately in each suite. function createRowBlocks(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -371,7 +371,7 @@ suite('Connection', function() { } function createStatementBlocks(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -382,7 +382,7 @@ suite('Connection', function() { } function createStackBlocks(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -394,7 +394,7 @@ suite('Connection', function() { test('Value', function() { const parent = createRowBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('INPUT').connection.setShadowDom(xml); @@ -426,7 +426,7 @@ suite('Connection', function() { test('Multiple Value', function() { const parent = createRowBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -477,7 +477,7 @@ suite('Connection', function() { test('Statement', function() { const parent = createStatementBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('NAME').connection.setShadowDom(xml); @@ -509,7 +509,7 @@ suite('Connection', function() { test('Multiple Statement', function() { const parent = createStatementBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -561,7 +561,7 @@ suite('Connection', function() { test('Next', function() { const parent = createStackBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.nextConnection.setShadowDom(xml); @@ -591,7 +591,7 @@ suite('Connection', function() { test('Multiple Next', function() { const parent = createStackBlocks(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -639,21 +639,21 @@ suite('Connection', function() { suite('Add - With Shadow Connected', function() { // These are defined separately in each suite. function createRowBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStatementBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStackBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; @@ -661,13 +661,13 @@ suite('Connection', function() { test('Value', function() { const parent = createRowBlock(this.workspace); - const xml1 = Blockly.Xml.textToDom( + const xml1 = Blockly.utils.xml.textToDom( '' ); parent.getInput('INPUT').connection.setShadowDom(xml1); assertInputHasBlock(parent, 'INPUT', true, '1'); const xml2 = - Blockly.Xml.textToDom(''); + Blockly.utils.xml.textToDom(''); parent.getInput('INPUT').connection.setShadowDom(xml2); assertInputHasBlock(parent, 'INPUT', true, '2'); assertSerialization( @@ -695,7 +695,7 @@ suite('Connection', function() { test('Multiple Value', function() { const parent = createRowBlock(this.workspace); - const xml1 = Blockly.Xml.textToDom( + const xml1 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -705,7 +705,7 @@ suite('Connection', function() { assertInputHasBlock(parent, 'INPUT', true, '1'); assertInputHasBlock( parent.getInputTargetBlock('INPUT'), 'INPUT', true, 'a'); - const xml2 = Blockly.Xml.textToDom( + const xml2 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -752,11 +752,11 @@ suite('Connection', function() { test('Statement', function() { const parent = createStatementBlock(this.workspace); - const xml1 = Blockly.Xml.textToDom( + const xml1 = Blockly.utils.xml.textToDom( ''); parent.getInput('NAME').connection.setShadowDom(xml1); assertInputHasBlock(parent, 'NAME', true, '1'); - const xml2 = Blockly.Xml.textToDom( + const xml2 = Blockly.utils.xml.textToDom( ''); parent.getInput('NAME').connection.setShadowDom(xml2); assertInputHasBlock(parent, 'NAME', true, '2'); @@ -785,7 +785,7 @@ suite('Connection', function() { test('Multiple Statement', function() { const parent = createStatementBlock(this.workspace); - const xml1 = Blockly.Xml.textToDom( + const xml1 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -795,7 +795,7 @@ suite('Connection', function() { assertInputHasBlock(parent, 'NAME', true, '1'); assertInputHasBlock( parent.getInputTargetBlock('NAME'), 'NAME', true, 'a'); - const xml2 = Blockly.Xml.textToDom( + const xml2 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -843,11 +843,11 @@ suite('Connection', function() { test('Next', function() { const parent = createStackBlock(this.workspace); const xml1 = - Blockly.Xml.textToDom(''); + Blockly.utils.xml.textToDom(''); parent.nextConnection.setShadowDom(xml1); assertNextHasBlock(parent, true, '1'); const xml2 = - Blockly.Xml.textToDom(''); + Blockly.utils.xml.textToDom(''); parent.nextConnection.setShadowDom(xml2); assertNextHasBlock(parent, true, '2'); assertSerialization( @@ -873,7 +873,7 @@ suite('Connection', function() { test('Multiple Next', function() { const parent = createStackBlock(this.workspace); - const xml1 = Blockly.Xml.textToDom( + const xml1 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -882,7 +882,7 @@ suite('Connection', function() { parent.nextConnection.setShadowDom(xml1); assertNextHasBlock(parent, true, '1'); assertNextHasBlock(parent.getNextBlock(), true, 'a'); - const xml2 = Blockly.Xml.textToDom( + const xml2 = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -926,7 +926,7 @@ suite('Connection', function() { suite('Remove - No Block Connected', function() { // These are defined separately in each suite. function createRowBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -937,7 +937,7 @@ suite('Connection', function() { } function createStatementBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -948,7 +948,7 @@ suite('Connection', function() { } function createStackBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1010,7 +1010,7 @@ suite('Connection', function() { suite('Remove - Block Connected', function() { // These are defined separately in each suite. function createRowBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1022,7 +1022,7 @@ suite('Connection', function() { } function createStatementBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1034,7 +1034,7 @@ suite('Connection', function() { } function createStackBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1103,21 +1103,21 @@ suite('Connection', function() { suite('Add - Connect & Disconnect - Remove', function() { // These are defined separately in each suite. function createRowBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStatementBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; } function createStackBlock(workspace) { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), workspace); return block; @@ -1125,7 +1125,7 @@ suite('Connection', function() { test('Value', function() { const parent = createRowBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('INPUT').connection.setShadowDom(xml); @@ -1141,7 +1141,7 @@ suite('Connection', function() { test('Multiple Value', function() { const parent = createRowBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1165,7 +1165,7 @@ suite('Connection', function() { test('Statement', function() { const parent = createStatementBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.getInput('NAME').connection.setShadowDom(xml); @@ -1182,7 +1182,7 @@ suite('Connection', function() { test('Multiple Statement', function() { const parent = createStatementBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1207,7 +1207,7 @@ suite('Connection', function() { test('Next', function() { const parent = createStackBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); parent.nextConnection.setShadowDom(xml); @@ -1223,7 +1223,7 @@ suite('Connection', function() { test('Multiple Next', function() { const parent = createStackBlock(this.workspace); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -1248,28 +1248,28 @@ suite('Connection', function() { test('Attach to output', function() { const block = this.workspace.newBlock('row_block'); chai.assert.throws(() => - block.outputConnection.setShadowDom(Blockly.Xml.textToDom( + block.outputConnection.setShadowDom(Blockly.utils.xml.textToDom( ''))); }); test('Attach to previous', function() { const block = this.workspace.newBlock('stack_block'); chai.assert.throws(() => - block.previousConnection.setShadowDom(Blockly.Xml.textToDom( + block.previousConnection.setShadowDom(Blockly.utils.xml.textToDom( ''))); }); test('Missing output', function() { const block = this.workspace.newBlock('row_block'); chai.assert.throws(() => - block.outputConnection.setShadowDom(Blockly.Xml.textToDom( + block.outputConnection.setShadowDom(Blockly.utils.xml.textToDom( ''))); }); test('Missing previous', function() { const block = this.workspace.newBlock('stack_block'); chai.assert.throws(() => - block.previousConnection.setShadowDom(Blockly.Xml.textToDom( + block.previousConnection.setShadowDom(Blockly.utils.xml.textToDom( ''))); }); @@ -1277,7 +1277,7 @@ suite('Connection', function() { const block = this.workspace.newBlock('logic_operation'); chai.assert.throws(() => block.getInput('A').connection.setShadowDom( - Blockly.Xml.textToDom(''))); + Blockly.utils.xml.textToDom(''))); }); test('Invalid connection checks, previous', function() { @@ -1289,7 +1289,7 @@ suite('Connection', function() { }]); const block = this.workspace.newBlock('stack_checks_block'); chai.assert.throws(() => - block.nextConnection.setShadowDom(Blockly.Xml.textToDom( + block.nextConnection.setShadowDom(Blockly.utils.xml.textToDom( ''))); }); }); @@ -2788,7 +2788,7 @@ suite('Connection', function() { test('Value', function() { const newParent = this.workspace.newBlock('row_block'); const child = this.workspace.newBlock('row_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.getInput('INPUT').connection.setShadowDom(xml); @@ -2803,7 +2803,7 @@ suite('Connection', function() { test('Statement', function() { const newParent = this.workspace.newBlock('statement_block'); const child = this.workspace.newBlock('stack_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.getInput('NAME').connection.setShadowDom(xml); @@ -2821,7 +2821,7 @@ suite('Connection', function() { test('Next', function() { const newParent = this.workspace.newBlock('stack_block'); const child = this.workspace.newBlock('stack_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.nextConnection.setShadowDom(xml); @@ -2838,7 +2838,7 @@ suite('Connection', function() { test('Value', function() { const newParent = this.workspace.newBlock('row_block'); const child = this.workspace.newBlock('row_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.getInput('INPUT').connection.setShadowDom(xml); @@ -2856,7 +2856,7 @@ suite('Connection', function() { test('Statement', function() { const newParent = this.workspace.newBlock('statement_block'); const child = this.workspace.newBlock('stack_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.getInput('NAME').connection.setShadowDom(xml); @@ -2876,7 +2876,7 @@ suite('Connection', function() { test('Next', function() { const newParent = this.workspace.newBlock('stack_block'); const child = this.workspace.newBlock('stack_block'); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newParent.nextConnection.setShadowDom(xml); @@ -3054,10 +3054,10 @@ suite('Connection', function() { parent.getInput('INPUT').connection .connect(oldChild.outputConnection); newChild.getInput('INPUT').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); newChild.getInput('INPUT2').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); parent.getInput('INPUT').connection @@ -3086,10 +3086,10 @@ suite('Connection', function() { newChild.getInput('INPUT2').connection .connect(childY.outputConnection); childX.getInput('INPUT').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); childY.getInput('INPUT').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); parent.getInput('INPUT').connection @@ -3115,7 +3115,7 @@ suite('Connection', function() { newChild.getInput('INPUT').connection .connect(otherChild.outputConnection); newChild.getInput('INPUT2').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); parent.getInput('INPUT').connection @@ -3161,7 +3161,7 @@ suite('Connection', function() { parent.getInput('INPUT').connection .connect(oldChild.outputConnection); newChild.getInput('INPUT').connection.setShadowDom( - Blockly.Xml.textToDom('') + Blockly.utils.xml.textToDom('') .firstChild); parent.getInput('INPUT').connection @@ -3268,7 +3268,7 @@ suite('Connection', function() { const newChild = this.workspace.newBlock('stack_block'); parent.getInput('NAME').connection .connect(oldChild.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild.nextConnection.setShadowDom(xml); @@ -3293,7 +3293,7 @@ suite('Connection', function() { parent.getInput('NAME').connection .connect(oldChild.previousConnection); newChild1.nextConnection.connect(newChild2.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild2.nextConnection.setShadowDom(xml); @@ -3316,7 +3316,7 @@ suite('Connection', function() { const newChild = this.workspace.newBlock('stack_block_1to2'); parent.getInput('NAME').connection .connect(oldChild.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild.nextConnection.setShadowDom(xml); @@ -3409,7 +3409,7 @@ suite('Connection', function() { const oldChild = this.workspace.newBlock('stack_block'); const newChild = this.workspace.newBlock('stack_block'); parent.nextConnection.connect(oldChild.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild.nextConnection.setShadowDom(xml); @@ -3430,7 +3430,7 @@ suite('Connection', function() { const newChild2 = this.workspace.newBlock('stack_block_2to1'); parent.nextConnection.connect(oldChild.previousConnection); newChild1.nextConnection.connect(newChild2.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild2.nextConnection.setShadowDom(xml); @@ -3449,7 +3449,7 @@ suite('Connection', function() { const oldChild = this.workspace.newBlock('stack_block'); const newChild = this.workspace.newBlock('stack_block_1to2'); parent.nextConnection.connect(oldChild.previousConnection); - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' ); newChild.nextConnection.setShadowDom(xml); diff --git a/tests/mocha/event_block_change_test.js b/tests/mocha/event_block_change_test.js index 6b6ff89b1..a431e070c 100644 --- a/tests/mocha/event_block_change_test.js +++ b/tests/mocha/event_block_change_test.js @@ -35,7 +35,7 @@ suite('Block Change Event', function() { test('Undo', function() { const block = this.workspace.newBlock('xml_block', 'block_id'); block.domToMutation( - Blockly.Xml.textToDom('')); + Blockly.utils.xml.textToDom('')); const blockChange = new Blockly.Events.BlockChange( block, 'mutation', null, '', ''); blockChange.run(false); @@ -85,7 +85,7 @@ suite('Block Change Event', function() { test('events round-trip through JSON', function() { const block = this.workspace.newBlock('xml_block', 'block_id'); block.domToMutation( - Blockly.Xml.textToDom('')); + Blockly.utils.xml.textToDom('')); const origEvent = new Blockly.Events.BlockChange( block, 'mutation', null, '', ''); diff --git a/tests/mocha/event_block_delete_test.js b/tests/mocha/event_block_delete_test.js index e5aed21c5..0a9c9c894 100644 --- a/tests/mocha/event_block_delete_test.js +++ b/tests/mocha/event_block_delete_test.js @@ -6,13 +6,12 @@ goog.declareModuleId('Blockly.test.eventBlockDelete'); -import * as eventUtils from '../../build/src/core/events/utils.js'; import {defineRowBlock} from './test_helpers/block_definitions.js'; import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; suite('Block Delete Event', function() { setup(function() { - sharedTestSetup.call(this); + this.clock = sharedTestSetup.call(this, {fireEventsNow: false}).clock; defineRowBlock(); this.workspace = new Blockly.Workspace(); }); @@ -21,6 +20,23 @@ suite('Block Delete Event', function() { sharedTestTeardown.call(this); }); + suite('Receiving', function() { + test('blocks do not receive their own delete events', function() { + Blockly.Blocks['test'] = { + onchange: function(e) { }, + }; + // Need to stub the definition, because the property on the definition is + // what gets registered as an event listener. + const spy = sinon.spy(Blockly.Blocks['test'], 'onchange'); + const testBlock = this.workspace.newBlock('test'); + + testBlock.dispose(); + this.clock.runAll(); + + chai.assert.isFalse(spy.called); + }); + }); + suite('Serialization', function() { test('events round-trip through JSON', function() { const block = this.workspace.newBlock('row_block', 'block_id'); diff --git a/tests/mocha/event_marker_move_test.js b/tests/mocha/event_marker_move_test.js index e7ddac2f8..f44ca330a 100644 --- a/tests/mocha/event_marker_move_test.js +++ b/tests/mocha/event_marker_move_test.js @@ -7,7 +7,7 @@ goog.declareModuleId('Blockly.test.eventMarkerMove'); -import {defineRowBlock} from './test_helpers/block_definitions.js;'; +import {defineRowBlock} from './test_helpers/block_definitions.js'; import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; @@ -22,7 +22,7 @@ suite('Marker Move Event', function() { sharedTestTeardown.call(this); }); - suite.only('Serialization', function() { + suite('Serialization', function() { test('events round-trip through JSON', function() { const block1 = this.workspace.newBlock('row_block', 'test_id1'); const block2 = this.workspace.newBlock('row_block', 'test_id2'); diff --git a/tests/mocha/event_procedure_change_return_test.js b/tests/mocha/event_procedure_change_return_test.js deleted file mode 100644 index 5ec80cdda..000000000 --- a/tests/mocha/event_procedure_change_return_test.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureChangeReturn'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Change Return Event', function() { - const DEFAULT_TYPES = null; - const NON_DEFAULT_TYPES = []; - - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', id); - }; - - this.createEventToState = (procedureModel) => { - const event = new Blockly.Events.ProcedureChangeReturn( - this.workspace, - procedureModel, - procedureModel.getReturnTypes() === DEFAULT_TYPES ? - NON_DEFAULT_TYPES : - DEFAULT_TYPES); - return event; - }; - }); - - suite('forward (redo)', function() { - test('the procedure with the matching ID has its return set', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - - chai.assert.equal( - initial.getReturnTypes(), - final.getReturnTypes(), - "Expected the procedure's return type to be toggled"); - }); - - test('changing the return fires a change return event', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - { - model: initial, - oldTypes: DEFAULT_TYPES, - }, - this.workspace.id); - }); - - test('noop return changes do not fire change return events', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - {}, - this.workspace.id); - }); - - test( - 'attempting to change the return of a procedure that ' + - 'does not exist in the map throws', - function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - - chai.assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - }); - - suite('backward (undo)', function() { - test('the procedure with the matching ID has its return set', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - - chai.assert.equal( - initial.getReturnTypes(), - DEFAULT_TYPES, - "Expected the procedure's return type to be toggled"); - }); - - test('changing the return fires a change return event', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - { - model: initial, - oldTypes: NON_DEFAULT_TYPES, - }, - this.workspace.id); - }); - - test('noop return changes do not fire change return events', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - {}, - this.workspace.id); - }); - - test( - 'attempting to change the return of a procedure that ' + - 'does not exist throws', - function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - - chai.assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const model = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureChangeReturn( - this.workspace, model, NON_DEFAULT_TYPES); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_create_test.js b/tests/mocha/event_procedure_create_test.js deleted file mode 100644 index 1432ae3bc..000000000 --- a/tests/mocha/event_procedure_create_test.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureCreate'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Create Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (name, id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, name, id); - }; - - this.createEventToState = (procedureModel) => { - return new Blockly.Events.ProcedureCreate(this.workspace, procedureModel); - }; - }); - - suite('forward', function() { - test('a procedure model is created if it does not exist', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - event.run(/* forward= */ true); - - const createdProc = this.procedureMap.get('test id'); - chai.assert.isDefined(createdProc, 'Expected the procedure to exist'); - chai.assert.equal( - createdProc.getName(), - model.getName(), - "Expected the procedure's name to match the model"); - chai.assert.equal( - createdProc.getId(), - model.getId(), - "Expected the procedure's id to match the model"); - }); - - test('creating a procedure model fires a create event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {model: this.procedureMap.get('test id')}, - this.workspace.id); - }); - - test( - 'a procedure model is not created if a model with a ' + - 'matching ID exists', - function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ true); - - chai.assert.equal( - this.procedureMap.get('test id'), - model, - 'Expected the model in the procedure map to be the same ' + - 'as the original model'); - }); - - test('not creating a model does not fire a create event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {}, - this.workspace.id); - }); - }); - - suite('backward', function() { - test( - 'a procedure model is deleted if a model with a matching ID exists', - function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ false); - - chai.assert.isUndefined( - this.procedureMap.get('test id'), - 'Expected the procedure to be deleted'); - }); - - test('deleting a model fires a delete event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model}, - this.workspace.id); - }); - - test('not deleting a model does not fire a delete event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {}, - this.workspace.id); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const model = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - const origEvent = new Blockly.Events.ProcedureCreate(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_delete_test.js b/tests/mocha/event_procedure_delete_test.js deleted file mode 100644 index aa45b3e7f..000000000 --- a/tests/mocha/event_procedure_delete_test.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureDelete'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Delete Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (name, id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, name, id); - }; - - this.createEventToState = (procedureModel) => { - return new Blockly.Events.ProcedureDelete(this.workspace, procedureModel); - }; - }); - - suite('forward', function() { - test( - 'a procedure model is deleted if a model with a matching ID exists', - function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ true); - - chai.assert.isUndefined( - this.procedureMap.get('test id'), - 'Expected the procedure to be deleted'); - }); - - test('deleting a model fires a delete event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model}, - this.workspace.id); - }); - - test('not deleting a model does not fire a delete event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {}, - this.workspace.id); - }); - }); - - suite('backward', function() { - test('a procedure model is created if it does not exist', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - event.run(/* forward= */ false); - - const createdProc = this.procedureMap.get('test id'); - chai.assert.isDefined(createdProc, 'Expected the procedure to exist'); - chai.assert.equal( - createdProc.getName(), - model.getName(), - "Expected the procedure's name to match the model"); - chai.assert.equal( - createdProc.getId(), - model.getId(), - "Expected the procedure's id to match the model"); - }); - - test('creating a procedure model fires a create event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {model: this.procedureMap.get('test id')}, - this.workspace.id); - }); - - test( - 'a procedure model is not created if a model with a ' + - 'matching ID exists', - function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ false); - - chai.assert.equal( - this.procedureMap.get('test id'), - model, - 'Expected the model in the procedure map to be the same ' + - 'as the original model'); - }); - - test('not creating a model does not fire a create event', function() { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {}, - this.workspace.id); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const model = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureDelete(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_enable_test.js b/tests/mocha/event_procedure_enable_test.js deleted file mode 100644 index 8e34565c8..000000000 --- a/tests/mocha/event_procedure_enable_test.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureEnable'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Enable Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', id); - }; - - this.createEventToState = (procedureModel) => { - return new Blockly.Events.ProcedureEnable(this.workspace, procedureModel); - }; - }); - - suite('forward', function() { - test('the procedure with the matching ID is toggled', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - - chai.assert.equal( - initial.getEnabled(), - final.getEnabled(), - "Expected the procedure's enabled state to be flipped"); - }); - - test('toggling a procedure fires an enable event', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {model: initial}, - this.workspace.id); - }); - - test('noop toggles do not fire enable events', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureEnable, - this.workspace.id); - }); - - test( - 'attempting to toggle a procedure that does not exist throws', - function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - - chai.assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - }); - - suite('backward', function() { - test('the procedure with the matching ID is toggled', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - - chai.assert.equal( - initial.getEnabled(), - defaultEnabled, - "Expected the procedure's enabled state to be flipped"); - }); - - test('toggling a procedure fires an enable event', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {model: initial}, - this.workspace.id); - }); - - test('noop toggles do not fire enable events', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {}, - this.workspace.id); - }); - - test( - 'attempting to toggle a procedure that does not exist throws', - function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - - chai.assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const model = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureEnable(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_parameter_create_test.js b/tests/mocha/event_procedure_parameter_create_test.js deleted file mode 100644 index 2be5c7dcb..000000000 --- a/tests/mocha/event_procedure_parameter_create_test.js +++ /dev/null @@ -1,217 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureParameterCreate'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Parameter Create Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (name, id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, name, id); - }; - - this.createProcedureAndParameter = - (procName, procId, paramName, paramId) => { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, paramName, paramId); - const proc = new Blockly.procedures.ObservableProcedureModel( - this.workspace, procName, procId) - .insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new Blockly.Events.ProcedureParameterCreate( - this.workspace, procedureModel, parameterModel, 0); - }; - }); - - suite('forward', function() { - test('a parameter is inserted if it does not exist', function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - event.run(/* forward= */ true); - - const createdParam = actualProc.getParameter(0); - chai.assert.isDefined(createdParam, 'Expected the parameter to exist'); - chai.assert.equal( - createdParam.getName(), - modelParam.getName(), - "Expected the parameter's name to match the model"); - chai.assert.equal( - createdParam.getId(), - modelParam.getId(), - "Expected the parameter's id to match the model"); - }); - - test('inserting a parameter fires a create event', function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - { - model: actualProc, - parameter: actualProc.getParameter(0), - index: 0, - }, - this.workspace.id); - }); - - test( - 'a parameter is not created if a parameter with a ' + - 'matching ID and index already exists', - function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - const actualProc = this.procedureMap.get('test id'); - chai.assert.equal( - actualProc, - modelProc, - 'Expected the procedure in the procedure map to not have changed'); - chai.assert.equal( - actualProc.getParameter(0), - modelParam, - 'Expected the parameter to not have changed'); - }); - - test( - 'not creating a parameter model does not fire a create event', - function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - {}, - this.workspace.id); - }); - }); - - suite('backward', function() { - test('a parameter is removed if it exists', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - event.run(/* forward= */ false); - - chai.assert.isUndefined( - proc.getParameter(0), - 'Expected the parameter to be deleted'); - }); - - test('removing a parameter fires a delete event', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - { - model: proc, - parameter: param, - index: 0, - }, - this.workspace.id); - }); - - test( - 'a parameter is not deleted if a parameter with a ' + - 'matching ID and index does not exist', - function() { - // TODO: Figure out what we want to do in this case. - }); - - test('not removing a parameter does not fire a delete event', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - proc.deleteParameter(0); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - {}, - this.workspace.id); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test param name', 'test param id'); - const model = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureParameterCreate( - this.workspace, model, param, 0); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_parameter_delete_test.js b/tests/mocha/event_procedure_parameter_delete_test.js deleted file mode 100644 index e98850dfc..000000000 --- a/tests/mocha/event_procedure_parameter_delete_test.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureParameterDelete'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Parameter Delete Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (name, id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, name, id); - }; - - this.createProcedureAndParameter = - (procName, procId, paramName, paramId) => { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, procName, paramId); - const proc = new Blockly.procedures.ObservableProcedureModel( - this.workspace, paramName, procId) - .insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new Blockly.Events.ProcedureParameterDelete( - this.workspace, procedureModel, parameterModel, 0); - }; - }); - - suite('forward', function() { - test('a parameter is removed if it exists', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - event.run(/* forward= */ true); - - chai.assert.isUndefined( - proc.getParameter(0), - 'Expected the parameter to be deleted'); - }); - - test('removing a parameter fires a delete event', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - { - model: proc, - parameter: param, - index: 0, - }, - this.workspace.id); - }); - - test( - 'a parameter is not deleted if a parameter with a ' + - 'matching ID and index does not exist', - function() { - // TODO: Figure out what we want to do in this case. - }); - - test('not removing a parameter does not fire a delete event', function() { - const {param, proc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - proc.deleteParameter(0); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - {}, - this.workspace.id); - }); - }); - - suite('backward', function() { - test('a parameter is inserted if it does not exist', function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - event.run(/* forward= */ false); - - const createdParam = actualProc.getParameter(0); - chai.assert.isDefined(createdParam, 'Expected the parameter to exist'); - chai.assert.equal( - createdParam.getName(), - modelParam.getName(), - "Expected the parameter's name to match the model"); - chai.assert.equal( - createdParam.getId(), - modelParam.getId(), - "Expected the parameter's id to match the model"); - }); - - test('inserting a parameter fires a create event', function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - { - model: actualProc, - parameter: actualProc.getParameter(0), - index: 0, - }, - this.workspace.id); - }); - - test( - 'a parameter is not created if a parameter with a ' + - 'matching ID and index already exists', - function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - const actualProc = this.procedureMap.get('test id'); - chai.assert.equal( - actualProc, - modelProc, - 'Expected the procedure in the procedure map to not have changed'); - chai.assert.equal( - actualProc.getParameter(0), - modelParam, - 'Expected the parameter to not have changed'); - }); - - test( - 'not creating a parameter model does not fire a create event', - function() { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', 'test id', 'test param name', 'test param id'); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - {}, - this.workspace.id); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test param name', 'test param id'); - const model = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id') - .insertParameter(param, 0); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureParameterDelete( - this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_parameter_rename_test.js b/tests/mocha/event_procedure_parameter_rename_test.js deleted file mode 100644 index c88da7fb9..000000000 --- a/tests/mocha/event_procedure_parameter_rename_test.js +++ /dev/null @@ -1,225 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureParameterRename'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Parameter Rename Event', function() { - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - const DEFAULT_NAME = 'default'; - const NON_DEFAULT_NAME = 'non-default'; - - setup(function() { - this.createProcedureAndParameter = (procId, paramId) => { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, DEFAULT_NAME, paramId); - const proc = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', procId) - .insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new Blockly.Events.ProcedureParameterRename( - this.workspace, - procedureModel, - parameterModel, - parameterModel.getName() === DEFAULT_NAME ? - NON_DEFAULT_NAME : - DEFAULT_NAME); - }; - }); - - suite('forward', function() { - test('the parameter with the matching ID and index is renamed', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - event.run(/* forward= */ true); - - chai.assert.equal( - initialParam.getName(), - finalParam.getName(), - "Expected the procedure parameter's name to be changed"); - }); - - test('renaming a parameter fires a rename event', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - { - model: initialProc, - parameter: initialParam, - oldName: DEFAULT_NAME, - }, - this.workspace.id); - }); - - test('noop renames do not fire rename events', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - {}, - this.workspace.id); - }); - - test( - 'attempting to rename a parameter that does not exist throws', - function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - - chai.assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - }); - - suite('backward', function() { - test('the parameter with the matching ID and index is renamed', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - chai.assert.equal( - initialParam.getName(), - DEFAULT_NAME, - "Expected the procedure parameter's name to be changed"); - }); - - test('renaming a parameter fires a rename event', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - { - model: initialProc, - parameter: initialParam, - oldName: NON_DEFAULT_NAME, - }, - this.workspace.id); - }); - - test('noop renames do not fire rename events', function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - - event.run(/* forward= */ false); - - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - {}, - this.workspace.id); - }); - - test( - 'attempting to rename a parameter that does not exist throws', - function() { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - - chai.assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test param name', 'test param id'); - const model = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id') - .insertParameter(param, 0); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureParameterDelete( - this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_procedure_rename_test.js b/tests/mocha/event_procedure_rename_test.js deleted file mode 100644 index 9514cb443..000000000 --- a/tests/mocha/event_procedure_rename_test.js +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.eventProcedureRename'); - -import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; -import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; - - -suite('Procedure Rename Event', function() { - const DEFAULT_NAME = 'default'; - const NON_DEFAULT_NAME = 'non-default'; - - setup(function() { - sharedTestSetup.call(this); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - sharedTestTeardown.call(this); - }); - - suite('running', function() { - setup(function() { - this.createProcedureModel = (id) => { - return new Blockly.procedures.ObservableProcedureModel( - this.workspace, DEFAULT_NAME, id); - }; - - this.createEventToState = (procedureModel) => { - return new Blockly.Events.ProcedureRename( - this.workspace, - procedureModel, - procedureModel.getName() === DEFAULT_NAME ? - NON_DEFAULT_NAME : - DEFAULT_NAME); - }; - }); - - suite('forward', function() { - test('the procedure with the matching ID is renamed', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - - chai.assert.equal( - initial.getName(), - final.getName(), - "Expected the procedure's name to be changed"); - }); - - test('renaming a procedure fires a rename event', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureRename, - {model: initial, oldName: DEFAULT_NAME}, - this.workspace.id); - }); - - test('noop renames do not fire rename events', function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureRename, - {}, - this.workspace.id); - }); - - test( - 'attempting to rename a procedure that does not exist throws', - function() { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - - chai.assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - }); - - suite('backward', function() { - test('the procedure with the matching ID is renamed', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - - chai.assert.equal( - initial.getName(), - DEFAULT_NAME, - "Expected the procedure's name to be changed"); - }); - - test('renaming a procedure fires a rename event', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureRename, - {model: initial, oldName: NON_DEFAULT_NAME}, - this.workspace.id); - }); - - test('noop renames do not fire rename events', function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureRename, - {}, - this.workspace.id); - }); - - test( - 'attempting to rename a procedure that does not exist throws', - function() { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - - chai.assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - }); - }); - - suite('serialization', function() { - test('events round-trip through JSON', function() { - const model = new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name', 'test id'); - this.procedureMap.add(model); - const origEvent = new Blockly.Events.ProcedureRename( - this.workspace, model, NON_DEFAULT_NAME); - - const json = origEvent.toJson(); - const newEvent = new Blockly.Events.fromJson(json, this.workspace); - - chai.assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/tests/mocha/event_selected_test.js b/tests/mocha/event_selected_test.js index 726aba93a..f7be3745d 100644 --- a/tests/mocha/event_selected_test.js +++ b/tests/mocha/event_selected_test.js @@ -7,7 +7,7 @@ goog.declareModuleId('Blockly.test.eventSelected'); -import {defineRowBlock} from './test_helpers/block_definitions.js;'; +import {defineRowBlock} from './test_helpers/block_definitions.js'; import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; @@ -22,7 +22,7 @@ suite('Selected Event', function() { sharedTestTeardown.call(this); }); - suite.only('Serialization', function() { + suite('Serialization', function() { test('events round-trip through JSON', function() { const block1 = this.workspace.newBlock('row_block', 'test_id1'); const block2 = this.workspace.newBlock('row_block', 'test_id2'); diff --git a/tests/mocha/event_test.js b/tests/mocha/event_test.js index b0a5df63c..b6780c6f0 100644 --- a/tests/mocha/event_test.js +++ b/tests/mocha/event_test.js @@ -1047,7 +1047,7 @@ suite('Events', function() { test('New block new var xml', function() { const TEST_GROUP_ID = 'test_group_id'; const genUidStub = createGenUidStubWithReturns(TEST_GROUP_ID); - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' name1' + diff --git a/tests/mocha/event_var_create_test.js b/tests/mocha/event_var_create_test.js index b90372e8f..dbcd7a4ab 100644 --- a/tests/mocha/event_var_create_test.js +++ b/tests/mocha/event_var_create_test.js @@ -21,7 +21,18 @@ suite('Var Create Event', function() { }); suite('Serialization', function() { - test('events round-trip through JSON', function() { + test('untyped variable events round-trip through JSON', function() { + const varModel = + new Blockly.VariableModel(this.workspace, 'name', '', 'id'); + const origEvent = new Blockly.Events.VarCreate(varModel); + + const json = origEvent.toJson(); + const newEvent = new Blockly.Events.fromJson(json, this.workspace); + + chai.assert.deepEqual(newEvent, origEvent); + }); + + test('typed variable events round-trip through JSON', function() { const varModel = new Blockly.VariableModel(this.workspace, 'name', 'type', 'id'); const origEvent = new Blockly.Events.VarCreate(varModel); diff --git a/tests/mocha/event_var_delete_test.js b/tests/mocha/event_var_delete_test.js index f086873d3..ef532c2d2 100644 --- a/tests/mocha/event_var_delete_test.js +++ b/tests/mocha/event_var_delete_test.js @@ -20,7 +20,18 @@ suite('Var Delete Event', function() { }); suite('Serialization', function() { - test('events round-trip through JSON', function() { + test('untyped variable events round-trip through JSON', function() { + const varModel = + new Blockly.VariableModel(this.workspace, 'name', '', 'id'); + const origEvent = new Blockly.Events.VarDelete(varModel); + + const json = origEvent.toJson(); + const newEvent = new Blockly.Events.fromJson(json, this.workspace); + + chai.assert.deepEqual(newEvent, origEvent); + }); + + test('typed variable events round-trip through JSON', function() { const varModel = new Blockly.VariableModel(this.workspace, 'name', 'type', 'id'); const origEvent = new Blockly.Events.VarDelete(varModel); diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index d23acd80e..8cdff6de8 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -126,7 +126,7 @@ suite('Angle Fields', function() { function() { return null; }, - value: 2, expectedValue: 1}, + value: 2, expectedValue: '1'}, {title: 'Force Mult of 30 Validator', validator: function(newValue) { @@ -150,7 +150,7 @@ suite('Angle Fields', function() { }); test('When Not Editing', function() { this.field.setValue(suiteInfo.value); - assertFieldValue(this.field, suiteInfo.expectedValue); + assertFieldValue(this.field, +suiteInfo.expectedValue); }); }); }); @@ -161,14 +161,14 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { clockwise: true, }); - chai.assert.isTrue(field.clockwise_); + chai.assert.isTrue(field.clockwise); }); test('JSON Definition', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, clockwise: true, }); - chai.assert.isTrue(field.clockwise_); + chai.assert.isTrue(field.clockwise); }); test('Constant', function() { // Note: Generally constants should be set at compile time, not @@ -176,7 +176,7 @@ suite('Angle Fields', function() { // can do this. Blockly.FieldAngle.CLOCKWISE = true; const field = new Blockly.FieldAngle(); - chai.assert.isTrue(field.clockwise_); + chai.assert.isTrue(field.clockwise); }); }); suite('Offset', function() { @@ -184,14 +184,14 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { offset: 90, }); - chai.assert.equal(field.offset_, 90); + chai.assert.equal(field.offset, 90); }); test('JSON Definition', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, offset: 90, }); - chai.assert.equal(field.offset_, 90); + chai.assert.equal(field.offset, 90); }); test('Constant', function() { // Note: Generally constants should be set at compile time, not @@ -199,7 +199,7 @@ suite('Angle Fields', function() { // can do this. Blockly.FieldAngle.OFFSET = 90; const field = new Blockly.FieldAngle(); - chai.assert.equal(field.offset_, 90); + chai.assert.equal(field.offset, 90); }); test('Null', function() { // Note: Generally constants should be set at compile time, not @@ -210,7 +210,7 @@ suite('Angle Fields', function() { value: 0, offset: null, }); - chai.assert.equal(field.offset_, 90); + chai.assert.equal(field.offset, 90); }); }); suite('Wrap', function() { @@ -218,14 +218,14 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { wrap: 180, }); - chai.assert.equal(field.wrap_, 180); + chai.assert.equal(field.wrap, 180); }); test('JSON Definition', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, wrap: 180, }); - chai.assert.equal(field.wrap_, 180); + chai.assert.equal(field.wrap, 180); }); test('Constant', function() { // Note: Generally constants should be set at compile time, not @@ -233,7 +233,7 @@ suite('Angle Fields', function() { // can do this. Blockly.FieldAngle.WRAP = 180; const field = new Blockly.FieldAngle(); - chai.assert.equal(field.wrap_, 180); + chai.assert.equal(field.wrap, 180); }); test('Null', function() { // Note: Generally constants should be set at compile time, not @@ -244,7 +244,7 @@ suite('Angle Fields', function() { value: 0, wrap: null, }); - chai.assert.equal(field.wrap_, 180); + chai.assert.equal(field.wrap, 180); }); }); suite('Round', function() { @@ -252,14 +252,14 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { round: 30, }); - chai.assert.equal(field.round_, 30); + chai.assert.equal(field.round, 30); }); test('JSON Definition', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, round: 30, }); - chai.assert.equal(field.round_, 30); + chai.assert.equal(field.round, 30); }); test('Constant', function() { // Note: Generally constants should be set at compile time, not @@ -267,7 +267,7 @@ suite('Angle Fields', function() { // can do this. Blockly.FieldAngle.ROUND = 30; const field = new Blockly.FieldAngle(); - chai.assert.equal(field.round_, 30); + chai.assert.equal(field.round, 30); }); test('Null', function() { // Note: Generally constants should be set at compile time, not @@ -278,7 +278,7 @@ suite('Angle Fields', function() { value: 0, round: null, }); - chai.assert.equal(field.round_, 30); + chai.assert.equal(field.round, 30); }); }); suite('Mode', function() { @@ -287,16 +287,16 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { mode: 'compass', }); - chai.assert.equal(field.offset_, 90); - chai.assert.isTrue(field.clockwise_); + chai.assert.equal(field.offset, 90); + chai.assert.isTrue(field.clockwise); }); test('JS Configuration', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, mode: 'compass', }); - chai.assert.equal(field.offset_, 90); - chai.assert.isTrue(field.clockwise_); + chai.assert.equal(field.offset, 90); + chai.assert.isTrue(field.clockwise); }); }); suite('Protractor', function() { @@ -304,16 +304,16 @@ suite('Angle Fields', function() { const field = new Blockly.FieldAngle(0, null, { mode: 'protractor', }); - chai.assert.equal(field.offset_, 0); - chai.assert.isFalse(field.clockwise_); + chai.assert.equal(field.offset, 0); + chai.assert.isFalse(field.clockwise); }); test('JS Configuration', function() { const field = Blockly.FieldAngle.fromJson({ value: 0, mode: 'protractor', }); - chai.assert.equal(field.offset_, 0); - chai.assert.isFalse(field.clockwise_); + chai.assert.equal(field.offset, 0); + chai.assert.isFalse(field.clockwise); }); }); }); diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js index 771ce6627..2e491c855 100644 --- a/tests/mocha/field_checkbox_test.js +++ b/tests/mocha/field_checkbox_test.js @@ -152,7 +152,7 @@ suite('Checkbox Fields', function() { workspace: { keyboardAccessibilityMode: false, }, - render: function() {field.render_();}, + queueRender: function() {field.render_();}, bumpNeighbours: function() {}, }; field.constants_ = { diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js index 65d4a9d2c..f1a37d9e3 100644 --- a/tests/mocha/field_colour_test.js +++ b/tests/mocha/field_colour_test.js @@ -173,9 +173,9 @@ suite('Colour Fields', function() { suite('Customizations', function() { suite('Colours and Titles', function() { function assertColoursAndTitles(field, colours, titles) { - field.dropdownCreate_(); + field.dropdownCreate(); let index = 0; - let node = field.picker_.firstChild.firstChild; + let node = field.picker.firstChild.firstChild; while (node) { chai.assert.equal(node.getAttribute('title'), titles[index]); chai.assert.equal( @@ -251,8 +251,8 @@ suite('Colour Fields', function() { }); suite('Columns', function() { function assertColumns(field, columns) { - field.dropdownCreate_(); - chai.assert.equal(field.picker_.firstChild.children.length, columns); + field.dropdownCreate(); + chai.assert.equal(field.picker.firstChild.children.length, columns); } test('Constants', function() { const columns = Blockly.FieldColour.COLUMNS; diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index 23b112c81..93ece7a1c 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -202,11 +202,11 @@ suite('Number Fields', function() { function() { return null; }, - value: 2, expectedValue: 1}, + value: 2, expectedValue: '1'}, {title: 'Force End with 6 Validator', validator: function(newValue) { - return String(newValue).replace(/.$/, '6'); + return +String(newValue).replace(/.$/, '6'); }, value: 25, expectedValue: 26}, {title: 'Returns Undefined Validator', validator: function() {}, value: 2, @@ -226,7 +226,7 @@ suite('Number Fields', function() { }); test('When Not Editing', function() { this.field.setValue(suiteInfo.value); - assertFieldValue(this.field, suiteInfo.expectedValue); + assertFieldValue(this.field, +suiteInfo.expectedValue); }); }); }); diff --git a/tests/mocha/field_test.js b/tests/mocha/field_test.js index fcd124ed2..ca1974087 100644 --- a/tests/mocha/field_test.js +++ b/tests/mocha/field_test.js @@ -315,21 +315,21 @@ suite('Abstract Fields', function() { test('No implementations', function() { const field = new DefaultSerializationField(''); field.fromXml( - Blockly.Xml.textToDom('test value')); + Blockly.utils.xml.textToDom('test value')); chai.assert.equal(field.getValue(), 'test value'); }); test('Xml implementations', function() { const field = new CustomXmlField(''); field.fromXml( - Blockly.Xml.textToDom('custom value')); + Blockly.utils.xml.textToDom('custom value')); chai.assert.equal(field.someProperty, 'custom value'); }); test('Xml super implementation', function() { const field = new CustomXmlCallSuperField(''); field.fromXml( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( 'test value' ) ); @@ -340,7 +340,7 @@ suite('Abstract Fields', function() { test('XML andd JSO implementations', function() { const field = new CustomXmlAndJsoField(''); field.fromXml( - Blockly.Xml.textToDom('custom value')); + Blockly.utils.xml.textToDom('custom value')); chai.assert.equal(field.someProperty, 'custom value'); }); }); @@ -666,7 +666,7 @@ suite('Abstract Fields', function() { .appendField(field, 'TOOLTIP'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -684,7 +684,7 @@ suite('Abstract Fields', function() { field.setTooltip('tooltip'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -701,7 +701,7 @@ suite('Abstract Fields', function() { .appendField(field, 'TOOLTIP'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -724,7 +724,7 @@ suite('Abstract Fields', function() { return this.getFieldValue('TOOLTIP'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -745,7 +745,7 @@ suite('Abstract Fields', function() { tooltip: 'tooltip', }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -763,7 +763,7 @@ suite('Abstract Fields', function() { .appendField(field, 'TOOLTIP'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -780,7 +780,7 @@ suite('Abstract Fields', function() { .appendField(field, 'TOOLTIP'); }, }; - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' diff --git a/tests/mocha/flyout_test.js b/tests/mocha/flyout_test.js index 40c584281..cf5e17390 100644 --- a/tests/mocha/flyout_test.js +++ b/tests/mocha/flyout_test.js @@ -360,7 +360,7 @@ suite('Flyout', function() { suite('XML', function() { test('True string', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + '' + '' @@ -370,7 +370,7 @@ suite('Flyout', function() { }); test('False string', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + '' + '' @@ -381,7 +381,7 @@ suite('Flyout', function() { test('Disabled string', function() { // The XML system supports this for some reason!? - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + '' + '' @@ -391,7 +391,7 @@ suite('Flyout', function() { }); test('Different string', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + '' + '' diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 7dcc92e42..d1359e907 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -73,14 +73,6 @@ 'Blockly.test.eventCommentDelete', 'Blockly.test.eventCommentMove', 'Blockly.test.eventMarkerMove', - 'Blockly.test.eventProcedureCreate', - 'Blockly.test.eventProcedureDelete', - 'Blockly.test.eventProcedureRename', - 'Blockly.test.eventProcedureEnable', - 'Blockly.test.eventProcedureChangeReturn', - 'Blockly.test.eventProcedureParameterCreate', - 'Blockly.test.eventProcedureParameterDelete', - 'Blockly.test.eventProcedureParameterRename', 'Blockly.test.eventSelected', 'Blockly.test.eventThemeChange', 'Blockly.test.eventToolboxItemSelect', diff --git a/tests/mocha/input_test.js b/tests/mocha/input_test.js index eb82738b1..6016a8f53 100644 --- a/tests/mocha/input_test.js +++ b/tests/mocha/input_test.js @@ -19,11 +19,11 @@ suite('Inputs', function() { }]); this.workspace = Blockly.inject('blocklyDiv'); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); - this.renderStub = sinon.stub(this.block, 'render'); + this.renderStub = sinon.stub(this.block, 'queueRender'); this.bumpNeighboursStub = sinon.stub(this.block, 'bumpNeighbours'); this.dummy = this.block.appendDummyInput('DUMMY'); diff --git a/tests/mocha/insertion_marker_test.js b/tests/mocha/insertion_marker_test.js index c03fbafa3..6bd4594e3 100644 --- a/tests/mocha/insertion_marker_test.js +++ b/tests/mocha/insertion_marker_test.js @@ -77,7 +77,7 @@ suite('InsertionMarkers', function() { delete javascriptGenerator['statement_block']; }); test('Marker Surrounds', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -88,7 +88,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'statement[a]{\n};\n'); }); test('Marker Enclosed', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -99,7 +99,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'statement[a]{\n};\n'); }); test('Marker Enclosed and Surrounds', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -118,7 +118,7 @@ suite('InsertionMarkers', function() { '};\n'); }); test('Marker Prev', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -129,7 +129,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'stack[a];\n'); }); test('Marker Next', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -140,7 +140,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'stack[a];\n'); }); test('Marker Middle of Stack', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -157,7 +157,7 @@ suite('InsertionMarkers', function() { 'stack[b];\n'); }); test('Marker On Output', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -168,7 +168,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'row[a]();\n'); }); test('Marker On Input', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -179,7 +179,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'row[a]();\n'); }); test('Marker Middle of Row', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -194,7 +194,7 @@ suite('InsertionMarkers', function() { this.assertGen(xml, 'row[a](row[b]());\n'); }); test('Marker Detatched', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -215,7 +215,7 @@ suite('InsertionMarkers', function() { }; }); test('Marker Surrounds', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -231,7 +231,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Enclosed', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -245,7 +245,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Enclosed and Surrounds', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -267,7 +267,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Prev', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -283,7 +283,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Next', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -297,7 +297,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Middle of Stack', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -319,7 +319,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker On Output', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -335,7 +335,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker On Input', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -349,7 +349,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Middle of Row', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -371,7 +371,7 @@ suite('InsertionMarkers', function() { ''); }); test('Marker Detatched', function() { - const xml = Blockly.Xml.textToDom( + const xml = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + diff --git a/tests/mocha/jso_serialization_test.js b/tests/mocha/jso_serialization_test.js index 10d15560b..32e4f63e6 100644 --- a/tests/mocha/jso_serialization_test.js +++ b/tests/mocha/jso_serialization_test.js @@ -9,6 +9,7 @@ goog.declareModuleId('Blockly.test.jsoSerialization'); import * as Blockly from '../../build/src/core/blockly.js'; import {createGenUidStubWithReturns, sharedTestSetup, sharedTestTeardown, workspaceTeardown} from './test_helpers/setup_teardown.js'; import {defineRowBlock, defineStackBlock, defineStatementBlock} from './test_helpers/block_definitions.js'; +import {MockParameterModel, MockProcedureModel} from './test_helpers/procedures.js'; suite('JSO Serialization', function() { @@ -373,7 +374,7 @@ suite('JSO Serialization', function() { this.createBlockWithShadow = function(blockType, inputName) { const block = this.workspace.newBlock(blockType); block.getInput(inputName).connection.setShadowDom( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '')); return block; }; @@ -384,7 +385,7 @@ suite('JSO Serialization', function() { block.getInput(inputName).connection.connect( childBlock.outputConnection || childBlock.previousConnection); block.getInput(inputName).connection.setShadowDom( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '')); return block; }; @@ -600,7 +601,7 @@ suite('JSO Serialization', function() { this.createNextWithShadow = function() { const block = this.workspace.newBlock('stack_block'); block.nextConnection.setShadowDom( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '')); return block; }; @@ -610,7 +611,7 @@ suite('JSO Serialization', function() { const childBlock = this.workspace.newBlock('stack_block'); block.nextConnection.connect(childBlock.previousConnection); block.nextConnection.setShadowDom( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '')); return block; }; @@ -795,126 +796,41 @@ suite('JSO Serialization', function() { }); }); - suite.skip('Procedures', function() { - class MockProcedureModel { - constructor() { - this.id = Blockly.utils.idGenerator.genUid(); - this.name = ''; - this.parameters = []; - this.returnTypes = null; - this.enabled = true; - } - - setName(name) { - this.name = name; - return this; - } - - insertParameter(parameterModel, index) { - this.parameters.splice(index, 0, parameterModel); - return this; - } - - deleteParameter(index) { - this.parameters.splice(index, 1); - return this; - } - - setReturnTypes(types) { - this.returnTypes = types; - return this; - } - - setEnabled(enabled) { - this.enabled = enabled; - return this; - } - - getId() { - return this.id; - } - - getName() { - return this.name; - } - - getParameter(index) { - return this.parameters[index]; - } - - getParameters() { - return [...this.parameters]; - } - - getReturnTypes() { - return this.returnTypes; - } - - getEnabled() { - return this.enabled; - } - } - - class MockParameterModel { - constructor(name) { - this.id = Blockly.utils.idGenerator.genUid(); - this.name = name; - this.types = []; - } - - setName(name) { - this.name = name; - return this; - } - - setTypes(types) { - this.types = types; - return this; - } - - getName() { - return this.name; - } - - getTypes() { - return this.types; - } - - getId() { - return this.id; - } - } - + suite('Procedures', function() { setup(function() { this.procedureMap = this.workspace.getProcedureMap(); + this.serializer = + new Blockly.serialization.procedures.ProcedureSerializer( + MockProcedureModel, MockParameterModel); }); teardown(function() { this.procedureMap = null; + this.serializer = null; }); suite('invariant properties', function() { test('the state always has an id property', function() { const procedureModel = new MockProcedureModel(); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'id', procedureModel.getId()); }); test('if the name has not been set, name is an empty string', function() { const procedureModel = new MockProcedureModel(); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'name', ''); }); test('if the name has been set, name is the string', function() { const procedureModel = new MockProcedureModel().setName('testName'); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'name', 'testName'); }); }); @@ -923,8 +839,8 @@ suite('JSO Serialization', function() { test('if the procedure does not return, returnTypes is null', function() { const procedureModel = new MockProcedureModel(); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'returnTypes', null); }); @@ -933,8 +849,8 @@ suite('JSO Serialization', function() { function() { const procedureModel = new MockProcedureModel().setReturnTypes([]); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'returnTypes', []); }); @@ -944,8 +860,8 @@ suite('JSO Serialization', function() { const procedureModel = new MockProcedureModel() .setReturnTypes(['a type']); this.procedureMap.add(procedureModel); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const procedure = jso['procedures'][0]; + const jso = this.serializer.save(this.workspace); + const procedure = jso[0]; assertProperty(procedure, 'returnTypes', ['a type']); }); }); @@ -956,8 +872,8 @@ suite('JSO Serialization', function() { const parameterModel = new MockParameterModel('testparam'); this.procedureMap.add( new MockProcedureModel().insertParameter(parameterModel, 0)); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const parameter = jso['procedures'][0]['parameters'][0]; + const jso = this.serializer.save(this.workspace); + const parameter = jso[0]['parameters'][0]; assertProperty(parameter, 'id', parameterModel.getId()); }); @@ -965,8 +881,8 @@ suite('JSO Serialization', function() { const parameterModel = new MockParameterModel('testparam'); this.procedureMap.add( new MockProcedureModel().insertParameter(parameterModel, 0)); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const parameter = jso['procedures'][0]['parameters'][0]; + const jso = this.serializer.save(this.workspace); + const parameter = jso[0]['parameters'][0]; assertProperty(parameter, 'name', 'testparam'); }); }); @@ -978,8 +894,8 @@ suite('JSO Serialization', function() { const parameterModel = new MockParameterModel('testparam'); this.procedureMap.add( new MockProcedureModel().insertParameter(parameterModel, 0)); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const parameter = jso['procedures'][0]['parameters'][0]; + const jso = this.serializer.save(this.workspace); + const parameter = jso[0]['parameters'][0]; assertNoProperty(parameter, 'types'); }); @@ -988,8 +904,8 @@ suite('JSO Serialization', function() { new MockParameterModel('testparam').setTypes(['a type']); this.procedureMap.add( new MockProcedureModel().insertParameter(parameterModel, 0)); - const jso = Blockly.serialization.workspaces.save(this.workspace); - const parameter = jso['procedures'][0]['parameters'][0]; + const jso = this.serializer.save(this.workspace); + const parameter = jso[0]['parameters'][0]; assertProperty(parameter, 'types', ['a type']); }); }); diff --git a/tests/mocha/procedure_map_test.js b/tests/mocha/procedure_map_test.js index 80e3a37f1..3117cb6a2 100644 --- a/tests/mocha/procedure_map_test.js +++ b/tests/mocha/procedure_map_test.js @@ -6,6 +6,7 @@ import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js'; +import {MockProcedureModel} from './test_helpers/procedures.js'; goog.declareModuleId('Blockly.test.procedureMap'); @@ -20,789 +21,34 @@ suite('Procedure Map', function() { sharedTestTeardown.call(this); }); - suite('triggering block updates', function() { - setup(function() { - Blockly.Blocks['procedure_mock'] = { - init: function() { }, - doProcedureUpdate: function() { }, - }; + suite('publishing', function() { + test('inserting a procedure tells it to start publishing', function() { + const procedureModel = new MockProcedureModel(); + const spy = sinon.spy(procedureModel, 'startPublishing'); + this.procedureMap.set(procedureModel.getId(), procedureModel); - this.procedureBlock = this.workspace.newBlock('procedure_mock'); - - this.updateSpy = sinon.spy(this.procedureBlock, 'doProcedureUpdate'); + chai.assert.isTrue( + spy.called, 'Expected the model to start publishing'); }); - teardown(function() { - delete Blockly.Blocks['procedure_mock']; + test('adding a procedure tells it to start publishing', function() { + const procedureModel = new MockProcedureModel(); + const spy = sinon.spy(procedureModel, 'startPublishing'); + this.procedureMap.add(procedureModel); + + chai.assert.isTrue( + spy.called, 'Expected the model to start publishing'); }); - suite('procedure map updates', function() { - test('inserting a procedure does not trigger an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.set(procedureModel.getId(), procedureModel); + test('deleting a procedure tells it to stop publishing', function() { + const procedureModel = new MockProcedureModel(); + const spy = sinon.spy(procedureModel, 'stopPublishing'); + this.procedureMap.add(procedureModel); - chai.assert.isFalse( - this.updateSpy.called, 'Expected no update to be triggered'); - }); + this.procedureMap.delete(procedureModel.getId()); - test('adding a procedure does not trigger an update', function() { - this.procedureMap.add( - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name')); - - chai.assert.isFalse( - this.updateSpy.called, 'Expected no update to be triggered'); - }); - - test('deleting a procedure triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.add(procedureModel); - - this.procedureMap.delete(procedureModel.getId()); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - }); - - suite('procedure model updates', function() { - test('setting the name triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.add(procedureModel); - - procedureModel.setName('new name'); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('setting the return type triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.add(procedureModel); - - procedureModel.setReturnTypes([]); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('removing the return type triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name') - .setReturnTypes([]); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.setReturnTypes(null); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('disabling the procedure triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.add(procedureModel); - - procedureModel.setEnabled(false); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('enabling the procedure triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name') - .setEnabled(false); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.setEnabled(true); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('inserting a parameter triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name'); - this.procedureMap.add(procedureModel); - - procedureModel.insertParameter( - new Blockly.procedures.ObservableParameterModel(this.workspace)); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('deleting a parameter triggers an update', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name') - .insertParameter( - new Blockly.procedures.ObservableParameterModel( - this.workspace)); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.deleteParameter(0); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - }); - - suite('parameter model updates', function() { - test('setting the name triggers an update', function() { - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - this.procedureMap.add( - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name') - .insertParameter(parameterModel)); - this.updateSpy.resetHistory(); - - parameterModel.setName('test2'); - - chai.assert.isTrue( - this.updateSpy.calledOnce, 'Expected an update to be triggered'); - }); - - test('modifying the variable model does not trigger an update', function() { - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - this.procedureMap.add( - new Blockly.procedures.ObservableProcedureModel( - this.workspace, 'test name') - .insertParameter(parameterModel)); - this.updateSpy.resetHistory(); - - const variableModel = parameterModel.getVariableModel(); - variableModel.name = 'some name'; - variableModel.type = 'some type'; - - chai.assert.isFalse( - this.updateSpy.called, 'Expected no update to be triggered'); - }); - }); - }); - - suite('event firing', function() { - setup(function() { - this.eventSpy = createChangeListenerSpy(this.workspace); - }); - - teardown(function() { - this.workspace.removeChangeListener(this.eventSpy); - }); - - suite('procedure create', function() { - test('create events are fired when a procedure is inserted', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.set(procedureModel.getId(), procedureModel); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {model: procedureModel}, - this.workspace.id); - }); - - test( - 'create events are not fired if a procedure is already inserted', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.set(procedureModel.getId(), procedureModel); - - this.eventSpy.resetHistory(); - this.procedureMap.set(procedureModel.getId(), procedureModel); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {}, - this.workspace.id); - }); - - test('create events are fired when a procedure is added', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {model: procedureModel}, - this.workspace.id); - }); - - test( - 'create events are not fired if a procedure is already added', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - - this.eventSpy.resetHistory(); - this.procedureMap.add(procedureModel); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureCreate, - {}, - this.workspace.id); - }); - }); - - suite('procedure delete', function() { - test('delete events are fired when a procedure is deleted', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - this.procedureMap.delete(procedureModel.getId()); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model: procedureModel}, - this.workspace.id); - }); - - test( - 'delete events are not fired if a procedure does not exist', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.delete(procedureModel.getId()); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {}, - this.workspace.id); - }); - - test( - 'delete events are fired when the procedure map is cleared', - function() { - const procedureModel1 = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - const procedureModel2 = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - const procedureModel3 = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel1); - this.procedureMap.add(procedureModel2); - this.procedureMap.add(procedureModel3); - this.procedureMap.clear(); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model: procedureModel1}, - this.workspace.id); - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model: procedureModel2}, - this.workspace.id); - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureDelete, - {model: procedureModel3}, - this.workspace.id); - }); - }); - - suite('procedure rename', function() { - test('rename events are fired when a procedure is renamed', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setName('test name'); - this.procedureMap.add(procedureModel); - procedureModel.setName('new name'); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureRename, - { - model: procedureModel, - oldName: 'test name', - }, - this.workspace.id); - }); - - test('rename events are not fired if the rename is noop', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setName('test name'); - this.procedureMap.add(procedureModel); - procedureModel.setName('test name'); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureRename, - {}, - this.workspace.id); - }); - - test( - 'rename events are not fired if the procedure is not in the map', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setName('test name'); - procedureModel.setName('new name'); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureRename, - {}, - this.workspace.id); - }); - }); - - suite('procedure enable', function() { - test('enable events are fired when a procedure is enabled', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setEnabled(false); - this.procedureMap.add(procedureModel); - procedureModel.setEnabled(true); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {model: procedureModel}, - this.workspace.id); - }); - - test('enable events are fired when a procedure is disabled', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - procedureModel.setEnabled(false); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {model: procedureModel}, - this.workspace.id); - }); - - test('enable events are not fired if enabling is noop', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - procedureModel.setEnabled(true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {}, - this.workspace.id); - }); - - test('enable events are not fired if disabling is noop', function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setEnabled(false); - this.procedureMap.add(procedureModel); - procedureModel.setEnabled(false); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {}, - this.workspace.id); - }); - - test( - 'enable events are not fired if the procedure is not in the map', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setEnabled(false); - procedureModel.setEnabled(true); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureEnable, - {}, - this.workspace.id); - }); - }); - - suite('parameter create', function() { - test( - 'parameter create events are fired when a parameter is inserted', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - procedureModel.insertParameter(parameterModel, 0); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - { - model: procedureModel, - parameter: parameterModel, - index: 0, - }, - this.workspace.id); - }); - - test( - 'parameter create events are not fired if the parameter is ' + - 'already inserted', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - procedureModel.insertParameter(parameterModel, 0); - - this.eventSpy.resetHistory(); - procedureModel.insertParameter(parameterModel, 0); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - {}, - this.workspace.id); - }); - - test( - 'parameter create events are not fired if the procedure is ' + - 'not in the map', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - procedureModel.insertParameter( - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'), - 0); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterCreate, - {}, - this.workspace.id); - }); - }); - - suite('parameter delete', function() { - test( - 'parameter delete events are fired when a parameter is deleted', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - procedureModel.insertParameter(parameterModel, 0); - procedureModel.deleteParameter(0); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - { - model: procedureModel, - parameter: parameterModel, - index: 0, - }, - this.workspace.id); - }); - - test( - 'parameter delete events are not fired if the parameter does not exist', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - procedureModel.deleteParameter(0); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - {}, - this.workspace.id); - }); - - test( - 'parameter delete events are not fired if the procedure is ' + - 'not in the map', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .insertParameter( - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'), - 0); - procedureModel.deleteParameter(0); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterDelete, - {}, - this.workspace.id); - }); - }); - - suite('parameter rename', function() { - test( - 'parameter rename events are fired when a parameter is renamed', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - procedureModel.insertParameter(parameterModel, 0); - - parameterModel.setName('new name'); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - { - model: procedureModel, - parameter: parameterModel, - oldName: 'test name', - }, - this.workspace.id); - }); - - test( - 'parameter rename events are not fired if the rename is noop', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace); - this.procedureMap.add(procedureModel); - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - procedureModel.insertParameter(parameterModel, 0); - - parameterModel.setName('test name'); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - {}, - this.workspace.id); - }); - - test( - 'parameter rename events are not fired if the procedure is ' + - 'not in the map', - function() { - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .insertParameter(parameterModel, 0); - - parameterModel.setName('new name'); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - {}, - this.workspace.id); - }); - - test( - 'parameter rename events are not fired if the parameter is ' + - 'not in a procedure', - function() { - const parameterModel = - new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test name'); - - parameterModel.setName('new name'); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureParameterRename, - {}, - this.workspace.id); - }); - }); - - suite('procedure change return', function() { - test( - 'return type change events are fired when the return is added', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setReturnTypes(null); - this.procedureMap.add(procedureModel); - procedureModel.setReturnTypes([]); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - { - model: procedureModel, - oldTypes: null, - }, - this.workspace.id); - }); - - test( - 'return type change events are fired when the return is removed', - function() { - const types = []; - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setReturnTypes(types); - this.procedureMap.add(procedureModel); - procedureModel.setReturnTypes(null); - - assertEventFiredShallow( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - { - model: procedureModel, - oldTypes: types, - }, - this.workspace.id); - }); - - test( - 'return type change events are not fired if adding is noop', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setReturnTypes([]); - this.procedureMap.add(procedureModel); - procedureModel.setReturnTypes([]); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - {}, - this.workspace.id); - }); - - test( - 'return type change events are not fired if removing is noop', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setReturnTypes(null); - this.procedureMap.add(procedureModel); - procedureModel.setReturnTypes(null); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - {}, - this.workspace.id); - }); - - test( - 'return type change events are not fired if the procedure is ' + - 'not in the map', - function() { - const procedureModel = - new Blockly.procedures.ObservableProcedureModel(this.workspace) - .setReturnTypes(null); - - procedureModel.setReturnTypes([]); - - assertEventNotFired( - this.eventSpy, - Blockly.Events.ProcedureChangeReturn, - {}, - this.workspace.id); - }); - }); - }); - - suite('backing variable to parameters', function() { - test( - 'construction references an existing variable if available', - function() { - const variable = this.workspace.createVariable('test1'); - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - - chai.assert.equal( - variable, - param.getVariableModel(), - 'Expected the parameter model to reference the existing variable'); - }); - - test('construction creates a variable if none exists', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - - chai.assert.equal( - this.workspace.getVariable('test1'), - param.getVariableModel(), - 'Expected the parameter model to create a variable'); - }); - - test('setName references an existing variable if available', function() { - const variable = this.workspace.createVariable('test2'); - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - - param.setName('test2'); - - chai.assert.equal( - variable, - param.getVariableModel(), - 'Expected the parameter model to reference the existing variable'); - }); - - test('setName creates a variable if none exits', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - - param.setName('test2'); - - chai.assert.equal( - this.workspace.getVariable('test2'), - param.getVariableModel(), - 'Expected the parameter model to create a variable'); - }); - - test('setTypes is unimplemented', function() { - const param = new Blockly.procedures.ObservableParameterModel( - this.workspace, 'test1'); - - chai.assert.throws( - () => { - param.setTypes(['some', 'types']); - }, - 'The built-in ParameterModel does not support typing'); + chai.assert.isTrue( + spy.calledOnce, 'Expected the model stop publishing'); }); }); }); diff --git a/tests/mocha/serializer_test.js b/tests/mocha/serializer_test.js index 26c89972d..d45cd40c3 100644 --- a/tests/mocha/serializer_test.js +++ b/tests/mocha/serializer_test.js @@ -73,10 +73,25 @@ Serializer.Attributes.Disabled = new SerializerTestCase('Disabled', '' + '' + ''); +Serializer.Attributes.NotDeletable = new SerializerTestCase('Deletable', + '' + + '' + + ''); +Serializer.Attributes.NotMovable = new SerializerTestCase('Movable', + '' + + '' + + ''); +Serializer.Attributes.NotEditable = new SerializerTestCase('Editable', + '' + + '' + + ''); Serializer.Attributes.testCases = [ Serializer.Attributes.Basic, Serializer.Attributes.Collapsed, Serializer.Attributes.Disabled, + Serializer.Attributes.NotDeletable, + Serializer.Attributes.NotMovable, + Serializer.Attributes.NotEditable, ]; Serializer.Attributes.Inline = new SerializerTestSuite('Inline'); @@ -1830,7 +1845,7 @@ const runSerializerTestSuite = (serializer, deserializer, testSuite) => { const createTestFunction = function(test) { return function() { Blockly.Xml.domToWorkspace( - Blockly.Xml.textToDom(test.xml), this.workspace); + Blockly.utils.xml.textToDom(test.xml), this.workspace); if (serializer && deserializer) { const save = serializer(workspaces.save(this.workspace)); this.workspace.clear(); @@ -1851,7 +1866,7 @@ const runSerializerTestSuite = (serializer, deserializer, testSuite) => { suiteCall(testSuite.title, function() { setup(function() { - sharedTestSetup.call(this); + sharedTestSetup.call(this, {fireEventsNow: false}); this.workspace = new Blockly.Workspace(); }); diff --git a/tests/mocha/test_helpers/fields.js b/tests/mocha/test_helpers/fields.js index 8d796d4a6..f3f6b7315 100644 --- a/tests/mocha/test_helpers/fields.js +++ b/tests/mocha/test_helpers/fields.js @@ -73,8 +73,8 @@ export function assertFieldValue(field, expectedValue, expectedText = undefined) if (expectedText === undefined) { expectedText = String(expectedValue); } - chai.assert.equal(actualValue, expectedValue, 'Value'); - chai.assert.equal(actualText, expectedText, 'Text'); + chai.assert.deepEqual(actualValue, expectedValue); + chai.assert.deepEqual(actualText, expectedText); } /** diff --git a/tests/mocha/test_helpers/procedures.js b/tests/mocha/test_helpers/procedures.js index 9358ade73..8fb40dcde 100644 --- a/tests/mocha/test_helpers/procedures.js +++ b/tests/mocha/test_helpers/procedures.js @@ -6,6 +6,7 @@ goog.declareModuleId('Blockly.test.helpers.procedures'); import {ConnectionType} from '../../../build/src/core/connection_type.js'; +import {VariableModel} from '../../../build/src/core/variable_model.js'; /** @@ -102,7 +103,7 @@ export function assertCallBlockStructure( assertCallBlockArgsStructure(callBlock, args); assertBlockVarModels(callBlock, varIds); if (name !== undefined) { - chai.assert(callBlock.getFieldValue('NAME'), name); + chai.assert.equal(callBlock.getFieldValue('NAME'), name); } } @@ -112,21 +113,22 @@ export function assertCallBlockStructure( * @param {boolean=} hasReturn Whether the procedure definition should have * return. * @param {Array=} args An array of argument names. + * @param {string=} name The name of the def block (defaults to 'proc name'). * @return {Blockly.Block} The created block. */ export function createProcDefBlock( - workspace, hasReturn = false, args = []) { + workspace, hasReturn = false, args = [], name = 'proc name') { const type = hasReturn ? 'procedures_defreturn' : 'procedures_defnoreturn'; - let xml = ''; + let xml = ``; for (let i = 0; i < args.length; i ++) { xml += - ' \n'; + ` \n`; } xml += - ' proc name' + + ` ${name}` + ''; - return Blockly.Xml.domToBlock(Blockly.Xml.textToDom(xml), workspace); + return Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom(xml), workspace); } /** @@ -134,15 +136,120 @@ export function createProcDefBlock( * @param {!Blockly.Workspace} workspace The Blockly workspace. * @param {boolean=} hasReturn Whether the corresponding procedure definition * has return. + * @param {string=} name The name of the caller block (defaults to 'proc name'). * @return {Blockly.Block} The created block. */ export function createProcCallBlock( - workspace, hasReturn = false) { + workspace, hasReturn = false, name = 'proc name') { const type = hasReturn ? 'procedures_callreturn' : 'procedures_callnoreturn'; - return Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' + return Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( + `` + + ` ` + + `` ), workspace); } + +export class MockProcedureModel { + constructor(name = '') { + this.id = Blockly.utils.idGenerator.genUid(); + this.name = name; + this.parameters = []; + this.returnTypes = null; + this.enabled = true; + } + + setName(name) { + this.name = name; + return this; + } + + insertParameter(parameterModel, index) { + this.parameters.splice(index, 0, parameterModel); + return this; + } + + deleteParameter(index) { + this.parameters.splice(index, 1); + return this; + } + + setReturnTypes(types) { + this.returnTypes = types; + return this; + } + + setEnabled(enabled) { + this.enabled = enabled; + return this; + } + + getId() { + return this.id; + } + + getName() { + return this.name; + } + + getParameter(index) { + return this.parameters[index]; + } + + getParameters() { + return [...this.parameters]; + } + + getReturnTypes() { + return this.returnTypes; + } + + getEnabled() { + return this.enabled; + } + + startPublishing() { } + + stopPublishing() { } +} + +export class MockParameterModel { + constructor(name) { + this.id = Blockly.utils.idGenerator.genUid(); + this.name = name; + this.types = []; + } + + setName(name) { + this.name = name; + return this; + } + + setTypes(types) { + this.types = types; + return this; + } + + getName() { + return this.name; + } + + getTypes() { + return this.types; + } + + getId() { + return this.id; + } +} + +export class MockParameterModelWithVar extends MockParameterModel { + constructor(name, workspace) { + super(name); + this.variable = new VariableModel(workspace, name); + } + + getVariableModel() { + return this.variable; + } +} diff --git a/tests/mocha/test_helpers/serialization.js b/tests/mocha/test_helpers/serialization.js index cc076bfc0..5ab11a13c 100644 --- a/tests/mocha/test_helpers/serialization.js +++ b/tests/mocha/test_helpers/serialization.js @@ -61,11 +61,12 @@ export const runSerializationTestSuite = (testCases) => { let block; if (testCase.json) { block = Blockly.serialization.blocks.append( - testCase.json, this.workspace); + testCase.json, this.workspace, {recordUndo: true}); } else { - block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( testCase.xml), this.workspace); } + this.clock.runAll(); testCase.assertBlockStructure(block); }; }; @@ -78,13 +79,15 @@ export const runSerializationTestSuite = (testCases) => { return function() { if (testCase.json) { const block = Blockly.serialization.blocks.append( - testCase.json, this.workspace); + testCase.json, this.workspace, {recordUndo: true}); + this.clock.runAll(); const generatedJson = Blockly.serialization.blocks.save(block); const expectedJson = testCase.expectedJson || testCase.json; chai.assert.deepEqual(generatedJson, expectedJson); } else { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( testCase.xml), this.workspace); + this.clock.runAll(); const generatedXml = Blockly.Xml.domToPrettyText( Blockly.Xml.blockToDom(block)); diff --git a/tests/mocha/test_helpers/toolbox_definitions.js b/tests/mocha/test_helpers/toolbox_definitions.js index 0a7f2b9ef..cf9998eca 100644 --- a/tests/mocha/test_helpers/toolbox_definitions.js +++ b/tests/mocha/test_helpers/toolbox_definitions.js @@ -176,7 +176,7 @@ export function getDeeplyNestedJSON() { * @return {Array} Array holding xml elements for a toolbox. */ export function getXmlArray() { - const block = Blockly.Xml.textToDom( + const block = Blockly.utils.xml.textToDom( ` NEQ @@ -190,9 +190,9 @@ export function getXmlArray() { `); - const separator = Blockly.Xml.textToDom(''); - const button = Blockly.Xml.textToDom(''); - const label = Blockly.Xml.textToDom(''); + const separator = Blockly.utils.xml.textToDom(''); + const button = Blockly.utils.xml.textToDom(''); + const label = Blockly.utils.xml.textToDom(''); return [block, separator, button, label]; } diff --git a/tests/mocha/test_helpers/workspace.js b/tests/mocha/test_helpers/workspace.js index a51d5b02e..8aefda588 100644 --- a/tests/mocha/test_helpers/workspace.js +++ b/tests/mocha/test_helpers/workspace.js @@ -697,7 +697,7 @@ export function testAWorkspace() { }); function testUndoDelete(xmlText) { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); Blockly.Xml.domToBlock(xml, this.workspace); this.workspace.getTopBlocks()[0].dispose(false); this.workspace.undo(); @@ -819,7 +819,7 @@ export function testAWorkspace() { }); function testUndoConnect(xmlText, parentId, childId, func) { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); Blockly.Xml.domToWorkspace(xml, this.workspace); const parent = this.workspace.getBlockById(parentId); @@ -1008,7 +1008,7 @@ export function testAWorkspace() { }); function testUndoDisconnect(xmlText, childId) { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); Blockly.Xml.domToWorkspace(xml, this.workspace); const child = this.workspace.getBlockById(childId); diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index 067ff4275..bc9bd9706 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -189,15 +189,15 @@ suite('Toolbox', function() { this.toolbox.dispose(); }); - function createKeyDownMock(keyCode) { + function createKeyDownMock(key) { return { - 'keyCode': keyCode, + 'key': key, 'preventDefault': function() {}, }; } - function testCorrectFunctionCalled(toolbox, keyCode, funcName) { - const event = createKeyDownMock(keyCode); + function testCorrectFunctionCalled(toolbox, key, funcName) { + const event = createKeyDownMock(key); const preventDefaultEvent = sinon.stub(event, 'preventDefault'); const selectMethodStub = sinon.stub(toolbox, funcName); selectMethodStub.returns(true); @@ -207,21 +207,21 @@ suite('Toolbox', function() { } test('Down button is pushed -> Should call selectNext_', function() { - testCorrectFunctionCalled(this.toolbox, Blockly.utils.KeyCodes.DOWN, 'selectNext_', true); + testCorrectFunctionCalled(this.toolbox, 'ArrowDown', 'selectNext_', true); }); test('Up button is pushed -> Should call selectPrevious_', function() { - testCorrectFunctionCalled(this.toolbox, Blockly.utils.KeyCodes.UP, 'selectPrevious_', true); + testCorrectFunctionCalled(this.toolbox, 'ArrowUp', 'selectPrevious_', true); }); test('Left button is pushed -> Should call selectParent_', function() { - testCorrectFunctionCalled(this.toolbox, Blockly.utils.KeyCodes.LEFT, 'selectParent_', true); + testCorrectFunctionCalled(this.toolbox, 'ArrowLeft', 'selectParent_', true); }); test('Right button is pushed -> Should call selectChild_', function() { - testCorrectFunctionCalled(this.toolbox, Blockly.utils.KeyCodes.RIGHT, 'selectChild_', true); + testCorrectFunctionCalled(this.toolbox, 'ArrowRight', 'selectChild_', true); }); - test('Enter button is pushed -> Should toggle expandedd', function() { + test('Enter button is pushed -> Should toggle expanded', function() { this.toolbox.selectedItem_ = getCollapsibleItem(this.toolbox); const toggleExpandedStub = sinon.stub(this.toolbox.selectedItem_, 'toggleExpanded'); - const event = createKeyDownMock(Blockly.utils.KeyCodes.ENTER); + const event = createKeyDownMock('Enter'); const preventDefaultEvent = sinon.stub(event, 'preventDefault'); this.toolbox.onKeyDown_(event); sinon.assert.called(toggleExpandedStub); @@ -229,7 +229,7 @@ suite('Toolbox', function() { }); test('Enter button is pushed when no item is selected -> Should not call prevent default', function() { this.toolbox.selectedItem_ = null; - const event = createKeyDownMock(Blockly.utils.KeyCodes.ENTER); + const event = createKeyDownMock('Enter'); const preventDefaultEvent = sinon.stub(event, 'preventDefault'); this.toolbox.onKeyDown_(event); sinon.assert.notCalled(preventDefaultEvent); diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js index 5c2f3c3be..028d8fcdc 100644 --- a/tests/mocha/trashcan_test.js +++ b/tests/mocha/trashcan_test.js @@ -15,7 +15,7 @@ import {simulateClick} from './test_helpers/user_input.js'; suite("Trashcan", function() { function fireDeleteEvent(workspace, xmlString) { - let xml = Blockly.Xml.textToDom( + let xml = Blockly.utils.xml.textToDom( '' + xmlString + ''); xml = xml.children[0]; @@ -63,7 +63,7 @@ suite("Trashcan", function() { chai.assert.equal(this.trashcan.contents_.length, 0); }); test("Non-Delete w/ oldXml", function() { - let xml = Blockly.Xml.textToDom( + let xml = Blockly.utils.xml.textToDom( '' + ' ' + '' diff --git a/tests/mocha/variable_map_test.js b/tests/mocha/variable_map_test.js index 2efb3afbd..ceef57088 100644 --- a/tests/mocha/variable_map_test.js +++ b/tests/mocha/variable_map_test.js @@ -301,7 +301,7 @@ suite('Variable Map', function() { const variable = this.variableMap.createVariable('test name', 'test type', 'test id'); this.variableMap.deleteVariable(variable); - + assertEventFired( this.eventSpy, Blockly.Events.VarDelete, @@ -320,7 +320,7 @@ suite('Variable Map', function() { new Blockly.VariableModel( this.workspace, 'test name', 'test type', 'test id'); this.variableMap.deleteVariable(variable); - + assertEventNotFired( this.eventSpy, Blockly.Events.VarDelete, @@ -335,7 +335,7 @@ suite('Variable Map', function() { function() { this.variableMap.createVariable('test name', 'test type', 'test id'); this.variableMap.deleteVariableById('test id'); - + assertEventFired( this.eventSpy, Blockly.Events.VarDelete, @@ -351,7 +351,7 @@ suite('Variable Map', function() { 'delete events are not fired when a variable does not exist', function() { this.variableMap.deleteVariableById('test id'); - + assertEventNotFired( this.eventSpy, Blockly.Events.VarDelete, @@ -379,7 +379,7 @@ suite('Variable Map', function() { }, this.workspace.id); }); - + test( 'rename events are not fired if the variable name already matches', function() { @@ -387,14 +387,14 @@ suite('Variable Map', function() { this.variableMap.createVariable( 'test name', 'test type', 'test id'); this.variableMap.renameVariable(variable, 'test name'); - + assertEventNotFired( this.eventSpy, Blockly.Events.VarRename, {}, this.workspace.id); }); - + test( 'rename events are not fired if the variable does not exist', function() { @@ -402,7 +402,7 @@ suite('Variable Map', function() { new Blockly.VariableModel( 'test name', 'test type', 'test id'); this.variableMap.renameVariable(variable, 'test name'); - + assertEventNotFired( this.eventSpy, Blockly.Events.VarRename, @@ -426,21 +426,21 @@ suite('Variable Map', function() { }, this.workspace.id); }); - + test( 'rename events are not fired if the variable name already matches', function() { this.variableMap.createVariable( 'test name', 'test type', 'test id'); this.variableMap.renameVariableById('test id', 'test name'); - + assertEventNotFired( this.eventSpy, Blockly.Events.VarRename, {}, this.workspace.id); }); - + test( 'renaming throws if the variable does not exist', function() { diff --git a/tests/mocha/webdriver.js b/tests/mocha/webdriver.js index e7eb99bc7..d64024a9f 100644 --- a/tests/mocha/webdriver.js +++ b/tests/mocha/webdriver.js @@ -30,7 +30,7 @@ async function runMochaTestsInBrowser() { ], logLevel: 'warn', }; - + // Run in headless mode on Github Actions. if (process.env.CI) { options.capabilities['goog:chromeOptions'].args.push( @@ -53,7 +53,7 @@ async function runMochaTestsInBrowser() { const text = await elem.getAttribute('tests_failed'); return text !== 'unset'; }, { - timeout: 50000, + timeout: 100000, }); const elem = await browser.$('#failureCount'); diff --git a/tests/mocha/workspace_comment_test.js b/tests/mocha/workspace_comment_test.js index 0ea07b88b..1fe3bfc76 100644 --- a/tests/mocha/workspace_comment_test.js +++ b/tests/mocha/workspace_comment_test.js @@ -152,14 +152,14 @@ suite('Workspace comment', function() { }); test('Initial position', function() { - const xy = this.comment.getXY(); + const xy = this.comment.getRelativeToSurfaceXY(); chai.assert.equal(xy.x, 0, 'Initial X position'); chai.assert.equal(xy.y, 0, 'Initial Y position'); }); test('moveBy', function() { this.comment.moveBy(10, 100); - const xy = this.comment.getXY(); + const xy = this.comment.getRelativeToSurfaceXY(); chai.assert.equal(xy.x, 10, 'New X position'); chai.assert.equal(xy.y, 100, 'New Y position'); }); diff --git a/tests/mocha/workspace_svg_test.js b/tests/mocha/workspace_svg_test.js index cea36e100..d33da06bc 100644 --- a/tests/mocha/workspace_svg_test.js +++ b/tests/mocha/workspace_svg_test.js @@ -46,7 +46,7 @@ suite('WorkspaceSvg', function() { }); test('appendDomToWorkspace alignment', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -70,8 +70,8 @@ suite('WorkspaceSvg', function() { 'Block 2 position y'); }); - test('Replacing shadow disposes svg', function() { - const dom = Blockly.Xml.textToDom( + test('Replacing shadow disposes of old shadow', function() { + const dom = Blockly.utils.xml.textToDom( '' + '' + '' + @@ -84,7 +84,7 @@ suite('WorkspaceSvg', function() { const blocks = this.workspace.getAllBlocks(false); chai.assert.equal(blocks.length, 2, 'Block count'); const shadowBlock = blocks[1]; - chai.assert.exists(shadowBlock.getSvgRoot()); + chai.assert.equal(false, shadowBlock.isDeadOrDying()); const block = this.workspace.newBlock('simple_test_block'); block.initSvg(); @@ -92,8 +92,8 @@ suite('WorkspaceSvg', function() { const inputConnection = this.workspace.getTopBlocks()[0].getInput('NAME').connection; inputConnection.connect(block.outputConnection); - chai.assert.exists(block.getSvgRoot()); - chai.assert.notExists(shadowBlock.getSvgRoot()); + chai.assert.equal(false, block.isDeadOrDying()); + chai.assert.equal(true, shadowBlock.isDeadOrDying()); }); suite('updateToolbox', function() { @@ -209,7 +209,7 @@ suite('WorkspaceSvg', function() { const block = this.workspace.newBlock('stack_block'); block.initSvg(); block.render(); - runViewportEventTest(() => this.workspace.zoomToFit(block.id), + runViewportEventTest(() => this.workspace.centerOnBlock(block.id), this.eventsFireStub, this.changeListenerSpy, this.workspace, this.clock); }); @@ -240,7 +240,7 @@ suite('WorkspaceSvg', function() { test('domToWorkspace that doesn\'t trigger scroll', function() { // 4 blocks with space in center. Blockly.Xml.domToWorkspace( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -248,12 +248,12 @@ suite('WorkspaceSvg', function() { '' + ''), this.workspace); - const xmlDom = Blockly.Xml.textToDom( + const xmlDom = Blockly.utils.xml.textToDom( ''); this.clock.runAll(); resetEventHistory(this.eventsFireStub, this.changeListenerSpy); // Add block in center of other blocks, not triggering scroll. - Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom( + Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom( ''), this.workspace); this.clock.runAll(); assertEventNotFired( @@ -265,7 +265,7 @@ suite('WorkspaceSvg', function() { test('domToWorkspace at 0,0 that doesn\'t trigger scroll', function() { // 4 blocks with space in center. Blockly.Xml.domToWorkspace( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + @@ -273,7 +273,7 @@ suite('WorkspaceSvg', function() { '' + ''), this.workspace); - const xmlDom = Blockly.Xml.textToDom( + const xmlDom = Blockly.utils.xml.textToDom( ''); this.clock.runAll(); resetEventHistory(this.eventsFireStub, this.changeListenerSpy); @@ -291,7 +291,7 @@ suite('WorkspaceSvg', function() { // TODO: Un-skip after adding filtering for consecutive viewport events. const addingMultipleBlocks = () => { Blockly.Xml.domToWorkspace( - Blockly.Xml.textToDom( + Blockly.utils.xml.textToDom( '' + '' + '' + diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 1306918e6..df794bd8a 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -75,7 +75,7 @@ suite('XML', function() { }); suite('textToDom', function() { test('Basic', function() { - const dom = Blockly.Xml.textToDom(this.complexXmlText); + const dom = Blockly.utils.xml.textToDom(this.complexXmlText); chai.assert.equal(dom.nodeName, 'xml', 'XML tag'); chai.assert.equal(dom.getElementsByTagName('block').length, 6, 'Block tags'); }); @@ -306,7 +306,7 @@ suite('XML', function() { suite('Comments', function() { suite('Headless', function() { setup(function() { - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); }); @@ -331,7 +331,7 @@ suite('XML', function() { setup(function() { // Let the parent teardown dispose of it. this.workspace = Blockly.inject('blocklyDiv', {comments: true}); - this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + this.block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.workspace); }); @@ -435,7 +435,7 @@ suite('XML', function() { }); suite('domToText', function() { test('Round tripping', function() { - const dom = Blockly.Xml.textToDom(this.complexXmlText); + const dom = Blockly.utils.xml.textToDom(this.complexXmlText); const text = Blockly.Xml.domToText(dom); chai.assert.equal(text.replace(/\s+/g, ''), this.complexXmlText.replace(/\s+/g, ''), 'Round trip'); @@ -443,7 +443,7 @@ suite('XML', function() { }); suite('domToPrettyText', function() { test('Round tripping', function() { - const dom = Blockly.Xml.textToDom(this.complexXmlText); + const dom = Blockly.utils.xml.textToDom(this.complexXmlText); const text = Blockly.Xml.domToPrettyText(dom); chai.assert.equal(text.replace(/\s+/g, ''), this.complexXmlText.replace(/\s+/g, ''), 'Round trip'); @@ -479,7 +479,7 @@ suite('XML', function() { suite('Comments', function() { suite('Headless', function() { test('Text', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -487,7 +487,7 @@ suite('XML', function() { chai.assert.equal(block.getCommentText(), 'test text'); }); test('No Text', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -495,7 +495,7 @@ suite('XML', function() { chai.assert.equal(block.getCommentText(), ''); }); test('Size', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -504,7 +504,7 @@ suite('XML', function() { {width: 100, height: 200}); }); test('Pinned True', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -512,7 +512,7 @@ suite('XML', function() { chai.assert.isTrue(block.commentModel.pinned); }); test('Pinned False', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -520,7 +520,7 @@ suite('XML', function() { chai.assert.isFalse(block.commentModel.pinned); }); test('Pinned Undefined', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -537,7 +537,7 @@ suite('XML', function() { }); test('Text', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -546,7 +546,7 @@ suite('XML', function() { chai.assert.isNotNull(block.getCommentIcon()); }); test('No Text', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' ' + '' @@ -555,7 +555,7 @@ suite('XML', function() { chai.assert.isNotNull(block.getCommentIcon()); }); test('Size', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -568,7 +568,7 @@ suite('XML', function() { }); suite('Pinned', function() { test('Pinned True', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -579,7 +579,7 @@ suite('XML', function() { chai.assert.isTrue(block.getCommentIcon().isVisible()); }); test('Pinned False', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -590,7 +590,7 @@ suite('XML', function() { chai.assert.isFalse(block.getCommentIcon().isVisible()); }); test('Pinned Undefined', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' + ' test text' + '' @@ -624,7 +624,7 @@ suite('XML', function() { }); test('Backwards compatibility', function() { createGenUidStubWithReturns('1'); - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' name1' + @@ -635,7 +635,7 @@ suite('XML', function() { assertVariableValues(this.workspace, 'name1', '', '1'); }); test('Variables at top', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' name1' + @@ -653,7 +653,7 @@ suite('XML', function() { assertVariableValues(this.workspace, 'name3', '', 'id3'); }); test('Variables at top duplicated variables tag', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -665,7 +665,7 @@ suite('XML', function() { }); }); test('Variables at top missing type', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' name1' + @@ -679,7 +679,7 @@ suite('XML', function() { }); }); test('Variables at top mismatch block type', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' name1' + @@ -709,7 +709,7 @@ suite('XML', function() { workspaceTeardown.call(this, this.workspace); }); test('Headless', function() { - const dom = Blockly.Xml.textToDom( + const dom = Blockly.utils.xml.textToDom( '' + ' ' + ' ' + @@ -746,7 +746,7 @@ suite('XML', function() { }; suite('Rendered -> XML -> Headless -> XML', function() { test('Comment', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.renderedWorkspace); block.setCommentText('test text'); @@ -757,7 +757,7 @@ suite('XML', function() { }); suite('Headless -> XML -> Rendered -> XML', function() { test('Comment', function() { - const block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + const block = Blockly.Xml.domToBlock(Blockly.utils.xml.textToDom( '' ), this.headlessWorkspace); block.setCommentText('test text'); diff --git a/tests/node/.eslintrc.json b/tests/node/.eslintrc.json index 287b288a6..9252228ed 100644 --- a/tests/node/.eslintrc.json +++ b/tests/node/.eslintrc.json @@ -8,5 +8,5 @@ "console": true, "require": true }, - "extends": "../../.eslintrc.json" + "extends": "../../.eslintrc.js" } diff --git a/tests/node/run_node_test.js b/tests/node/run_node_test.js index bea22c32b..27c970446 100644 --- a/tests/node/run_node_test.js +++ b/tests/node/run_node_test.js @@ -24,14 +24,14 @@ const xmlText = '\n' + suite('Test Node.js', function() { test('Import XML', function() { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); // Create workspace and import the XML const workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(xml, workspace); }); test('Roundtrip XML', function() { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); const workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(xml, workspace); @@ -42,7 +42,7 @@ suite('Test Node.js', function() { assert.equal(headlessText, xmlText, 'equal'); }); test('Generate Code', function() { - const xml = Blockly.Xml.textToDom(xmlText); + const xml = Blockly.utils.xml.textToDom(xmlText); // Create workspace and import the XML const workspace = new Blockly.Workspace(); diff --git a/tests/playground.html b/tests/playground.html index ef8d7bdf9..b2b9ad933 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -177,7 +177,7 @@ function load() { var state = JSON.parse(input.value); Blockly.serialization.workspaces.load(state, workspace); } else if (valid.xml) { - var xml = Blockly.Xml.textToDom(input.value); + var xml = Blockly.utils.xml.textToDom(input.value); Blockly.Xml.domToWorkspace(xml, workspace); } taChange(); @@ -216,7 +216,7 @@ function saveIsValid(save) { } var validXml = true try { - Blockly.Xml.textToDom(save); + Blockly.utils.xml.textToDom(save); } catch (e) { validXml = false; } @@ -296,7 +296,7 @@ function spaghetti(n) { '$1' + spaghettiXml + '' + xml + ''; - var dom = Blockly.Xml.textToDom(xml); + var dom = Blockly.utils.xml.textToDom(xml); console.time('Spaghetti domToWorkspace'); Blockly.Xml.domToWorkspace(dom, workspace); console.timeEnd('Spaghetti domToWorkspace'); diff --git a/tests/playgrounds/shared_procedures.html b/tests/playgrounds/shared_procedures.html index 63a1a9054..c1681e540 100644 --- a/tests/playgrounds/shared_procedures.html +++ b/tests/playgrounds/shared_procedures.html @@ -9,7 +9,7 @@