From 0c2470183cf857d22f05333d9221cde8db3ff97c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 26 Jun 2024 11:19:21 -0700 Subject: [PATCH 001/102] release: Update version number to 12.0.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c5d8fe98..5ce76f3c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockly", - "version": "11.1.1", + "version": "12.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockly", - "version": "11.1.1", + "version": "12.0.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 7826c53ef..034436128 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "11.1.1", + "version": "12.0.0", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From 989c91f6267a4a561aedb8ee532d4e3422db4dbf Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 27 Jun 2024 11:11:45 -0700 Subject: [PATCH 002/102] feat!: Add support for preserving block comment locations. (#8231) * feat: Add support for preserving block comment locations. * chore: format the tests. --- core/bubbles/textinput_bubble.ts | 32 ++++++++++++++- core/icons/comment_icon.ts | 67 ++++++++++++++++++++++++++++++- core/interfaces/i_comment_icon.ts | 7 ++++ core/xml.ts | 27 +++++++++++-- tests/mocha/block_test.js | 4 ++ tests/mocha/comment_test.js | 26 ++++++++++++ 6 files changed, 158 insertions(+), 5 deletions(-) diff --git a/core/bubbles/textinput_bubble.ts b/core/bubbles/textinput_bubble.ts index d7d1f5ae7..d10619846 100644 --- a/core/bubbles/textinput_bubble.ts +++ b/core/bubbles/textinput_bubble.ts @@ -47,6 +47,9 @@ export class TextInputBubble extends Bubble { /** Functions listening for changes to the size of this bubble. */ private sizeChangeListeners: (() => void)[] = []; + /** Functions listening for changes to the location of this bubble. */ + private locationChangeListeners: (() => void)[] = []; + /** The text of this bubble. */ private text = ''; @@ -105,6 +108,11 @@ export class TextInputBubble extends Bubble { this.sizeChangeListeners.push(listener); } + /** Adds a change listener to be notified when this bubble's location changes. */ + addLocationChangeListener(listener: () => void) { + this.locationChangeListeners.push(listener); + } + /** Creates the editor UI for this bubble. */ private createEditor(container: SVGGElement): { inputRoot: SVGForeignObjectElement; @@ -212,10 +220,25 @@ export class TextInputBubble extends Bubble { /** @returns the size of this bubble. */ getSize(): Size { - // Overriden to be public. + // Overridden to be public. return super.getSize(); } + override moveDuringDrag(newLoc: Coordinate) { + super.moveDuringDrag(newLoc); + this.onLocationChange(); + } + + override setPositionRelativeToAnchor(left: number, top: number) { + super.setPositionRelativeToAnchor(left, top); + this.onLocationChange(); + } + + protected override positionByRect(rect = new Rect(0, 0, 0, 0)) { + super.positionByRect(rect); + this.onLocationChange(); + } + /** Handles mouse down events on the resize target. */ private onResizePointerDown(e: PointerEvent) { this.bringToFront(); @@ -297,6 +320,13 @@ export class TextInputBubble extends Bubble { listener(); } } + + /** Handles a location change event for the text area. Calls event listeners. */ + private onLocationChange() { + for (const listener of this.locationChangeListeners) { + listener(); + } + } } Css.register(` diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index df54560c5..c05748dcc 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -58,6 +58,9 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { /** The size of this comment (which is applied to the editable bubble). */ private bubbleSize = new Size(DEFAULT_BUBBLE_WIDTH, DEFAULT_BUBBLE_HEIGHT); + /** The location of the comment bubble in workspace coordinates. */ + private bubbleLocation?: Coordinate; + /** * The visibility of the bubble for this comment. * @@ -149,7 +152,13 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { } override onLocationChange(blockOrigin: Coordinate): void { + const oldLocation = this.workspaceLocation; super.onLocationChange(blockOrigin); + if (this.bubbleLocation) { + const newLocation = this.workspaceLocation; + const delta = Coordinate.difference(newLocation, oldLocation); + this.bubbleLocation = Coordinate.sum(this.bubbleLocation, delta); + } const anchorLocation = this.getAnchorLocation(); this.textInputBubble?.setAnchorLocation(anchorLocation); this.textBubble?.setAnchorLocation(anchorLocation); @@ -191,18 +200,43 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { return this.bubbleSize; } + /** + * Sets the location of the comment bubble in the workspace. + */ + setBubbleLocation(location: Coordinate) { + this.bubbleLocation = location; + this.textInputBubble?.moveDuringDrag(location); + this.textBubble?.moveDuringDrag(location); + } + + /** + * @returns the location of the comment bubble in the workspace. + */ + getBubbleLocation(): Coordinate | undefined { + return this.bubbleLocation; + } + /** * @returns the state of the comment as a JSON serializable value if the * comment has text. Otherwise returns null. */ saveState(): CommentState | null { if (this.text) { - return { + const state: CommentState = { 'text': this.text, 'pinned': this.bubbleIsVisible(), 'height': this.bubbleSize.height, 'width': this.bubbleSize.width, }; + const location = this.getBubbleLocation(); + if (location) { + state['x'] = this.sourceBlock.workspace.RTL + ? this.sourceBlock.workspace.getWidth() - + (location.x + this.bubbleSize.width) + : location.x; + state['y'] = location.y; + } + return state; } return null; } @@ -216,6 +250,16 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { ); this.bubbleVisiblity = state['pinned'] ?? false; this.setBubbleVisible(this.bubbleVisiblity); + let x = state['x']; + const y = state['y']; + renderManagement.finishQueuedRenders().then(() => { + if (x && y) { + x = this.sourceBlock.workspace.RTL + ? this.sourceBlock.workspace.getWidth() - (x + this.bubbleSize.width) + : x; + this.setBubbleLocation(new Coordinate(x, y)); + } + }); } override onClick(): void { @@ -259,6 +303,12 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { } } + onBubbleLocationChange(): void { + if (this.textInputBubble) { + this.bubbleLocation = this.textInputBubble.getRelativeToSurfaceXY(); + } + } + bubbleIsVisible(): boolean { return this.bubbleVisiblity; } @@ -308,8 +358,14 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { ); this.textInputBubble.setText(this.getText()); this.textInputBubble.setSize(this.bubbleSize, true); + if (this.bubbleLocation) { + this.textInputBubble.moveDuringDrag(this.bubbleLocation); + } this.textInputBubble.addTextChangeListener(() => this.onTextChange()); this.textInputBubble.addSizeChangeListener(() => this.onSizeChange()); + this.textInputBubble.addLocationChangeListener(() => + this.onBubbleLocationChange(), + ); } /** Shows the non editable text bubble for this comment. */ @@ -320,6 +376,9 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { this.getAnchorLocation(), this.getBubbleOwnerRect(), ); + if (this.bubbleLocation) { + this.textBubble.moveDuringDrag(this.bubbleLocation); + } } /** Hides any open bubbles owned by this comment. */ @@ -365,6 +424,12 @@ export interface CommentState { /** The width of the comment bubble. */ width?: number; + + /** The X coordinate of the comment bubble. */ + x?: number; + + /** The Y coordinate of the comment bubble. */ + y?: number; } registry.register(CommentIcon.TYPE, CommentIcon); diff --git a/core/interfaces/i_comment_icon.ts b/core/interfaces/i_comment_icon.ts index 09b071110..2762348de 100644 --- a/core/interfaces/i_comment_icon.ts +++ b/core/interfaces/i_comment_icon.ts @@ -8,6 +8,7 @@ import {IconType} from '../icons/icon_types.js'; import {CommentState} from '../icons/comment_icon.js'; import {IIcon, isIcon} from './i_icon.js'; import {Size} from '../utils/size.js'; +import {Coordinate} from '../utils/coordinate.js'; import {IHasBubble, hasBubble} from './i_has_bubble.js'; import {ISerializable, isSerializable} from './i_serializable.js'; @@ -20,6 +21,10 @@ export interface ICommentIcon extends IIcon, IHasBubble, ISerializable { getBubbleSize(): Size; + setBubbleLocation(location: Coordinate): void; + + getBubbleLocation(): Coordinate | undefined; + saveState(): CommentState; loadState(state: CommentState): void; @@ -35,6 +40,8 @@ export function isCommentIcon(obj: Object): obj is ICommentIcon { (obj as any)['getText'] !== undefined && (obj as any)['setBubbleSize'] !== undefined && (obj as any)['getBubbleSize'] !== undefined && + (obj as any)['setBubbleLocation'] !== undefined && + (obj as any)['getBubbleLocation'] !== undefined && obj.getType() === IconType.COMMENT ); } diff --git a/core/xml.ts b/core/xml.ts index bad381c5d..b8ecf6433 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -217,12 +217,24 @@ export function blockToDom( const comment = block.getIcon(IconType.COMMENT)!; const size = comment.getBubbleSize(); const pinned = comment.bubbleIsVisible(); + const location = comment.getBubbleLocation(); const commentElement = utilsXml.createElement('comment'); commentElement.appendChild(utilsXml.createTextNode(commentText)); commentElement.setAttribute('pinned', `${pinned}`); - commentElement.setAttribute('h', String(size.height)); - commentElement.setAttribute('w', String(size.width)); + commentElement.setAttribute('h', `${size.height}`); + commentElement.setAttribute('w', `${size.width}`); + if (location) { + commentElement.setAttribute( + 'x', + `${ + block.workspace.RTL + ? block.workspace.getWidth() - (location.x + size.width) + : location.x + }`, + ); + commentElement.setAttribute('y', `${location.y}`); + } element.appendChild(commentElement); } @@ -795,6 +807,8 @@ function applyCommentTagNodes(xmlChildren: Element[], block: Block) { const pinned = xmlChild.getAttribute('pinned') === 'true'; const width = parseInt(xmlChild.getAttribute('w') ?? '50', 10); const height = parseInt(xmlChild.getAttribute('h') ?? '50', 10); + let x = parseInt(xmlChild.getAttribute('x') ?? '', 10); + const y = parseInt(xmlChild.getAttribute('y') ?? '', 10); block.setCommentText(text); const comment = block.getIcon(IconType.COMMENT)!; @@ -803,8 +817,15 @@ function applyCommentTagNodes(xmlChildren: Element[], block: Block) { } // Set the pinned state of the bubble. comment.setBubbleVisible(pinned); + // Actually show the bubble after the block has been rendered. - setTimeout(() => comment.setBubbleVisible(pinned), 1); + setTimeout(() => { + if (!isNaN(x) && !isNaN(y)) { + x = block.workspace.RTL ? block.workspace.getWidth() - (x + width) : x; + comment.setBubbleLocation(new Coordinate(x, y)); + } + comment.setBubbleVisible(pinned); + }, 1); } } diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index dd070f86c..d7c0d7c58 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -1388,6 +1388,10 @@ suite('Blocks', function () { return Blockly.utils.Size(0, 0); } + setBubbleLocation() {} + + getBubbleLocation() {} + bubbleIsVisible() { return true; } diff --git a/tests/mocha/comment_test.js b/tests/mocha/comment_test.js index d4091b9c2..1f392194f 100644 --- a/tests/mocha/comment_test.js +++ b/tests/mocha/comment_test.js @@ -141,4 +141,30 @@ suite('Comments', function () { assertBubbleSize(this.comment, 100, 100); }); }); + suite('Set/Get Bubble Location', function () { + teardown(function () { + sinon.restore(); + }); + function assertBubbleLocation(comment, x, y) { + const location = comment.getBubbleLocation(); + assert.equal(location.x, x); + assert.equal(location.y, y); + } + test('Set Location While Visible', function () { + this.comment.setBubbleVisible(true); + + this.comment.setBubbleLocation(new Blockly.utils.Coordinate(100, 100)); + assertBubbleLocation(this.comment, 100, 100); + + this.comment.setBubbleVisible(false); + assertBubbleLocation(this.comment, 100, 100); + }); + test('Set Location While Invisible', function () { + this.comment.setBubbleLocation(new Blockly.utils.Coordinate(100, 100)); + assertBubbleLocation(this.comment, 100, 100); + + this.comment.setBubbleVisible(true); + assertBubbleLocation(this.comment, 100, 100); + }); + }); }); From f45270e0837b4da5c899943fae62bcefed28d836 Mon Sep 17 00:00:00 2001 From: Shreyans Pathak Date: Fri, 12 Jul 2024 12:11:19 -0400 Subject: [PATCH 003/102] refactor: field_checkbox `dom.addClass` params (#8309) --- core/field_checkbox.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/field_checkbox.ts b/core/field_checkbox.ts index 83f460bb9..0773a1f82 100644 --- a/core/field_checkbox.ts +++ b/core/field_checkbox.ts @@ -114,7 +114,7 @@ export class FieldCheckbox extends Field { super.initView(); const textElement = this.getTextElement(); - dom.addClass(textElement, 'blocklyCheckbox'); + dom.addClass(this.fieldGroup_!, 'blocklyCheckboxField'); textElement.style.display = this.value_ ? 'block' : 'none'; } From 9ba791c1446b088e423bfbbb55517ee8fbda5675 Mon Sep 17 00:00:00 2001 From: Gabriel Fleury <55366345+ga-fleury@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:34:42 -0300 Subject: [PATCH 004/102] bug: Rename the blockly icon CSS classes to use camelCase (#8329) (#8335) --- core/icons/comment_icon.ts | 2 +- core/icons/mutator_icon.ts | 2 +- core/icons/warning_icon.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index c05748dcc..064f67843 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -114,7 +114,7 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { }, this.svgRoot, ); - dom.addClass(this.svgRoot!, 'blockly-icon-comment'); + dom.addClass(this.svgRoot!, 'blocklyCommentIcon'); } override dispose() { diff --git a/core/icons/mutator_icon.ts b/core/icons/mutator_icon.ts index 7fb3fcf3b..2c350f544 100644 --- a/core/icons/mutator_icon.ts +++ b/core/icons/mutator_icon.ts @@ -116,7 +116,7 @@ export class MutatorIcon extends Icon implements IHasBubble { {'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, this.svgRoot, ); - dom.addClass(this.svgRoot!, 'blockly-icon-mutator'); + dom.addClass(this.svgRoot!, 'blocklyMutatorIcon'); } override dispose(): void { diff --git a/core/icons/warning_icon.ts b/core/icons/warning_icon.ts index 08f511a60..5a22ec16d 100644 --- a/core/icons/warning_icon.ts +++ b/core/icons/warning_icon.ts @@ -89,7 +89,7 @@ export class WarningIcon extends Icon implements IHasBubble { }, this.svgRoot, ); - dom.addClass(this.svgRoot!, 'blockly-icon-warning'); + dom.addClass(this.svgRoot!, 'blocklyWarningIcon'); } override dispose() { From 5a32c3fe43c2f14d8cf6c1f88eab6f9569d1cd46 Mon Sep 17 00:00:00 2001 From: Suryansh Shakya <83297944+nullHawk@users.noreply.github.com> Date: Fri, 12 Jul 2024 22:05:10 +0530 Subject: [PATCH 005/102] feat: added blocklyField to field's SVG Group (#8334) --- core/field.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/field.ts b/core/field.ts index 51e006823..cb0fadb03 100644 --- a/core/field.ts +++ b/core/field.ts @@ -323,6 +323,9 @@ export abstract class Field protected initView() { this.createBorderRect_(); this.createTextElement_(); + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyField'); + } } /** From dd18edd3439fa24bd37b92131c6e0c2997c848a3 Mon Sep 17 00:00:00 2001 From: Shashwat Pathak <111122076+shashwatpathak98@users.noreply.github.com> Date: Fri, 12 Jul 2024 22:06:25 +0530 Subject: [PATCH 006/102] fix!: Make `IPathObject` styling methods optional (#8332) --- core/block_svg.ts | 6 +++--- core/renderers/common/i_path_object.ts | 30 +++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/block_svg.ts b/core/block_svg.ts index bc02ef638..ac6970dce 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -849,7 +849,7 @@ export class BlockSvg * @internal */ applyColour() { - this.pathObject.applyColour(this); + this.pathObject.applyColour?.(this); const icons = this.getIcons(); for (let i = 0; i < icons.length; i++) { @@ -1115,7 +1115,7 @@ export class BlockSvg .getConstants() .getBlockStyleForColour(this.colour_); - this.pathObject.setStyle(styleObj.style); + this.pathObject.setStyle?.(styleObj.style); this.style = styleObj.style; this.styleName_ = styleObj.name; @@ -1137,7 +1137,7 @@ export class BlockSvg if (blockStyle) { this.hat = blockStyle.hat; - this.pathObject.setStyle(blockStyle); + this.pathObject.setStyle?.(blockStyle); // Set colour to match Block. this.colour_ = blockStyle.colourPrimary; this.style = blockStyle; diff --git a/core/renderers/common/i_path_object.ts b/core/renderers/common/i_path_object.ts index 30033f18e..cb6475202 100644 --- a/core/renderers/common/i_path_object.ts +++ b/core/renderers/common/i_path_object.ts @@ -49,21 +49,6 @@ export interface IPathObject { */ setPath(pathString: string): void; - /** - * Apply the stored colours to the block's path, taking into account whether - * the paths belong to a shadow block. - * - * @param block The source block. - */ - applyColour(block: BlockSvg): void; - - /** - * Update the style. - * - * @param blockStyle The block style to use. - */ - setStyle(blockStyle: BlockStyle): void; - /** * Flip the SVG paths in RTL. */ @@ -130,8 +115,23 @@ export interface IPathObject { rtl: boolean, ): void; + /** + * Apply the stored colours to the block's path, taking into account whether + * the paths belong to a shadow block. + * + * @param block The source block. + */ + applyColour?(block: BlockSvg): void; + /** * Removes any highlight associated with the given connection, if it exists. */ removeConnectionHighlight?(connection: RenderedConnection): void; + + /** + * Update the style. + * + * @param blockStyle The block style to use. + */ + setStyle?(blockStyle: BlockStyle): void; } From 968494205a03bb92cfc514b97d0c78172abcc36c Mon Sep 17 00:00:00 2001 From: Gabriel Fleury <55366345+ga-fleury@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:37:20 -0300 Subject: [PATCH 007/102] feat: Add a blocklyFieldText CSS class to fields' text elements (#8291) (#8302) * feat!: Add a blocklyFieldText CSS class to fields' text elements (#8291) * add class instead of replace Co-authored-by: Beka Westberg --------- Co-authored-by: Beka Westberg --- core/field.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/field.ts b/core/field.ts index cb0fadb03..eed34e613 100644 --- a/core/field.ts +++ b/core/field.ts @@ -376,7 +376,7 @@ export abstract class Field this.textElement_ = dom.createSvgElement( Svg.TEXT, { - 'class': 'blocklyText', + 'class': 'blocklyText blocklyFieldText', }, this.fieldGroup_, ); From 7c22c46ee685815fbbdd06764bee3f929736c873 Mon Sep 17 00:00:00 2001 From: Shreyans Pathak Date: Mon, 15 Jul 2024 14:54:30 -0400 Subject: [PATCH 008/102] refactor: Add `addClass` and `removeClass` methods to blockSvg (#8337) * refactor: Add `addClass` and `removeClass` methods to blockSvg * fix: lint * fix: jsdoc --- core/block_svg.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/core/block_svg.ts b/core/block_svg.ts index ac6970dce..adef213d5 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -671,6 +671,24 @@ export class BlockSvg } } + /** + * Add a CSS class to the SVG group of this block. + * + * @param className + */ + addClass(className: string) { + dom.addClass(this.svgGroup_, className); + } + + /** + * Remove a CSS class from the SVG group of this block. + * + * @param className + */ + removeClass(className: string) { + dom.removeClass(this.svgGroup_, className); + } + /** * Recursively adds or removes the dragging class to this node and its * children. @@ -683,10 +701,10 @@ export class BlockSvg if (adding) { this.translation = ''; common.draggingConnections.push(...this.getConnections_(true)); - dom.addClass(this.svgGroup_, 'blocklyDragging'); + this.addClass('blocklyDragging'); } else { common.draggingConnections.length = 0; - dom.removeClass(this.svgGroup_, 'blocklyDragging'); + this.removeClass('blocklyDragging'); } // Recurse through all blocks attached under this one. for (let i = 0; i < this.childBlocks_.length; i++) { From 00d090edcf3c5ab83dc27b93c061dd1617dc6616 Mon Sep 17 00:00:00 2001 From: Shashwat Pathak <111122076+shashwatpathak98@users.noreply.github.com> Date: Tue, 16 Jul 2024 01:58:39 +0530 Subject: [PATCH 009/102] feat: Add a `blocklyVariableField` CSS class to variable fields (#8359) --- core/field_variable.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/field_variable.ts b/core/field_variable.ts index 539557256..d0a929bf0 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -22,6 +22,7 @@ import { MenuGenerator, MenuOption, } from './field_dropdown.js'; +import * as dom from './utils/dom.js'; import * as fieldRegistry from './field_registry.js'; import * as internalConstants from './internal_constants.js'; import type {Menu} from './menu.js'; @@ -148,6 +149,11 @@ export class FieldVariable extends FieldDropdown { this.doValueUpdate_(variable.getId()); } + override initView() { + super.initView(); + dom.addClass(this.fieldGroup_!, 'blocklyVariableField'); + } + override shouldAddBorderRect_() { const block = this.getSourceBlock(); if (!block) { From aecfe34c381ef17c721f1d533f60e4c0aa24032a Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 15 Jul 2024 15:29:19 -0700 Subject: [PATCH 010/102] feat: add the IVariableMap and IVariableModel interfaces. (#8369) * feat: add the IVariableMap and IVariableModel interfaces. * chore: add license headers. --- core/blockly.ts | 4 ++ core/interfaces/i_variable_map.ts | 72 +++++++++++++++++++++++++++++ core/interfaces/i_variable_model.ts | 26 +++++++++++ 3 files changed, 102 insertions(+) create mode 100644 core/interfaces/i_variable_map.ts create mode 100644 core/interfaces/i_variable_model.ts diff --git a/core/blockly.ts b/core/blockly.ts index 77362c0b4..28eb0010a 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -149,6 +149,8 @@ import {ISerializable, isSerializable} from './interfaces/i_serializable.js'; import {IStyleable} from './interfaces/i_styleable.js'; import {IToolbox} from './interfaces/i_toolbox.js'; import {IToolboxItem} from './interfaces/i_toolbox_item.js'; +import {IVariableMap} from './interfaces/i_variable_map.js'; +import {IVariableModel} from './interfaces/i_variable_model.js'; import { IVariableBackedParameterModel, isVariableBackedParameterModel, @@ -552,6 +554,8 @@ export {ISerializable, isSerializable}; export {IStyleable}; export {IToolbox}; export {IToolboxItem}; +export {IVariableMap}; +export {IVariableModel}; export {IVariableBackedParameterModel, isVariableBackedParameterModel}; export {Marker}; export {MarkerManager}; diff --git a/core/interfaces/i_variable_map.ts b/core/interfaces/i_variable_map.ts new file mode 100644 index 000000000..0bfc532a7 --- /dev/null +++ b/core/interfaces/i_variable_map.ts @@ -0,0 +1,72 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {IVariableModel} from './i_variable_model.js'; +import {State} from '../serialization/variables.js'; + +/** + * Variable maps are container objects responsible for storing and managing the + * set of variables referenced on a workspace. + * + * Any of these methods may define invariants about which names and types are + * legal, and throw if they are not met. + */ +export interface IVariableMap { + /* Returns the variable corresponding to the given ID, or null if none. */ + getVariableById(id: string): T | null; + + /** + * Returns the variable with the given name, or null if not found. If `type` + * is provided, the variable's type must also match, or null should be + * returned. + */ + getVariable(name: string, type?: string): T | null; + + /* Returns a list of all variables managed by this variable map. */ + getAllVariables(): T[]; + + /** + * Returns a list of all of the variables of the given type managed by this + * variable map. + */ + getVariablesOfType(type: string): T[]; + + /** + * Returns a list of the set of types of the variables managed by this + * variable map. + */ + getTypes(): string[]; + + /** + * Creates a new variable with the given name. If ID is not specified, the + * variable map should create one. Returns the new variable. + */ + createVariable(name: string, id?: string, type?: string | null): T; + + /** + * Changes the name of the given variable to the name provided and returns the + * renamed variable. + */ + renameVariable(variable: T, newName: string): T; + + /* Changes the type of the given variable and returns it. */ + changeVariableType(variable: T, newType: string): T; + + /* Deletes the given variable. */ + deleteVariable(variable: T): void; + + /* Removes all variables from this variable map. */ + clear(): void; + + /* Returns an object representing the serialized state of the variable. */ + saveVariable(variable: T): U; + + /** + * Creates a variable in this variable map corresponding to the given state + * (produced by a call to `saveVariable`). + */ + loadVariable(state: U): T; +} diff --git a/core/interfaces/i_variable_model.ts b/core/interfaces/i_variable_model.ts new file mode 100644 index 000000000..97fa9161d --- /dev/null +++ b/core/interfaces/i_variable_model.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Representation of a variable. */ +export interface IVariableModel { + /* Returns the unique ID of this variable. */ + getId(): string; + + /* Returns the user-visible name of this variable. */ + getName(): string; + + /** + * Returns the type of the variable like 'int' or 'string'. Does not need to be + * unique. This will default to '' which is a specific type. + */ + getType(): string; + + /* Sets the user-visible name of this variable. */ + setName(name: string): this; + + /* Sets the type of this variable. */ + setType(type: string): this; +} From ae2fea484f63b97c6885a211c9920a5d75d921fa Mon Sep 17 00:00:00 2001 From: Abhinav Choudhary Date: Tue, 16 Jul 2024 23:30:32 +0530 Subject: [PATCH 011/102] fix!: Rename `blocklyTreeRow` and `blocklyToolboxCategory` CSS classes (#8357) * fix!: #8345 rename css class This commit renames the blocklyTreeRow CSS class to blocklyToolboxCategory * Update category.ts * fix: css class conflicts Rename original blocklyToolboxCategory to blocklyToolboxCategoryContainer --- core/toolbox/category.ts | 14 +++++++------- tests/mocha/comment_deserialization_test.js | 2 +- tests/mocha/toolbox_test.js | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index 6ff159b0b..2d0ea4aee 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -131,8 +131,8 @@ export class ToolboxCategory */ protected makeDefaultCssConfig_(): CssConfig { return { - 'container': 'blocklyToolboxCategory', - 'row': 'blocklyTreeRow', + 'container': 'blocklyToolboxCategoryContainer', + 'row': 'blocklyToolboxCategory', 'rowcontentcontainer': 'blocklyTreeRowContentContainer', 'icon': 'blocklyTreeIcon', 'label': 'blocklyTreeLabel', @@ -659,19 +659,19 @@ export type CssConfig = ToolboxCategory.CssConfig; /** CSS for Toolbox. See css.js for use. */ Css.register(` -.blocklyTreeRow:not(.blocklyTreeSelected):hover { +.blocklyToolboxCategory:not(.blocklyTreeSelected):hover { background-color: rgba(255, 255, 255, .2); } -.blocklyToolboxDiv[layout="h"] .blocklyToolboxCategory { +.blocklyToolboxDiv[layout="h"] .blocklyToolboxCategoryContainer { margin: 1px 5px 1px 0; } -.blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategory { +.blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategoryContainer { margin: 1px 0 1px 5px; } -.blocklyTreeRow { +.blocklyToolboxCategory { height: 22px; line-height: 22px; margin-bottom: 3px; @@ -679,7 +679,7 @@ Css.register(` white-space: nowrap; } -.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow { +.blocklyToolboxDiv[dir="RTL"] .blocklyToolboxCategory { margin-left: 8px; padding-right: 0; } diff --git a/tests/mocha/comment_deserialization_test.js b/tests/mocha/comment_deserialization_test.js index 2517ed779..54ee0b2ff 100644 --- a/tests/mocha/comment_deserialization_test.js +++ b/tests/mocha/comment_deserialization_test.js @@ -110,7 +110,7 @@ suite('Comment Deserialization', function () { test('Toolbox', function () { // Place from toolbox. const toolbox = this.workspace.getToolbox(); - simulateClick(toolbox.HtmlDiv.querySelector('.blocklyTreeRow')); + simulateClick(toolbox.HtmlDiv.querySelector('.blocklyToolboxCategory')); simulateClick( toolbox.getFlyout().svgGroup_.querySelector('.blocklyPath'), ); diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index b723e7038..b3cd45090 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -201,7 +201,9 @@ suite('Toolbox', function () { sinon.assert.calledOnce(hideChaffStub); }); test('Category clicked -> Should select category', function () { - const categoryXml = document.getElementsByClassName('blocklyTreeRow')[0]; + const categoryXml = document.getElementsByClassName( + 'blocklyToolboxCategory', + )[0]; const evt = { 'target': categoryXml, }; From c5532066f5ccec34af079d898d60d36d8a4597d0 Mon Sep 17 00:00:00 2001 From: Nirmal Kumar Date: Wed, 17 Jul 2024 01:39:49 +0530 Subject: [PATCH 012/102] feat: Add a blocklyTextBubble CSS class to the text bubble #8331 (#8333) --- core/bubbles/text_bubble.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/bubbles/text_bubble.ts b/core/bubbles/text_bubble.ts index 020ab4f2e..492bced13 100644 --- a/core/bubbles/text_bubble.ts +++ b/core/bubbles/text_bubble.ts @@ -27,6 +27,7 @@ export class TextBubble extends Bubble { super(workspace, anchor, ownerRect); this.paragraph = this.stringToSvg(text, this.contentContainer); this.updateBubbleSize(); + dom.addClass(this.svgRoot, 'blocklyTextBubble'); } /** @returns the current text of this text bubble. */ From bef8d8319d3cfb2ce9514ec84fae5a81a3f17389 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 16 Jul 2024 15:47:43 -0700 Subject: [PATCH 013/102] refactor: make VariableModel implement IVariableModel. (#8381) * refactor: make VariableModel implement IVariableModel. * chore: assauge the linter. --- core/variable_model.ts | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/core/variable_model.ts b/core/variable_model.ts index 0728a3d56..c4ec05367 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -16,6 +16,7 @@ import './events/events_var_create.js'; import * as idGenerator from './utils/idgenerator.js'; import type {Workspace} from './workspace.js'; +import {IVariableModel} from './interfaces/i_variable_model.js'; /** * Class for a variable model. @@ -23,7 +24,7 @@ import type {Workspace} from './workspace.js'; * * @see {Blockly.FieldVariable} */ -export class VariableModel { +export class VariableModel implements IVariableModel { type: string; private readonly id_: string; @@ -64,6 +65,36 @@ export class VariableModel { return this.id_; } + /** @returns The name of this variable. */ + getName(): string { + return this.name; + } + + /** + * Updates the user-visible name of this variable. + * + * @returns The newly-updated variable. + */ + setName(newName: string): this { + this.name = newName; + return this; + } + + /** @returns The type of this variable. */ + getType(): string { + return this.type; + } + + /** + * Updates the type of this variable. + * + * @returns The newly-updated variable. + */ + setType(newType: string): this { + this.type = newType; + return this; + } + /** * A custom compare function for the VariableModel objects. * From 8cca066bcf7130f8c57890ec508decf7bbd0307b Mon Sep 17 00:00:00 2001 From: Devesh Rahatekar <79015420+devesh-2002@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:14:24 +0530 Subject: [PATCH 014/102] feat: Add a blocklyShadow class (#8336) * feat: Add blockShadow class * formatted the file --- core/renderers/common/path_object.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/renderers/common/path_object.ts b/core/renderers/common/path_object.ts index d5c0850a1..8ca8cd193 100644 --- a/core/renderers/common/path_object.ts +++ b/core/renderers/common/path_object.ts @@ -186,8 +186,11 @@ export class PathObject implements IPathObject { */ protected updateShadow_(shadow: boolean) { if (shadow) { + this.setClass_('blocklyShadow', true); this.svgPath.setAttribute('stroke', 'none'); this.svgPath.setAttribute('fill', this.style.colourSecondary); + } else { + this.setClass_('blocklyShadow', false); } } From 33b53718eb7193771327bd6e4b70b05381c0e946 Mon Sep 17 00:00:00 2001 From: Krishnakumar Chavan <58606754+krishchvn@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:45:36 -0400 Subject: [PATCH 015/102] fix!: renamed blocklyTreeIcon Css class to blocklyToolboxCategoryIcon #8347 (#8367) * renamed blocklyTreeIcon Css class to blocklyToolboxCategoryIcon * fix!: renamed blocklyTreeIcon Css class to blocklyToolboxCategoryIcon #8347 * fixed whitespace formatting --- core/toolbox/category.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index 2d0ea4aee..bbcb6bf6f 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -134,7 +134,7 @@ export class ToolboxCategory 'container': 'blocklyToolboxCategoryContainer', 'row': 'blocklyToolboxCategory', 'rowcontentcontainer': 'blocklyTreeRowContentContainer', - 'icon': 'blocklyTreeIcon', + 'icon': 'blocklyToolboxCategoryIcon', 'label': 'blocklyTreeLabel', 'contents': 'blocklyToolboxContents', 'selected': 'blocklyTreeSelected', @@ -684,7 +684,7 @@ Css.register(` padding-right: 0; } -.blocklyTreeIcon { +.blocklyToolboxCategoryIcon { background-image: url(<<>>/sprites.png); height: 16px; vertical-align: middle; From ae80adfe9cb51890241cff435c30416804da401a Mon Sep 17 00:00:00 2001 From: Arun Chandran <53257113+Arun-cn@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:48:14 +0530 Subject: [PATCH 016/102] fix!: Replace Closure UI CSS classes with Blockly CSS classes (#8339) * fix!: Replace Closure UI CSS classes with Blockly CSS classes * chore: remove comments about deprecated goog-x class * chore: remove deprecated goog-x classes * fix: correct coding format to pass CI checks --- core/menu.ts | 3 +-- core/menuitem.ts | 23 +++++++---------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/core/menu.ts b/core/menu.ts index b0fb55573..29615925b 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -85,8 +85,7 @@ export class Menu { */ render(container: Element): HTMLDivElement { const element = document.createElement('div'); - // goog-menu is deprecated, use blocklyMenu. May 2020. - element.className = 'blocklyMenu goog-menu blocklyNonSelectable'; + element.className = 'blocklyMenu blocklyNonSelectable'; element.tabIndex = 0; if (this.roleName) { aria.setRole(element, this.roleName); diff --git a/core/menuitem.ts b/core/menuitem.ts index aad914b68..7fff1a72b 100644 --- a/core/menuitem.ts +++ b/core/menuitem.ts @@ -64,22 +64,19 @@ export class MenuItem { this.element = element; // Set class and style - // goog-menuitem* is deprecated, use blocklyMenuItem*. May 2020. element.className = - 'blocklyMenuItem goog-menuitem ' + - (this.enabled ? '' : 'blocklyMenuItemDisabled goog-menuitem-disabled ') + - (this.checked ? 'blocklyMenuItemSelected goog-option-selected ' : '') + - (this.highlight - ? 'blocklyMenuItemHighlight goog-menuitem-highlight ' - : '') + - (this.rightToLeft ? 'blocklyMenuItemRtl goog-menuitem-rtl ' : ''); + 'blocklyMenuItem ' + + (this.enabled ? '' : 'blocklyMenuItemDisabled ') + + (this.checked ? 'blocklyMenuItemSelected ' : '') + + (this.highlight ? 'blocklyMenuItemHighlight ' : '') + + (this.rightToLeft ? 'blocklyMenuItemRtl ' : ''); const content = document.createElement('div'); - content.className = 'blocklyMenuItemContent goog-menuitem-content'; + content.className = 'blocklyMenuItemContent'; // Add a checkbox for checkable menu items. if (this.checkable) { const checkbox = document.createElement('div'); - checkbox.className = 'blocklyMenuItemCheckbox goog-menuitem-checkbox'; + checkbox.className = 'blocklyMenuItemCheckbox '; content.appendChild(checkbox); } @@ -188,19 +185,13 @@ export class MenuItem { */ setHighlighted(highlight: boolean) { this.highlight = highlight; - const el = this.getElement(); if (el && this.isEnabled()) { - // goog-menuitem-highlight is deprecated, use blocklyMenuItemHighlight. - // May 2020. const name = 'blocklyMenuItemHighlight'; - const nameDep = 'goog-menuitem-highlight'; if (highlight) { dom.addClass(el, name); - dom.addClass(el, nameDep); } else { dom.removeClass(el, name); - dom.removeClass(el, nameDep); } } } From e298f5541256d80c43989e2ee12efddb6ddf7c70 Mon Sep 17 00:00:00 2001 From: Chaitanya Yeole <77329060+ChaitanyaYeole02@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:19:53 -0400 Subject: [PATCH 017/102] feat: Added blocklyTrashcanFlyout CSS class (#8372) * feat: Add blocklyTrashcanFlyout class * Fixed formatting issues * fix: versioning reverted to original * fix: prettier version resolved * fix: clean installation --- core/trashcan.ts | 7 +- package-lock.json | 2749 +++++++++++++++++++++------------------------ 2 files changed, 1310 insertions(+), 1446 deletions(-) diff --git a/core/trashcan.ts b/core/trashcan.ts index 050f506a4..7caee837e 100644 --- a/core/trashcan.ts +++ b/core/trashcan.ts @@ -239,10 +239,9 @@ export class Trashcan /** Initializes the trash can. */ init() { if (this.workspace.options.maxTrashcanContents > 0) { - dom.insertAfter( - this.flyout!.createDom(Svg.SVG)!, - this.workspace.getParentSvg(), - ); + const flyoutDom = this.flyout!.createDom(Svg.SVG)!; + dom.addClass(flyoutDom, 'blocklyTrashcanFlyout'); + dom.insertAfter(flyoutDom, this.workspace.getParentSvg()); this.flyout!.init(this.workspace); } this.workspace.getComponentManager().addComponent({ diff --git a/package-lock.json b/package-lock.json index a5249e6b1..c809034eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -397,31 +397,6 @@ "node": ">=0.10.0" } }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -531,18 +506,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -836,64 +799,24 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", + "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", "dev": true, "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.0", + "proxy-agent": "6.3.1", "tar-fs": "3.0.4", "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" + "yargs": "17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" }, "engines": { "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@puppeteer/browsers/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@puppeteer/browsers/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" } }, "node_modules/@rushstack/node-core-library": { @@ -1173,18 +1096,18 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, "optional": true, "dependencies": { @@ -1682,18 +1605,6 @@ "node": "^16.13 || >=18" } }, - "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@wdio/logger": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", @@ -1709,18 +1620,6 @@ "node": "^16.13 || >=18" } }, - "node_modules/@wdio/logger/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/@wdio/logger/node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -1802,67 +1701,6 @@ "node": "^16.13 || >=18" } }, - "node_modules/@wdio/utils/node_modules/@puppeteer/browsers": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", - "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - } - }, - "node_modules/@wdio/utils/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/@wdio/utils/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wdio/utils/node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -1922,9 +1760,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dependencies": { "debug": "^4.3.4" }, @@ -2009,12 +1847,15 @@ } }, "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -2048,9 +1889,9 @@ "dev": true }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -2063,7 +1904,7 @@ "node_modules/append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, "dependencies": { "buffer-equal": "^1.0.0" @@ -2201,15 +2042,6 @@ "ieee754": "^1.2.1" } }, - "node_modules/archiver/node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/archiver/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -2258,7 +2090,7 @@ "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "node_modules/are-docs-informative": { @@ -2277,12 +2109,12 @@ "dev": true }, "node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "dequal": "^2.0.3" } }, "node_modules/arr-diff": { @@ -2297,7 +2129,7 @@ "node_modules/arr-filter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -2318,7 +2150,7 @@ "node_modules/arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -2339,7 +2171,7 @@ "node_modules/array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2348,7 +2180,7 @@ "node_modules/array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, "dependencies": { "array-slice": "^1.0.0", @@ -2358,15 +2190,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-initial/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-last": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", @@ -2379,15 +2202,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-last/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", @@ -2423,7 +2237,7 @@ "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2460,9 +2274,9 @@ } }, "node_modules/ast-types/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/async": { @@ -2486,15 +2300,21 @@ } }, "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] }, "node_modules/async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", "dev": true, "dependencies": { "async-done": "^1.2.2" @@ -2545,15 +2365,15 @@ } }, "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", "dev": true }, "node_modules/bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", "dev": true, "dependencies": { "arr-filter": "^1.1.1", @@ -2592,9 +2412,9 @@ "dev": true }, "node_modules/bare-events": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz", - "integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", "dev": true, "optional": true }, @@ -2658,7 +2478,7 @@ "node_modules/base/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -2700,9 +2520,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", - "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -2729,6 +2549,16 @@ "url": "https://bevry.me/fund" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/blockly": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.0.2.tgz", @@ -2910,12 +2740,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2952,21 +2782,24 @@ } }, "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, "engines": { - "node": "*" + "node": ">=8.0.0" } }, "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/buffer-from": { @@ -3044,13 +2877,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3065,6 +2904,15 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -3178,7 +3026,7 @@ "node_modules/class-utils/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -3187,66 +3035,17 @@ "node": ">=0.10.0" } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/cliui": { @@ -3313,7 +3112,7 @@ "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3322,7 +3121,7 @@ "node_modules/collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, "dependencies": { "arr-map": "^2.0.2", @@ -3336,7 +3135,7 @@ "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "dependencies": { "map-visit": "^1.0.0", @@ -3403,10 +3202,13 @@ } }, "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/compress-commons": { "version": "6.0.2", @@ -3610,7 +3412,7 @@ "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3744,6 +3546,26 @@ "node-fetch": "^2.6.12" } }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3814,18 +3636,18 @@ } }, "node_modules/dat.gui": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.7.tgz", - "integrity": "sha512-sRl/28gF/XRC5ywC9I4zriATTsQcpSsRG7seXCPnTkK8/EQMIbCu5NPMpICLGxX9ZEUvcXR3ArLYCtgreFoMDw==", + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz", + "integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==", "dev": true }, "node_modules/data-uri-to-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", - "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "dev": true, "engines": { - "node": ">= 14" + "node": ">= 12" } }, "node_modules/data-urls": { @@ -3916,12 +3738,15 @@ } }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decimal.js": { @@ -4004,7 +3829,7 @@ "node_modules/default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true, "engines": { "node": ">= 0.10" @@ -4019,16 +3844,38 @@ "node": ">=10" } }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -4066,10 +3913,19 @@ "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4226,27 +4082,6 @@ "edgedriver": "bin/edgedriver.js" } }, - "node_modules/edgedriver/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/edgedriver/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/edgedriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -4256,24 +4091,6 @@ "node": ">=16" } }, - "node_modules/edgedriver/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dev": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/edgedriver/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -4324,6 +4141,27 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -4331,14 +4169,19 @@ "dev": true }, "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, + "hasInstallScript": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/es6-iterator": { @@ -4591,6 +4434,27 @@ "node": ">=10.13.0" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esniff/node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4700,7 +4564,7 @@ "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "dependencies": { "debug": "^2.3.3", @@ -4727,7 +4591,7 @@ "node_modules/expand-brackets/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -4739,7 +4603,7 @@ "node_modules/expand-brackets/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -4748,72 +4612,23 @@ "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/expand-brackets/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4822,13 +4637,13 @@ "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1" @@ -4893,7 +4708,7 @@ "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -4905,7 +4720,7 @@ "node_modules/extglob/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -4917,7 +4732,7 @@ "node_modules/extglob/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4986,19 +4801,6 @@ "node": ">=8.6.0" } }, - "node_modules/fast-glob/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, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5029,7 +4831,7 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { "pend": "~1.2.0" @@ -5070,10 +4872,17 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -5107,19 +4916,6 @@ "micromatch": "^4.0.2" } }, - "node_modules/find-yarn-workspace-root/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, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/findup-sync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", @@ -5135,6 +4931,145 @@ "node": ">= 0.10" } }, + "node_modules/findup-sync/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", @@ -5261,9 +5196,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -5283,7 +5218,7 @@ "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5292,7 +5227,7 @@ "node_modules/for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "dependencies": { "for-in": "^1.0.1" @@ -5354,7 +5289,7 @@ "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "dependencies": { "map-cache": "^0.2.2" @@ -5398,7 +5333,7 @@ "node_modules/fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", "dev": true, "dependencies": { "graceful-fs": "^4.1.11", @@ -5408,37 +5343,26 @@ "node": ">= 0.10" } }, - "node_modules/fs-mkdirp-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/fs-mkdirp-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5449,9 +5373,9 @@ } }, "node_modules/geckodriver": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.1.tgz", - "integrity": "sha512-nnAdIrwLkMcDu4BitWXF23pEMeZZ0Cj7HaWWFdSpeedBP9z6ft150JYiGO2mwzw6UiR823Znk1JeIf07RyzloA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.2.tgz", + "integrity": "sha512-/JFJ7DJPJUvDhLjzQk+DwjlkAmiShddfRHhZ/xVL9FWbza5Bi3UMGmmerEKqD69JbRs7R81ZW31co686mdYZyA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5471,27 +5395,6 @@ "node": "^16.13 || >=18 || >=20" } }, - "node_modules/geckodriver/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/geckodriver/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/geckodriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -5501,22 +5404,14 @@ "node": ">=16" } }, - "node_modules/geckodriver/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/geckodriver/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/geckodriver/node_modules/tar-fs": { @@ -5567,14 +5462,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5607,57 +5507,58 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-stream/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/get-uri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", - "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dev": true, "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^5.0.1", + "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "fs-extra": "^11.2.0" }, "engines": { "node": ">= 14" } }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/get-uri/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/get-uri/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": ">=14.14" } }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5700,7 +5601,7 @@ "node_modules/glob-stream": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", "dev": true, "dependencies": { "extend": "^3.0.0", @@ -5722,6 +5623,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -5741,7 +5643,7 @@ "node_modules/glob-stream/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -5751,7 +5653,7 @@ "node_modules/glob-stream/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -5806,7 +5708,7 @@ "node_modules/glob-watcher/node_modules/anymatch/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -5860,11 +5762,23 @@ "node": ">=0.10.0" } }, + "node_modules/glob-watcher/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob-watcher/node_modules/chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", "dev": true, "dependencies": { "anymatch": "^2.0.0", @@ -5883,22 +5797,10 @@ "fsevents": "^1.2.7" } }, - "node_modules/glob-watcher/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-watcher/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "dependencies": { "extend-shallow": "^2.0.1", @@ -5910,10 +5812,41 @@ "node": ">=0.10.0" } }, + "node_modules/glob-watcher/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, "node_modules/glob-watcher/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -5923,7 +5856,7 @@ "node_modules/glob-watcher/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -5935,7 +5868,7 @@ "node_modules/glob-watcher/node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "dependencies": { "binary-extensions": "^1.0.0" @@ -5947,7 +5880,64 @@ "node_modules/glob-watcher/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5985,7 +5975,7 @@ "node_modules/glob-watcher/node_modules/to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -6036,7 +6026,7 @@ "node_modules/global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.2", @@ -6076,18 +6066,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6193,6 +6171,18 @@ "win32" ] }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "12.6.1", "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", @@ -6231,9 +6221,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/grapheme-splitter": { @@ -6310,10 +6300,10 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "node_modules/gulp-cli/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6322,7 +6312,7 @@ "node_modules/gulp-cli/node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -6330,15 +6320,11 @@ "wrap-ansi": "^2.0.0" } }, - "node_modules/gulp-cli/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "node_modules/gulp-cli/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, "engines": { "node": ">=0.10.0" } @@ -6349,16 +6335,10 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, - "node_modules/gulp-cli/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "node_modules/gulp-cli/node_modules/is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -6367,70 +6347,10 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/gulp-cli/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-cli/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-cli/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-cli/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/gulp-cli/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "dependencies": { "code-point-at": "^1.0.0", @@ -6444,7 +6364,7 @@ "node_modules/gulp-cli/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -6456,7 +6376,7 @@ "node_modules/gulp-cli/node_modules/wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -6517,31 +6437,6 @@ "node": ">= 0.10" } }, - "node_modules/gulp-concat/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/gulp-concat/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulp-gzip": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz", @@ -6571,31 +6466,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-gzip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/gulp-gzip/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulp-header": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz", @@ -6608,31 +6478,6 @@ "through2": "^2.0.0" } }, - "node_modules/gulp-header/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/gulp-header/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulp-insert": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/gulp-insert/-/gulp-insert-0.5.0.tgz", @@ -6772,21 +6617,6 @@ "node": ">=0.4.0" } }, - "node_modules/gulp-sourcemaps/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/gulp-sourcemaps/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6796,16 +6626,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-sourcemaps/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulp-umd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/gulp-umd/-/gulp-umd-2.0.0.tgz", @@ -6817,35 +6637,10 @@ "through2": "^2.0.3" } }, - "node_modules/gulp-umd/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/gulp-umd/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", "dev": true, "dependencies": { "glogg": "^1.0.0" @@ -6854,18 +6649,6 @@ "node": ">= 0.10" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6875,10 +6658,34 @@ "node": ">=8" } }, - "node_modules/has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -6890,7 +6697,7 @@ "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "dependencies": { "get-value": "^2.0.6", @@ -6904,7 +6711,7 @@ "node_modules/has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -6914,10 +6721,34 @@ "node": ">=0.10.0" } }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-values/node_modules/kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -6959,6 +6790,12 @@ "node": ">=0.10.0" } }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -7044,9 +6881,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -7179,16 +7016,29 @@ "node_modules/invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/is-absolute": { @@ -7205,30 +7055,21 @@ } }, "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "hasown": "^2.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "node_modules/is-binary-path": { @@ -7262,47 +7103,28 @@ } }, "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "hasown": "^2.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/is-docker": { @@ -7377,32 +7199,17 @@ "node_modules/is-negated-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, "engines": { "node": ">=0.10.0" } @@ -7416,6 +7223,18 @@ "node": ">=8" } }, + "node_modules/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, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -7487,13 +7306,13 @@ "node_modules/is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "node_modules/is-valid-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -7593,6 +7412,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", @@ -7877,7 +7702,7 @@ "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", "dev": true, "dependencies": { "default-resolution": "^2.0.0", @@ -7917,7 +7742,7 @@ "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, "dependencies": { "invert-kv": "^1.0.0" @@ -7929,7 +7754,7 @@ "node_modules/lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", "dev": true, "dependencies": { "flush-write-stream": "^1.0.2" @@ -7994,7 +7819,7 @@ "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -8007,18 +7832,6 @@ "node": ">=0.10.0" } }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/locate-app": { "version": "2.4.21", "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.4.21.tgz", @@ -8040,6 +7853,18 @@ "userhome": "1.0.0" } }, + "node_modules/locate-app/node_modules/type-fest": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz", + "integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8217,7 +8042,7 @@ "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8232,7 +8057,7 @@ "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "dependencies": { "object-visit": "^1.0.0" @@ -8253,7 +8078,7 @@ "node_modules/matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, "dependencies": { "findup-sync": "^2.0.0", @@ -8265,10 +8090,70 @@ "node": ">= 0.10.0" } }, + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, "dependencies": { "detect-file": "^1.0.0", @@ -8280,10 +8165,19 @@ "node": ">= 0.10" } }, + "node_modules/matchdep/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -8292,38 +8186,40 @@ "node": ">=0.10.0" } }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/memoizee/node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/matchdep/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/micromatch": { + "node_modules/matchdep/node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", @@ -8347,88 +8243,10 @@ "node": ">=0.10.0" } }, - "node_modules/micromatch/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { + "node_modules/matchdep/node_modules/to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -8438,6 +8256,44 @@ "node": ">=0.10.0" } }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -8725,6 +8581,13 @@ "node": ">= 0.10" } }, + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "dev": true, + "optional": true + }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -8784,9 +8647,9 @@ } }, "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true }, "node_modules/nise": { @@ -8822,23 +8685,42 @@ } }, "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" } }, "node_modules/normalize-path": { @@ -8877,7 +8759,7 @@ "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8900,7 +8782,7 @@ "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "dependencies": { "copy-descriptor": "^0.1.0", @@ -8914,7 +8796,7 @@ "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -8923,57 +8805,23 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8994,7 +8842,7 @@ "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "dependencies": { "isobject": "^3.0.0" @@ -9004,14 +8852,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -9024,7 +8872,7 @@ "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, "dependencies": { "array-each": "^1.0.1", @@ -9039,7 +8887,7 @@ "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -9052,7 +8900,7 @@ "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "dependencies": { "isobject": "^3.0.1" @@ -9064,7 +8912,7 @@ "node_modules/object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -9128,7 +8976,7 @@ "node_modules/ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "dependencies": { "readable-stream": "^2.0.1" @@ -9152,7 +9000,7 @@ "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, "dependencies": { "lcid": "^1.0.0" @@ -9210,9 +9058,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", - "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -9220,22 +9068,21 @@ "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.2" + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" }, "engines": { "node": ">= 14" } }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -9263,7 +9110,7 @@ "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -9287,6 +9134,18 @@ "node": ">= 18" } }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", @@ -9299,7 +9158,7 @@ "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9319,7 +9178,7 @@ "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9414,7 +9273,7 @@ "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, "node_modules/path-exists": { @@ -9453,7 +9312,7 @@ "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "dependencies": { "path-root-regex": "^0.1.0" @@ -9465,7 +9324,7 @@ "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9514,7 +9373,7 @@ "node_modules/path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -9537,7 +9396,7 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "node_modules/picocolors": { @@ -9561,7 +9420,7 @@ "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9570,7 +9429,7 @@ "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9579,7 +9438,7 @@ "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "dependencies": { "pinkie": "^2.0.0" @@ -9650,7 +9509,7 @@ "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9709,7 +9568,7 @@ "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", "dev": true, "engines": { "node": ">= 0.8" @@ -9740,19 +9599,19 @@ } }, "node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", + "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" + "socks-proxy-agent": "^8.0.2" }, "engines": { "node": ">= 14" @@ -9779,9 +9638,9 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -9799,16 +9658,6 @@ "pump": "^2.0.0" } }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9842,12 +9691,101 @@ } } }, + "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/puppeteer-core/node_modules/devtools-protocol": { "version": "0.0.1147663", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", "dev": true }, + "node_modules/puppeteer-core/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer-core/node_modules/proxy-agent": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/puppeteer-core/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -9915,6 +9853,58 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -9983,7 +9973,7 @@ "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "dependencies": { "resolve": "^1.1.6" @@ -10027,7 +10017,7 @@ "node_modules/remove-bom-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, "dependencies": { "remove-bom-buffer": "^3.0.0", @@ -10038,31 +10028,6 @@ "node": ">= 0.10" } }, - "node_modules/remove-bom-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/remove-bom-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -10081,7 +10046,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "engines": { "node": ">=0.10" @@ -10090,7 +10055,7 @@ "node_modules/replace-homedir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1", @@ -10157,7 +10122,7 @@ "node_modules/require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", "dev": true }, "node_modules/requires-port": { @@ -10191,7 +10156,7 @@ "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.0", @@ -10213,7 +10178,7 @@ "node_modules/resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", "dev": true, "dependencies": { "value-or-function": "^3.0.0" @@ -10225,7 +10190,7 @@ "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, @@ -10362,7 +10327,7 @@ "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "dependencies": { "ret": "~0.1.10" @@ -10408,7 +10373,7 @@ "node_modules/semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", "dev": true, "dependencies": { "sver-compat": "^1.5.0" @@ -10418,9 +10383,9 @@ } }, "node_modules/serialize-error": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.2.tgz", - "integrity": "sha512-o43i0jLcA0LXA5Uu+gI1Vj+lF66KR9IAcy0ThbGq1bAMPN+k5IgSHsulfnqf/ddKAz6dWf+k8PD5hAr9oCSHEQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, "dependencies": { "type-fest": "^2.12.2" @@ -10432,6 +10397,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -10444,9 +10421,26 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -10465,7 +10459,7 @@ "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -10477,7 +10471,7 @@ "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10631,7 +10625,7 @@ "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -10655,7 +10649,7 @@ "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -10676,7 +10670,7 @@ "node_modules/snapdragon/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -10688,7 +10682,7 @@ "node_modules/snapdragon/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -10697,72 +10691,23 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/snapdragon/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10771,13 +10716,14 @@ "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/snapdragon/node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, "dependencies": { "atob": "^2.1.2", @@ -10788,39 +10734,33 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -10834,6 +10774,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, "dependencies": { "atob": "^2.1.2", @@ -10844,6 +10785,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, "node_modules/spacetrim": { @@ -10878,9 +10820,9 @@ "dev": true }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -10939,7 +10881,7 @@ "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "dev": true, "engines": { "node": "*" @@ -10948,7 +10890,7 @@ "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "dependencies": { "define-property": "^0.2.5", @@ -10961,7 +10903,7 @@ "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -10970,66 +10912,17 @@ "node": ">=0.10.0" } }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/stream-exhaust": { @@ -11039,9 +10932,9 @@ "dev": true }, "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "dev": true }, "node_modules/stream-to-array": { @@ -11196,7 +11089,7 @@ "node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, "dependencies": { "is-utf8": "^0.2.0" @@ -11253,7 +11146,7 @@ "node_modules/sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", "dev": true, "dependencies": { "es6-iterator": "^2.0.1", @@ -11298,10 +11191,20 @@ "tar-stream": "^3.1.5" } }, + "node_modules/tar-fs/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/tar-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", - "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "dependencies": { "b4a": "^1.6.4", @@ -11310,9 +11213,9 @@ } }, "node_modules/text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "dev": true, "dependencies": { "b4a": "^1.6.4" @@ -11342,6 +11245,16 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/through2-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", @@ -11352,7 +11265,7 @@ "xtend": "~4.0.0" } }, - "node_modules/through2-filter/node_modules/readable-stream": { + "node_modules/through2/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", @@ -11367,16 +11280,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/through2-filter/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", @@ -11411,7 +11314,7 @@ "node_modules/to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -11424,7 +11327,7 @@ "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -11436,7 +11339,7 @@ "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -11484,7 +11387,7 @@ "node_modules/to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", "dev": true, "dependencies": { "through2": "^2.0.3" @@ -11493,31 +11396,6 @@ "node": ">= 0.10" } }, - "node_modules/to-through/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/to-through/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/tough-cookie": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", @@ -11601,12 +11479,12 @@ } }, "node_modules/type-fest": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz", - "integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=12.20" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11644,7 +11522,7 @@ "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11674,7 +11552,7 @@ "node_modules/undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", "dev": true, "engines": { "node": ">= 0.10" @@ -11683,13 +11561,13 @@ "node_modules/undertaker/node_modules/fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", "dev": true }, "node_modules/undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -11728,7 +11606,7 @@ "node_modules/union-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11756,7 +11634,7 @@ "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "dependencies": { "has-value": "^0.3.1", @@ -11769,7 +11647,7 @@ "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "dependencies": { "get-value": "^2.0.3", @@ -11783,7 +11661,7 @@ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "dependencies": { "isarray": "1.0.0" @@ -11795,7 +11673,7 @@ "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11823,7 +11701,7 @@ "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, @@ -11900,7 +11778,7 @@ "node_modules/value-or-function": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", "dev": true, "engines": { "node": ">= 0.10" @@ -11966,20 +11844,10 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/vinyl-fs/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", "dev": true, "dependencies": { "append-buffer": "^1.0.2", @@ -11997,7 +11865,7 @@ "node_modules/vinyl-sourcemap/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -12084,9 +11952,9 @@ } }, "node_modules/webdriverio": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", - "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", + "version": "8.39.1", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.1.tgz", + "integrity": "sha512-dPwLgLNtP+l4vnybz+YFxxH8nBKOP7j6VVzKtfDyTLDQg9rz3U8OA4xMMQCBucnrVXy3KcKxGqlnMa+c4IfWCQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", @@ -12136,22 +12004,10 @@ "balanced-match": "^1.0.0" } }, - "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", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/webdriverio/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -12225,7 +12081,7 @@ "node_modules/which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", "dev": true }, "node_modules/workerpool": { @@ -12434,13 +12290,22 @@ "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, + "node_modules/yauzl/node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", From a2a57496940383c40f3b4d60c6a4a68204f6abce Mon Sep 17 00:00:00 2001 From: Shreyans Pathak Date: Wed, 17 Jul 2024 13:24:09 -0400 Subject: [PATCH 018/102] feat: Add css classes from json block definitions (#8377) * fix: override `jsonInit` method to add css classes * fix: lint * refactor: simplify logic --- core/block_svg.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index adef213d5..a5b7f8d10 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -1720,4 +1720,16 @@ export class BlockSvg traverseJson(json as unknown as {[key: string]: unknown}); return [json]; } + + override jsonInit(json: AnyDuringMigration): void { + super.jsonInit(json); + + if (json['classes']) { + this.addClass( + Array.isArray(json['classes']) + ? json['classes'].join(' ') + : json['classes'], + ); + } + } } From e1753ae066395f799d7929df4e23204ec3944096 Mon Sep 17 00:00:00 2001 From: Ruthwik Chikoti <145591715+ruthwikchikoti@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:08:29 +0530 Subject: [PATCH 019/102] fix!: Renamed the blocklyToolboxContents CSS class to blocklyToolboxCategoryGroup (#8384) --- core/toolbox/category.ts | 2 +- core/toolbox/collapsible_category.ts | 2 +- core/toolbox/toolbox.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index bbcb6bf6f..b47ba657c 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -136,7 +136,7 @@ export class ToolboxCategory 'rowcontentcontainer': 'blocklyTreeRowContentContainer', 'icon': 'blocklyToolboxCategoryIcon', 'label': 'blocklyTreeLabel', - 'contents': 'blocklyToolboxContents', + 'contents': 'blocklyToolboxCategoryGroup', 'selected': 'blocklyTreeSelected', 'openicon': 'blocklyTreeIconOpen', 'closedicon': 'blocklyTreeIconClosed', diff --git a/core/toolbox/collapsible_category.ts b/core/toolbox/collapsible_category.ts index faea8edcb..1a30a1c81 100644 --- a/core/toolbox/collapsible_category.ts +++ b/core/toolbox/collapsible_category.ts @@ -58,7 +58,7 @@ export class CollapsibleToolboxCategory override makeDefaultCssConfig_() { const cssConfig = super.makeDefaultCssConfig_(); - cssConfig['contents'] = 'blocklyToolboxContents'; + cssConfig['contents'] = 'blocklyToolboxCategoryGroup'; return cssConfig; } diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index e0fb62e23..ac4a7da91 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -209,7 +209,7 @@ export class Toolbox */ protected createContentsContainer_(): HTMLDivElement { const contentsContainer = document.createElement('div'); - dom.addClass(contentsContainer, 'blocklyToolboxContents'); + dom.addClass(contentsContainer, 'blocklyToolboxCategoryGroup'); if (this.isHorizontal()) { contentsContainer.style.flexDirection = 'row'; } @@ -1111,13 +1111,13 @@ Css.register(` -webkit-tap-highlight-color: transparent; /* issue #1345 */ } -.blocklyToolboxContents { +.blocklyToolboxCategoryGroup { display: flex; flex-wrap: wrap; flex-direction: column; } -.blocklyToolboxContents:focus { +.blocklyToolboxCategoryGroup:focus { outline: none; } `); From 0a1524f57702e90bfc5e772812e9a2bd94e1eb6c Mon Sep 17 00:00:00 2001 From: Suryansh Shakya <83297944+nullHawk@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:15:11 +0530 Subject: [PATCH 020/102] feat: added blocklyToolboxFlyout CSS class to the flyout (#8386) --- core/toolbox/toolbox.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index ac4a7da91..1e2a5970f 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -143,7 +143,9 @@ export class Toolbox this.flyout_ = this.createFlyout_(); this.HtmlDiv = this.createDom_(this.workspace_); - dom.insertAfter(this.flyout_.createDom('svg'), svg); + const flyoutDom = this.flyout_.createDom('svg'); + dom.addClass(flyoutDom, 'blocklyToolboxFlyout'); + dom.insertAfter(flyoutDom, svg); this.setVisible(true); this.flyout_.init(workspace); From 9fa4b2c9664bd50017f5a971eefbf6fcbdb5a20e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 18 Jul 2024 17:22:25 +0000 Subject: [PATCH 021/102] chore: fix package-lock --- package-lock.json | 2757 ++++++++++++++++++++++++--------------------- 1 file changed, 1446 insertions(+), 1311 deletions(-) diff --git a/package-lock.json b/package-lock.json index c809034eb..a5249e6b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -397,6 +397,31 @@ "node": ">=0.10.0" } }, + "node_modules/@gulp-sourcemaps/map-sources/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@gulp-sourcemaps/map-sources/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -506,6 +531,18 @@ "node": ">=12" } }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -799,24 +836,64 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", - "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", "dev": true, "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", + "proxy-agent": "6.3.0", "tar-fs": "3.0.4", "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "yargs": "17.7.1" }, "bin": { "browsers": "lib/cjs/main-cli.js" }, "engines": { "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@puppeteer/browsers/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, "node_modules/@rushstack/node-core-library": { @@ -1096,18 +1173,18 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.11", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", - "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "dependencies": { @@ -1605,6 +1682,18 @@ "node": "^16.13 || >=18" } }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@wdio/logger": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", @@ -1620,6 +1709,18 @@ "node": "^16.13 || >=18" } }, + "node_modules/@wdio/logger/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/@wdio/logger/node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -1701,6 +1802,67 @@ "node": "^16.13 || >=18" } }, + "node_modules/@wdio/utils/node_modules/@puppeteer/browsers": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", + "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.1", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + } + }, + "node_modules/@wdio/utils/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/@wdio/utils/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wdio/utils/node_modules/proxy-agent": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -1760,9 +1922,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dependencies": { "debug": "^4.3.4" }, @@ -1847,15 +2009,12 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=0.10.0" } }, "node_modules/ansi-styles": { @@ -1889,9 +2048,9 @@ "dev": true }, "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1904,7 +2063,7 @@ "node_modules/append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "dependencies": { "buffer-equal": "^1.0.0" @@ -2042,6 +2201,15 @@ "ieee754": "^1.2.1" } }, + "node_modules/archiver/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/archiver/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -2090,7 +2258,7 @@ "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "node_modules/are-docs-informative": { @@ -2109,12 +2277,12 @@ "dev": true }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", "dev": true, - "dependencies": { - "dequal": "^2.0.3" + "engines": { + "node": ">=6.0" } }, "node_modules/arr-diff": { @@ -2129,7 +2297,7 @@ "node_modules/arr-filter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -2150,7 +2318,7 @@ "node_modules/arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -2171,7 +2339,7 @@ "node_modules/array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "dev": true, "engines": { "node": ">=0.10.0" @@ -2180,7 +2348,7 @@ "node_modules/array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", "dev": true, "dependencies": { "array-slice": "^1.0.0", @@ -2190,6 +2358,15 @@ "node": ">=0.10.0" } }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-last": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", @@ -2202,6 +2379,15 @@ "node": ">=0.10.0" } }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", @@ -2237,7 +2423,7 @@ "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true, "engines": { "node": ">=0.10.0" @@ -2274,9 +2460,9 @@ } }, "node_modules/ast-types/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/async": { @@ -2300,21 +2486,15 @@ } }, "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true }, "node_modules/async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", "dev": true, "dependencies": { "async-done": "^1.2.2" @@ -2365,15 +2545,15 @@ } }, "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", "dev": true }, "node_modules/bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", "dev": true, "dependencies": { "arr-filter": "^1.1.1", @@ -2412,9 +2592,9 @@ "dev": true }, "node_modules/bare-events": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", - "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz", + "integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==", "dev": true, "optional": true }, @@ -2478,7 +2658,7 @@ "node_modules/base/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -2520,9 +2700,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", "dev": true, "engines": { "node": ">=10.0.0" @@ -2549,16 +2729,6 @@ "url": "https://bevry.me/fund" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/blockly": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.0.2.tgz", @@ -2740,12 +2910,12 @@ } }, "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { - "fill-range": "^7.1.1" + "fill-range": "^7.0.1" }, "engines": { "node": ">=8" @@ -2782,24 +2952,21 @@ } }, "node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true, "engines": { - "node": ">=8.0.0" + "node": "*" } }, "node_modules/buffer-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", - "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true, "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.0" } }, "node_modules/buffer-from": { @@ -2877,19 +3044,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2904,15 +3065,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -3026,7 +3178,7 @@ "node_modules/class-utils/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -3035,17 +3187,66 @@ "node": ">=0.10.0" } }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/cliui": { @@ -3112,7 +3313,7 @@ "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "engines": { "node": ">=0.10.0" @@ -3121,7 +3322,7 @@ "node_modules/collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", "dev": true, "dependencies": { "arr-map": "^2.0.2", @@ -3135,7 +3336,7 @@ "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "dependencies": { "map-visit": "^1.0.0", @@ -3202,13 +3403,10 @@ } }, "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true }, "node_modules/compress-commons": { "version": "6.0.2", @@ -3412,7 +3610,7 @@ "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true, "engines": { "node": ">=0.10.0" @@ -3546,26 +3744,6 @@ "node-fetch": "^2.6.12" } }, - "node_modules/cross-fetch/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3636,18 +3814,18 @@ } }, "node_modules/dat.gui": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz", - "integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==", + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.7.tgz", + "integrity": "sha512-sRl/28gF/XRC5ywC9I4zriATTsQcpSsRG7seXCPnTkK8/EQMIbCu5NPMpICLGxX9ZEUvcXR3ArLYCtgreFoMDw==", "dev": true }, "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", + "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", "dev": true, "engines": { - "node": ">= 12" + "node": ">= 14" } }, "node_modules/data-urls": { @@ -3738,15 +3916,12 @@ } }, "node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/decimal.js": { @@ -3829,7 +4004,7 @@ "node_modules/default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", "dev": true, "engines": { "node": ">= 0.10" @@ -3844,38 +4019,16 @@ "node": ">=10" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "object-keys": "^1.0.12" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -3913,19 +4066,10 @@ "node": ">=0.4.0" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true, "engines": { "node": ">=0.10.0" @@ -4082,6 +4226,27 @@ "edgedriver": "bin/edgedriver.js" } }, + "node_modules/edgedriver/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/edgedriver/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/edgedriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -4091,6 +4256,24 @@ "node": ">=16" } }, + "node_modules/edgedriver/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/edgedriver/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -4141,27 +4324,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -4169,19 +4331,14 @@ "dev": true }, "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", "dev": true, - "hasInstallScript": true, "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" } }, "node_modules/es6-iterator": { @@ -4434,27 +4591,6 @@ "node": ">=10.13.0" } }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esniff/node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4564,7 +4700,7 @@ "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "dependencies": { "debug": "^2.3.3", @@ -4591,7 +4727,7 @@ "node_modules/expand-brackets/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -4603,7 +4739,7 @@ "node_modules/expand-brackets/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -4612,23 +4748,72 @@ "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/expand-brackets/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -4637,13 +4822,13 @@ "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1" @@ -4708,7 +4893,7 @@ "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -4720,7 +4905,7 @@ "node_modules/extglob/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -4732,7 +4917,7 @@ "node_modules/extglob/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -4801,6 +4986,19 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/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, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4831,7 +5029,7 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "dependencies": { "pend": "~1.2.0" @@ -4872,17 +5070,10 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -4916,6 +5107,19 @@ "micromatch": "^4.0.2" } }, + "node_modules/find-yarn-workspace-root/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, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/findup-sync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", @@ -4931,145 +5135,6 @@ "node": ">= 0.10" } }, - "node_modules/findup-sync/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", @@ -5196,9 +5261,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "dev": true, "funding": [ { @@ -5218,7 +5283,7 @@ "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true, "engines": { "node": ">=0.10.0" @@ -5227,7 +5292,7 @@ "node_modules/for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "dependencies": { "for-in": "^1.0.1" @@ -5289,7 +5354,7 @@ "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "dependencies": { "map-cache": "^0.2.2" @@ -5333,7 +5398,7 @@ "node_modules/fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", "dev": true, "dependencies": { "graceful-fs": "^4.1.11", @@ -5343,26 +5408,37 @@ "node": ">= 0.10" } }, + "node_modules/fs-mkdirp-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5373,9 +5449,9 @@ } }, "node_modules/geckodriver": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.2.tgz", - "integrity": "sha512-/JFJ7DJPJUvDhLjzQk+DwjlkAmiShddfRHhZ/xVL9FWbza5Bi3UMGmmerEKqD69JbRs7R81ZW31co686mdYZyA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.1.tgz", + "integrity": "sha512-nnAdIrwLkMcDu4BitWXF23pEMeZZ0Cj7HaWWFdSpeedBP9z6ft150JYiGO2mwzw6UiR823Znk1JeIf07RyzloA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5395,6 +5471,27 @@ "node": "^16.13 || >=18 || >=20" } }, + "node_modules/geckodriver/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/geckodriver/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/geckodriver/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -5404,14 +5501,22 @@ "node": ">=16" } }, - "node_modules/geckodriver/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/geckodriver/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dev": true, "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/geckodriver/node_modules/tar-fs": { @@ -5462,19 +5567,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5507,58 +5607,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-stream/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/get-uri": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", - "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", + "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", "dev": true, "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", + "data-uri-to-buffer": "^5.0.1", "debug": "^4.3.4", - "fs-extra": "^11.2.0" + "fs-extra": "^8.1.0" }, "engines": { "node": ">= 14" } }, - "node_modules/get-uri/node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/get-uri/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=14.14" + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/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/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true, "engines": { "node": ">=0.10.0" @@ -5601,7 +5700,7 @@ "node_modules/glob-stream": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "dependencies": { "extend": "^3.0.0", @@ -5623,7 +5722,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -5643,7 +5741,7 @@ "node_modules/glob-stream/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -5653,7 +5751,7 @@ "node_modules/glob-stream/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -5708,7 +5806,7 @@ "node_modules/glob-watcher/node_modules/anymatch/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -5762,23 +5860,11 @@ "node": ">=0.10.0" } }, - "node_modules/glob-watcher/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-watcher/node_modules/chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", "dev": true, "dependencies": { "anymatch": "^2.0.0", @@ -5797,10 +5883,22 @@ "fsevents": "^1.2.7" } }, + "node_modules/glob-watcher/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob-watcher/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "dependencies": { "extend-shallow": "^2.0.1", @@ -5812,41 +5910,10 @@ "node": ">=0.10.0" } }, - "node_modules/glob-watcher/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, "node_modules/glob-watcher/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -5856,7 +5923,7 @@ "node_modules/glob-watcher/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -5868,7 +5935,7 @@ "node_modules/glob-watcher/node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "dependencies": { "binary-extensions": "^1.0.0" @@ -5880,64 +5947,7 @@ "node_modules/glob-watcher/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -5975,7 +5985,7 @@ "node_modules/glob-watcher/node_modules/to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -6026,7 +6036,7 @@ "node_modules/global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "dependencies": { "expand-tilde": "^2.0.2", @@ -6066,6 +6076,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6171,18 +6193,6 @@ "win32" ] }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/got": { "version": "12.6.1", "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", @@ -6221,9 +6231,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/grapheme-splitter": { @@ -6300,10 +6310,10 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "node_modules/gulp-cli/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", "dev": true, "engines": { "node": ">=0.10.0" @@ -6312,7 +6322,7 @@ "node_modules/gulp-cli/node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -6320,11 +6330,15 @@ "wrap-ansi": "^2.0.0" } }, - "node_modules/gulp-cli/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "node_modules/gulp-cli/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, "engines": { "node": ">=0.10.0" } @@ -6335,10 +6349,16 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "node_modules/gulp-cli/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/gulp-cli/node_modules/is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -6347,10 +6367,70 @@ "node": ">=0.10.0" } }, + "node_modules/gulp-cli/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/gulp-cli/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-cli/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/gulp-cli/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "dependencies": { "code-point-at": "^1.0.0", @@ -6364,7 +6444,7 @@ "node_modules/gulp-cli/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -6376,7 +6456,7 @@ "node_modules/gulp-cli/node_modules/wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -6437,6 +6517,31 @@ "node": ">= 0.10" } }, + "node_modules/gulp-concat/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-concat/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/gulp-gzip": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz", @@ -6466,6 +6571,31 @@ "node": ">=0.10.0" } }, + "node_modules/gulp-gzip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-gzip/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/gulp-header": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz", @@ -6478,6 +6608,31 @@ "through2": "^2.0.0" } }, + "node_modules/gulp-header/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-header/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/gulp-insert": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/gulp-insert/-/gulp-insert-0.5.0.tgz", @@ -6617,6 +6772,21 @@ "node": ">=0.4.0" } }, + "node_modules/gulp-sourcemaps/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/gulp-sourcemaps/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6626,6 +6796,16 @@ "node": ">=0.10.0" } }, + "node_modules/gulp-sourcemaps/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/gulp-umd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/gulp-umd/-/gulp-umd-2.0.0.tgz", @@ -6637,10 +6817,35 @@ "through2": "^2.0.3" } }, + "node_modules/gulp-umd/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-umd/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "dependencies": { "glogg": "^1.0.0" @@ -6649,6 +6854,18 @@ "node": ">= 0.10" } }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6658,34 +6875,10 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true, "engines": { "node": ">= 0.4" @@ -6697,7 +6890,7 @@ "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "dependencies": { "get-value": "^2.0.6", @@ -6711,7 +6904,7 @@ "node_modules/has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -6721,34 +6914,10 @@ "node": ">=0.10.0" } }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-values/node_modules/kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -6790,12 +6959,6 @@ "node": ">=0.10.0" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -6881,9 +7044,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -7016,29 +7179,16 @@ "node_modules/invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "node_modules/ip": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true }, "node_modules/is-absolute": { @@ -7055,21 +7205,30 @@ } }, "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "node_modules/is-binary-path": { @@ -7103,28 +7262,47 @@ } }, "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-docker": { @@ -7199,17 +7377,32 @@ "node_modules/is-negated-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { "node": ">=0.10.0" } @@ -7223,18 +7416,6 @@ "node": ">=8" } }, - "node_modules/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, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -7306,13 +7487,13 @@ "node_modules/is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "node_modules/is-valid-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", "dev": true, "engines": { "node": ">=0.10.0" @@ -7412,12 +7593,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true - }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", @@ -7702,7 +7877,7 @@ "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", "dev": true, "dependencies": { "default-resolution": "^2.0.0", @@ -7742,7 +7917,7 @@ "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "dependencies": { "invert-kv": "^1.0.0" @@ -7754,7 +7929,7 @@ "node_modules/lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", "dev": true, "dependencies": { "flush-write-stream": "^1.0.2" @@ -7819,7 +7994,7 @@ "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -7832,6 +8007,18 @@ "node": ">=0.10.0" } }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/locate-app": { "version": "2.4.21", "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.4.21.tgz", @@ -7853,18 +8040,6 @@ "userhome": "1.0.0" } }, - "node_modules/locate-app/node_modules/type-fest": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz", - "integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8042,7 +8217,7 @@ "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true, "engines": { "node": ">=0.10.0" @@ -8057,7 +8232,7 @@ "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "dependencies": { "object-visit": "^1.0.0" @@ -8078,7 +8253,7 @@ "node_modules/matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", "dev": true, "dependencies": { "findup-sync": "^2.0.0", @@ -8090,70 +8265,10 @@ "node": ">= 0.10.0" } }, - "node_modules/matchdep/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", "dev": true, "dependencies": { "detect-file": "^1.0.0", @@ -8165,19 +8280,10 @@ "node": ">= 0.10" } }, - "node_modules/matchdep/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -8186,40 +8292,38 @@ "node": ">=0.10.0" } }, - "node_modules/matchdep/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", "dev": true, "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" } }, - "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } + "node_modules/memoizee/node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true }, - "node_modules/matchdep/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/matchdep/node_modules/micromatch": { + "node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", @@ -8243,10 +8347,88 @@ "node": ">=0.10.0" } }, - "node_modules/matchdep/node_modules/to-regex-range": { + "node_modules/micromatch/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -8256,44 +8438,6 @@ "node": ">=0.10.0" } }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -8581,13 +8725,6 @@ "node": ">= 0.10" } }, - "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "dev": true, - "optional": true - }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -8647,9 +8784,9 @@ } }, "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, "node_modules/nise": { @@ -8685,42 +8822,23 @@ } }, "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "whatwg-url": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "4.x || >=6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/normalize-path": { @@ -8759,7 +8877,7 @@ "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "engines": { "node": ">=0.10.0" @@ -8782,7 +8900,7 @@ "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "dependencies": { "copy-descriptor": "^0.1.0", @@ -8796,7 +8914,7 @@ "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -8805,23 +8923,57 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8842,7 +8994,7 @@ "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "dependencies": { "isobject": "^3.0.0" @@ -8852,14 +9004,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", "object-keys": "^1.1.1" }, "engines": { @@ -8872,7 +9024,7 @@ "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "dependencies": { "array-each": "^1.0.1", @@ -8887,7 +9039,7 @@ "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -8900,7 +9052,7 @@ "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "dependencies": { "isobject": "^3.0.1" @@ -8912,7 +9064,7 @@ "node_modules/object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -8976,7 +9128,7 @@ "node_modules/ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "dev": true, "dependencies": { "readable-stream": "^2.0.1" @@ -9000,7 +9152,7 @@ "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "dependencies": { "lcid": "^1.0.0" @@ -9058,9 +9210,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", - "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", "dev": true, "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -9068,21 +9220,22 @@ "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.5", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.4" + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { "node": ">= 14" } }, "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", "dev": true, "dependencies": { "degenerator": "^5.0.0", + "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -9110,7 +9263,7 @@ "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -9134,18 +9287,6 @@ "node": ">= 18" } }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", @@ -9158,7 +9299,7 @@ "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9178,7 +9319,7 @@ "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9273,7 +9414,7 @@ "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", "dev": true }, "node_modules/path-exists": { @@ -9312,7 +9453,7 @@ "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "dependencies": { "path-root-regex": "^0.1.0" @@ -9324,7 +9465,7 @@ "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9373,7 +9514,7 @@ "node_modules/path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -9396,7 +9537,7 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, "node_modules/picocolors": { @@ -9420,7 +9561,7 @@ "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9429,7 +9570,7 @@ "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9438,7 +9579,7 @@ "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "dependencies": { "pinkie": "^2.0.0" @@ -9509,7 +9650,7 @@ "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true, "engines": { "node": ">=0.10.0" @@ -9568,7 +9709,7 @@ "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true, "engines": { "node": ">= 0.8" @@ -9599,19 +9740,19 @@ } }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.0", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", + "pac-proxy-agent": "^7.0.0", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "socks-proxy-agent": "^8.0.1" }, "engines": { "node": ">= 14" @@ -9638,9 +9779,9 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -9658,6 +9799,16 @@ "pump": "^2.0.0" } }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9691,101 +9842,12 @@ } } }, - "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/puppeteer-core/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/puppeteer-core/node_modules/devtools-protocol": { "version": "0.0.1147663", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", "dev": true }, - "node_modules/puppeteer-core/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/puppeteer-core/node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/puppeteer-core/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -9853,58 +9915,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -9973,7 +9983,7 @@ "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "dependencies": { "resolve": "^1.1.6" @@ -10017,7 +10027,7 @@ "node_modules/remove-bom-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "dependencies": { "remove-bom-buffer": "^3.0.0", @@ -10028,6 +10038,31 @@ "node": ">= 0.10" } }, + "node_modules/remove-bom-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -10046,7 +10081,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true, "engines": { "node": ">=0.10" @@ -10055,7 +10090,7 @@ "node_modules/replace-homedir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1", @@ -10122,7 +10157,7 @@ "node_modules/require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "node_modules/requires-port": { @@ -10156,7 +10191,7 @@ "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "dependencies": { "expand-tilde": "^2.0.0", @@ -10178,7 +10213,7 @@ "node_modules/resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", "dev": true, "dependencies": { "value-or-function": "^3.0.0" @@ -10190,7 +10225,7 @@ "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, @@ -10327,7 +10362,7 @@ "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "dependencies": { "ret": "~0.1.10" @@ -10373,7 +10408,7 @@ "node_modules/semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", "dev": true, "dependencies": { "sver-compat": "^1.5.0" @@ -10383,9 +10418,9 @@ } }, "node_modules/serialize-error": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", - "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.2.tgz", + "integrity": "sha512-o43i0jLcA0LXA5Uu+gI1Vj+lF66KR9IAcy0ThbGq1bAMPN+k5IgSHsulfnqf/ddKAz6dWf+k8PD5hAr9oCSHEQ==", "dev": true, "dependencies": { "type-fest": "^2.12.2" @@ -10397,18 +10432,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -10421,26 +10444,9 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -10459,7 +10465,7 @@ "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -10471,7 +10477,7 @@ "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -10625,7 +10631,7 @@ "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -10649,7 +10655,7 @@ "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -10670,7 +10676,7 @@ "node_modules/snapdragon/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -10682,7 +10688,7 @@ "node_modules/snapdragon/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -10691,23 +10697,72 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/snapdragon/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -10716,14 +10771,13 @@ "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "node_modules/snapdragon/node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, "dependencies": { "atob": "^2.1.2", @@ -10734,33 +10788,39 @@ } }, "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "dependencies": { - "ip-address": "^9.0.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.0.0", + "node": ">= 10.13.0", "npm": ">= 3.0.0" } }, "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", "dev": true, "dependencies": { - "agent-base": "^7.1.1", + "agent-base": "^7.0.2", "debug": "^4.3.4", - "socks": "^2.8.3" + "socks": "^2.7.1" }, "engines": { "node": ">= 14" } }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "dev": true + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -10774,7 +10834,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, "dependencies": { "atob": "^2.1.2", @@ -10785,7 +10844,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, "node_modules/spacetrim": { @@ -10820,9 +10878,9 @@ "dev": true }, "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -10881,7 +10939,7 @@ "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true, "engines": { "node": "*" @@ -10890,7 +10948,7 @@ "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "dependencies": { "define-property": "^0.2.5", @@ -10903,7 +10961,7 @@ "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -10912,17 +10970,66 @@ "node": ">=0.10.0" } }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/stream-exhaust": { @@ -10932,9 +11039,9 @@ "dev": true }, "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, "node_modules/stream-to-array": { @@ -11089,7 +11196,7 @@ "node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "dependencies": { "is-utf8": "^0.2.0" @@ -11146,7 +11253,7 @@ "node_modules/sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", "dev": true, "dependencies": { "es6-iterator": "^2.0.1", @@ -11191,20 +11298,10 @@ "tar-stream": "^3.1.5" } }, - "node_modules/tar-fs/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", "dev": true, "dependencies": { "b4a": "^1.6.4", @@ -11213,9 +11310,9 @@ } }, "node_modules/text-decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", - "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", "dev": true, "dependencies": { "b4a": "^1.6.4" @@ -11245,16 +11342,6 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/through2-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", @@ -11265,7 +11352,7 @@ "xtend": "~4.0.0" } }, - "node_modules/through2/node_modules/readable-stream": { + "node_modules/through2-filter/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", @@ -11280,6 +11367,16 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/through2-filter/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", @@ -11314,7 +11411,7 @@ "node_modules/to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -11327,7 +11424,7 @@ "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -11339,7 +11436,7 @@ "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -11387,7 +11484,7 @@ "node_modules/to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", "dev": true, "dependencies": { "through2": "^2.0.3" @@ -11396,6 +11493,31 @@ "node": ">= 0.10" } }, + "node_modules/to-through/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/to-through/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/tough-cookie": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", @@ -11479,12 +11601,12 @@ } }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz", + "integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11522,7 +11644,7 @@ "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true, "engines": { "node": ">=0.10.0" @@ -11552,7 +11674,7 @@ "node_modules/undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", "dev": true, "engines": { "node": ">= 0.10" @@ -11561,13 +11683,13 @@ "node_modules/undertaker/node_modules/fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", "dev": true }, "node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -11606,7 +11728,7 @@ "node_modules/union-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true, "engines": { "node": ">=0.10.0" @@ -11634,7 +11756,7 @@ "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "dependencies": { "has-value": "^0.3.1", @@ -11647,7 +11769,7 @@ "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "dependencies": { "get-value": "^2.0.3", @@ -11661,7 +11783,7 @@ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "dependencies": { "isarray": "1.0.0" @@ -11673,7 +11795,7 @@ "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true, "engines": { "node": ">=0.10.0" @@ -11701,7 +11823,7 @@ "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, @@ -11778,7 +11900,7 @@ "node_modules/value-or-function": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", "dev": true, "engines": { "node": ">= 0.10" @@ -11844,10 +11966,20 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/vinyl-fs/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "dependencies": { "append-buffer": "^1.0.2", @@ -11865,7 +11997,7 @@ "node_modules/vinyl-sourcemap/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -11952,9 +12084,9 @@ } }, "node_modules/webdriverio": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.1.tgz", - "integrity": "sha512-dPwLgLNtP+l4vnybz+YFxxH8nBKOP7j6VVzKtfDyTLDQg9rz3U8OA4xMMQCBucnrVXy3KcKxGqlnMa+c4IfWCQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", @@ -12004,10 +12136,22 @@ "balanced-match": "^1.0.0" } }, + "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", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webdriverio/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -12081,7 +12225,7 @@ "node_modules/which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", "dev": true }, "node_modules/workerpool": { @@ -12290,22 +12434,13 @@ "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, - "node_modules/yauzl/node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", From 32f8e2433777bffd6a931f7177b768a90c10bcd8 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 18 Jul 2024 11:01:22 -0700 Subject: [PATCH 022/102] refactor: update the variable interfaces. (#8388) --- core/interfaces/i_variable_map.ts | 17 +++-------- core/interfaces/i_variable_model.ts | 33 +++++++++++++++++++- core/registry.ts | 14 +++++++++ core/serialization/variables.ts | 47 ++++++++--------------------- core/variable_model.ts | 35 +++++++++++++++++++-- 5 files changed, 97 insertions(+), 49 deletions(-) diff --git a/core/interfaces/i_variable_map.ts b/core/interfaces/i_variable_map.ts index 0bfc532a7..6c21aa8e0 100644 --- a/core/interfaces/i_variable_map.ts +++ b/core/interfaces/i_variable_map.ts @@ -4,8 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {IVariableModel} from './i_variable_model.js'; -import {State} from '../serialization/variables.js'; +import type {IVariableModel, IVariableState} from './i_variable_model.js'; /** * Variable maps are container objects responsible for storing and managing the @@ -14,7 +13,7 @@ import {State} from '../serialization/variables.js'; * Any of these methods may define invariants about which names and types are * legal, and throw if they are not met. */ -export interface IVariableMap { +export interface IVariableMap> { /* Returns the variable corresponding to the given ID, or null if none. */ getVariableById(id: string): T | null; @@ -46,6 +45,9 @@ export interface IVariableMap { */ createVariable(name: string, id?: string, type?: string | null): T; + /* Adds a variable to this variable map. */ + addVariable(variable: T): void; + /** * Changes the name of the given variable to the name provided and returns the * renamed variable. @@ -60,13 +62,4 @@ export interface IVariableMap { /* Removes all variables from this variable map. */ clear(): void; - - /* Returns an object representing the serialized state of the variable. */ - saveVariable(variable: T): U; - - /** - * Creates a variable in this variable map corresponding to the given state - * (produced by a call to `saveVariable`). - */ - loadVariable(state: U): T; } diff --git a/core/interfaces/i_variable_model.ts b/core/interfaces/i_variable_model.ts index 97fa9161d..791b10725 100644 --- a/core/interfaces/i_variable_model.ts +++ b/core/interfaces/i_variable_model.ts @@ -4,8 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import type {Workspace} from '../workspace.js'; + /* Representation of a variable. */ -export interface IVariableModel { +export interface IVariableModel { /* Returns the unique ID of this variable. */ getId(): string; @@ -23,4 +25,33 @@ export interface IVariableModel { /* Sets the type of this variable. */ setType(type: string): this; + + getWorkspace(): Workspace; + + /* Serializes this variable */ + save(): T; +} + +export interface IVariableModelStatic { + new ( + workspace: Workspace, + name: string, + type?: string, + id?: string, + ): IVariableModel; + + /** + * Creates a new IVariableModel corresponding to the given state on the + * specified workspace. This method must be static in your implementation. + */ + load(state: T, workspace: Workspace): IVariableModel; +} + +/** + * Represents the state of a given variable. + */ +export interface IVariableState { + name: string; + id: string; + type?: string; } diff --git a/core/registry.ts b/core/registry.ts index d46c36f48..c7e16e935 100644 --- a/core/registry.ts +++ b/core/registry.ts @@ -24,6 +24,12 @@ import type {IPaster} from './interfaces/i_paster.js'; import type {ICopyData, ICopyable} from './interfaces/i_copyable.js'; import type {IConnectionPreviewer} from './interfaces/i_connection_previewer.js'; import type {IDragger} from './interfaces/i_dragger.js'; +import type { + IVariableModel, + IVariableModelStatic, + IVariableState, +} from './interfaces/i_variable_model.js'; +import type {IVariableMap} from './interfaces/i_variable_map.js'; /** * A map of maps. With the keys being the type and name of the class we are @@ -109,6 +115,14 @@ export class Type<_T> { /** @internal */ static PASTER = new Type>>('paster'); + + static VARIABLE_MODEL = new Type>( + 'variableModel', + ); + + static VARIABLE_MAP = new Type>>( + 'variableMap', + ); } /** diff --git a/core/serialization/variables.ts b/core/serialization/variables.ts index 69c6cda8c..62a52c41f 100644 --- a/core/serialization/variables.ts +++ b/core/serialization/variables.ts @@ -7,20 +7,13 @@ // Former goog.module ID: Blockly.serialization.variables import type {ISerializer} from '../interfaces/i_serializer.js'; +import type {IVariableState} from '../interfaces/i_variable_model.js'; import type {Workspace} from '../workspace.js'; import * as priorities from './priorities.js'; +import * as registry from '../registry.js'; import * as serializationRegistry from './registry.js'; -/** - * Represents the state of a given variable. - */ -export interface State { - name: string; - id: string; - type: string | undefined; -} - /** * Serializer for saving and loading variable state. */ @@ -40,23 +33,9 @@ export class VariableSerializer implements ISerializer { * @returns The state of the workspace's variables, or null if there are no * variables. */ - save(workspace: Workspace): State[] | null { - const variableStates = []; - for (const variable of workspace.getAllVariables()) { - const state = { - 'name': variable.name, - 'id': variable.getId(), - }; - if (variable.type) { - (state as AnyDuringMigration)['type'] = variable.type; - } - variableStates.push(state); - } - // AnyDuringMigration because: Type '{ name: string; id: string; }[] | - // null' is not assignable to type 'State[] | null'. - return ( - variableStates.length ? variableStates : null - ) as AnyDuringMigration; + save(workspace: Workspace): IVariableState[] | null { + const variableStates = workspace.getAllVariables().map((v) => v.save()); + return variableStates.length ? variableStates : null; } /** @@ -66,14 +45,14 @@ export class VariableSerializer implements ISerializer { * @param state The state of the variables to deserialize. * @param workspace The workspace to deserialize into. */ - load(state: State[], workspace: Workspace) { - for (const varState of state) { - workspace.createVariable( - varState['name'], - varState['type'], - varState['id'], - ); - } + load(state: IVariableState[], workspace: Workspace) { + const VariableModel = registry.getObject( + registry.Type.VARIABLE_MODEL, + registry.DEFAULT, + ); + state.forEach((s) => { + VariableModel?.load(s, workspace); + }); } /** diff --git a/core/variable_model.ts b/core/variable_model.ts index c4ec05367..017b02c60 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -15,8 +15,9 @@ import './events/events_var_create.js'; import * as idGenerator from './utils/idgenerator.js'; +import * as registry from './registry.js'; import type {Workspace} from './workspace.js'; -import {IVariableModel} from './interfaces/i_variable_model.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; /** * Class for a variable model. @@ -24,7 +25,7 @@ import {IVariableModel} from './interfaces/i_variable_model.js'; * * @see {Blockly.FieldVariable} */ -export class VariableModel implements IVariableModel { +export class VariableModel implements IVariableModel { type: string; private readonly id_: string; @@ -95,6 +96,30 @@ export class VariableModel implements IVariableModel { return this; } + getWorkspace(): Workspace { + return this.workspace; + } + + save(): IVariableState { + const state: IVariableState = { + 'name': this.getName(), + 'id': this.getId(), + }; + const type = this.getType(); + if (type) { + state['type'] = type; + } + + return state; + } + + static load(state: IVariableState, workspace: Workspace) { + // TODO(adodson): Once VariableMap implements IVariableMap, directly + // construct a variable, retrieve the variable map from the workspace, + // add the variable to that variable map, and fire a VAR_CREATE event. + workspace.createVariable(state['name'], state['type'], state['id']); + } + /** * A custom compare function for the VariableModel objects. * @@ -108,3 +133,9 @@ export class VariableModel implements IVariableModel { return var1.name.localeCompare(var2.name, undefined, {sensitivity: 'base'}); } } + +registry.register( + registry.Type.VARIABLE_MODEL, + registry.DEFAULT, + VariableModel, +); From 02e64bebbe986fd05cd753fefdefd853a66ca16f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 19 Jul 2024 10:53:16 -0700 Subject: [PATCH 023/102] refactor: make VariableMap implement IVariableMap. (#8395) * refactor: make VariableMap implement IVariableMap. * chore: remove unused arrayUtils import. * chore: fix comment on variable map backing store. * chore: Added JSDoc to new VariableMap methods. * chore: Improve test descriptions. --- core/variable_map.ts | 148 ++++++++++++++++++------------- core/variables.ts | 6 +- core/workspace.ts | 8 +- tests/mocha/variable_map_test.js | 73 +++++++++++++-- 4 files changed, 164 insertions(+), 71 deletions(-) diff --git a/core/variable_map.ts b/core/variable_map.ts index bc19b07a5..b8e2e4e0a 100644 --- a/core/variable_map.ts +++ b/core/variable_map.ts @@ -19,25 +19,26 @@ import './events/events_var_rename.js'; import type {Block} from './block.js'; import * as dialog from './dialog.js'; import * as eventUtils from './events/utils.js'; +import * as registry from './registry.js'; import {Msg} from './msg.js'; import {Names} from './names.js'; -import * as arrayUtils from './utils/array.js'; import * as idGenerator from './utils/idgenerator.js'; import {VariableModel} from './variable_model.js'; import type {Workspace} from './workspace.js'; +import type {IVariableMap} from './interfaces/i_variable_map.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. */ -export class VariableMap { +export class VariableMap implements IVariableMap { /** - * A map from variable type to list of variable names. The lists contain + * A map from variable type to map of IDs to variables. The maps contain * all of the named variables in the workspace, including variables that are * not currently in use. */ - private variableMap = new Map(); + private variableMap = new Map>(); /** @param workspace The workspace this map belongs to. */ constructor(public workspace: Workspace) {} @@ -45,8 +46,8 @@ export class VariableMap { /** Clear the variable map. Fires events for every deletion. */ clear() { for (const variables of this.variableMap.values()) { - while (variables.length > 0) { - this.deleteVariable(variables[0]); + for (const variable of variables.values()) { + this.deleteVariable(variable); } } if (this.variableMap.size !== 0) { @@ -60,10 +61,10 @@ export class VariableMap { * * @param variable Variable to rename. * @param newName New variable name. - * @internal + * @returns The newly renamed variable. */ - renameVariable(variable: VariableModel, newName: string) { - if (variable.name === newName) return; + renameVariable(variable: VariableModel, newName: string): VariableModel { + if (variable.name === newName) return variable; const type = variable.type; const conflictVar = this.getVariable(newName, type); const blocks = this.workspace.getAllBlocks(false); @@ -87,6 +88,20 @@ export class VariableMap { } finally { eventUtils.setGroup(existingGroup); } + return variable; + } + + changeVariableType(variable: VariableModel, newType: string): VariableModel { + this.variableMap.get(variable.getType())?.delete(variable.getId()); + variable.setType(newType); + const newTypeVariables = + this.variableMap.get(newType) ?? new Map(); + newTypeVariables.set(variable.getId(), variable); + if (!this.variableMap.has(newType)) { + this.variableMap.set(newType, newTypeVariables); + } + + return variable; } /** @@ -159,8 +174,8 @@ export class VariableMap { } // Finally delete the original variable, which is now unreferenced. eventUtils.fire(new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); - // And remove it from the list. - arrayUtils.removeElem(this.variableMap.get(type)!, variable); + // And remove it from the map. + this.variableMap.get(type)?.delete(variable.getId()); } /* End functions for renaming variables. */ @@ -177,8 +192,8 @@ export class VariableMap { */ createVariable( name: string, - opt_type?: string | null, - opt_id?: string | null, + opt_type?: string, + opt_id?: string, ): VariableModel { let variable = this.getVariable(name, opt_type); if (variable) { @@ -204,20 +219,30 @@ export class VariableMap { const type = opt_type || ''; variable = new VariableModel(this.workspace, name, type, id); - const variables = this.variableMap.get(type) || []; - variables.push(variable); - // Delete the list of variables of this type, and re-add it so that - // the most recent addition is at the end. - // This is used so the toolbox's set block is set to the most recent - // variable. - this.variableMap.delete(type); - this.variableMap.set(type, variables); - + const variables = + this.variableMap.get(type) ?? new Map(); + variables.set(variable.getId(), variable); + if (!this.variableMap.has(type)) { + this.variableMap.set(type, variables); + } eventUtils.fire(new (eventUtils.get(eventUtils.VAR_CREATE))(variable)); return variable; } + /** + * Adds the given variable to this variable map. + * + * @param variable The variable to add. + */ + addVariable(variable: VariableModel) { + const type = variable.getType(); + if (!this.variableMap.has(type)) { + this.variableMap.set(type, new Map()); + } + this.variableMap.get(type)?.set(variable.getId(), variable); + } + /* Begin functions for variable deletion. */ /** * Delete a variable. @@ -225,22 +250,12 @@ export class VariableMap { * @param variable Variable to delete. */ deleteVariable(variable: VariableModel) { - const variableId = variable.getId(); - const variableList = this.variableMap.get(variable.type); - if (variableList) { - for (let i = 0; i < variableList.length; i++) { - const tempVar = variableList[i]; - if (tempVar.getId() === variableId) { - variableList.splice(i, 1); - eventUtils.fire( - new (eventUtils.get(eventUtils.VAR_DELETE))(variable), - ); - if (variableList.length === 0) { - this.variableMap.delete(variable.type); - } - return; - } - } + const variables = this.variableMap.get(variable.type); + if (!variables || !variables.has(variable.getId())) return; + variables.delete(variable.getId()); + eventUtils.fire(new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); + if (variables.size === 0) { + this.variableMap.delete(variable.type); } } @@ -321,17 +336,16 @@ export class VariableMap { * the empty string, which is a specific type. * @returns The variable with the given name, or null if it was not found. */ - getVariable(name: string, opt_type?: string | null): VariableModel | null { + getVariable(name: string, opt_type?: string): VariableModel | null { const type = opt_type || ''; - const list = this.variableMap.get(type); - if (list) { - for (let j = 0, variable; (variable = list[j]); j++) { - if (Names.equals(variable.name, name)) { - return variable; - } - } - } - return null; + const variables = this.variableMap.get(type); + if (!variables) return null; + + return ( + [...variables.values()].find((variable) => + Names.equals(variable.getName(), name), + ) ?? null + ); } /** @@ -342,10 +356,8 @@ export class VariableMap { */ getVariableById(id: string): VariableModel | null { for (const variables of this.variableMap.values()) { - for (const variable of variables) { - if (variable.getId() === id) { - return variable; - } + if (variables.has(id)) { + return variables.get(id) ?? null; } } return null; @@ -361,11 +373,19 @@ export class VariableMap { */ getVariablesOfType(type: string | null): VariableModel[] { type = type || ''; - const variableList = this.variableMap.get(type); - if (variableList) { - return variableList.slice(); - } - return []; + const variables = this.variableMap.get(type); + if (!variables) return []; + + return [...variables.values()]; + } + + /** + * Returns a list of unique types of variables in this variable map. + * + * @returns A list of unique types of variables in this variable map. + */ + getTypes(): string[] { + return [...this.variableMap.keys()]; } /** @@ -399,7 +419,7 @@ export class VariableMap { getAllVariables(): VariableModel[] { let allVariables: VariableModel[] = []; for (const variables of this.variableMap.values()) { - allVariables = allVariables.concat(variables); + allVariables = allVariables.concat(...variables.values()); } return allVariables; } @@ -410,9 +430,13 @@ export class VariableMap { * @returns All of the variable names of all types. */ getAllVariableNames(): string[] { - return Array.from(this.variableMap.values()) - .flat() - .map((variable) => variable.name); + const names: string[] = []; + for (const variables of this.variableMap.values()) { + for (const variable of variables.values()) { + names.push(variable.getName()); + } + } + return names; } /** @@ -438,3 +462,5 @@ export class VariableMap { return uses; } } + +registry.register(registry.Type.VARIABLE_MAP, registry.DEFAULT, VariableMap); diff --git a/core/variables.ts b/core/variables.ts index dee53a72b..da9d28bff 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -610,7 +610,11 @@ function createVariable( // Create a potential variable if in the flyout. let variable = null; if (potentialVariableMap) { - variable = potentialVariableMap.createVariable(opt_name, opt_type, id); + variable = potentialVariableMap.createVariable( + opt_name, + opt_type, + id ?? undefined, + ); } else { // In the main workspace, create a real variable. variable = workspace.createVariable(opt_name, opt_type, id); diff --git a/core/workspace.ts b/core/workspace.ts index 16f32611b..71a2e4af9 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -400,7 +400,11 @@ export class Workspace implements IASTNodeLocation { opt_type?: string | null, opt_id?: string | null, ): VariableModel { - return this.variableMap.createVariable(name, opt_type, opt_id); + return this.variableMap.createVariable( + name, + opt_type ?? undefined, + opt_id ?? undefined, + ); } /** @@ -456,7 +460,7 @@ export class Workspace implements IASTNodeLocation { * if none are found. */ getVariablesOfType(type: string | null): VariableModel[] { - return this.variableMap.getVariablesOfType(type); + return this.variableMap.getVariablesOfType(type ?? ''); } /** diff --git a/tests/mocha/variable_map_test.js b/tests/mocha/variable_map_test.js index c3d75e8a5..13a474245 100644 --- a/tests/mocha/variable_map_test.js +++ b/tests/mocha/variable_map_test.js @@ -39,17 +39,17 @@ suite('Variable Map', function () { this.variableMap.createVariable('name1', 'type1', 'id1'); // Assert there is only one variable in the this.variableMap. - let keys = Array.from(this.variableMap.variableMap.keys()); + let keys = this.variableMap.getTypes(); assert.equal(keys.length, 1); - let varMapLength = this.variableMap.variableMap.get(keys[0]).length; + let varMapLength = this.variableMap.getVariablesOfType(keys[0]).length; assert.equal(varMapLength, 1); this.variableMap.createVariable('name1', 'type1'); assertVariableValues(this.variableMap, 'name1', 'type1', 'id1'); // Check that the size of the variableMap did not change. - keys = Array.from(this.variableMap.variableMap.keys()); + keys = this.variableMap.getTypes(); assert.equal(keys.length, 1); - varMapLength = this.variableMap.variableMap.get(keys[0]).length; + varMapLength = this.variableMap.getVariablesOfType(keys[0]).length; assert.equal(varMapLength, 1); }); @@ -59,16 +59,16 @@ suite('Variable Map', function () { this.variableMap.createVariable('name1', 'type1', 'id1'); // Assert there is only one variable in the this.variableMap. - let keys = Array.from(this.variableMap.variableMap.keys()); + let keys = this.variableMap.getTypes(); assert.equal(keys.length, 1); - const varMapLength = this.variableMap.variableMap.get(keys[0]).length; + const varMapLength = this.variableMap.getVariablesOfType(keys[0]).length; assert.equal(varMapLength, 1); this.variableMap.createVariable('name1', 'type2', 'id2'); assertVariableValues(this.variableMap, 'name1', 'type1', 'id1'); assertVariableValues(this.variableMap, 'name1', 'type2', 'id2'); // Check that the size of the variableMap did change. - keys = Array.from(this.variableMap.variableMap.keys()); + keys = this.variableMap.getTypes(); assert.equal(keys.length, 2); }); @@ -246,6 +246,65 @@ suite('Variable Map', function () { }); }); + suite( + 'Using changeVariableType to change the type of a variable', + function () { + test('updates it to a new non-empty value', function () { + const variable = this.variableMap.createVariable( + 'name1', + 'type1', + 'id1', + ); + this.variableMap.changeVariableType(variable, 'type2'); + const oldTypeVariables = this.variableMap.getVariablesOfType('type1'); + const newTypeVariables = this.variableMap.getVariablesOfType('type2'); + assert.deepEqual(oldTypeVariables, []); + assert.deepEqual(newTypeVariables, [variable]); + assert.equal(variable.getType(), 'type2'); + }); + + test('updates it to a new empty value', function () { + const variable = this.variableMap.createVariable( + 'name1', + 'type1', + 'id1', + ); + this.variableMap.changeVariableType(variable, ''); + const oldTypeVariables = this.variableMap.getVariablesOfType('type1'); + const newTypeVariables = this.variableMap.getVariablesOfType(''); + assert.deepEqual(oldTypeVariables, []); + assert.deepEqual(newTypeVariables, [variable]); + assert.equal(variable.getType(), ''); + }); + }, + ); + + suite('addVariable', function () { + test('normally', function () { + const variable = new Blockly.VariableModel(this.workspace, 'foo', 'int'); + assert.isNull(this.variableMap.getVariableById(variable.getId())); + this.variableMap.addVariable(variable); + assert.equal( + this.variableMap.getVariableById(variable.getId()), + variable, + ); + }); + }); + + suite('getTypes', function () { + test('when map is empty', function () { + const types = this.variableMap.getTypes(); + assert.deepEqual(types, []); + }); + + test('with various types', function () { + this.variableMap.createVariable('name1', 'type1', 'id1'); + this.variableMap.createVariable('name2', '', 'id2'); + const types = this.variableMap.getTypes(); + assert.deepEqual(types, ['type1', '']); + }); + }); + suite('getAllVariables', function () { test('Trivial', function () { const var1 = this.variableMap.createVariable('name1', 'type1', 'id1'); From 294ef74d1bac10873297161c66e37e96f19d43ff Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 19 Jul 2024 14:58:04 -0700 Subject: [PATCH 024/102] refactor: Use IVariableModel instead of VariableModel. (#8400) * refactor: Use IVariableModel methods instead of directly accessing properties. * refactor: replace references to VariableModel with IVariableModel. --- blocks/loops.ts | 2 +- blocks/procedures.ts | 47 ++++++---- blocks/variables_dynamic.ts | 4 +- core/block.ts | 9 +- core/events/events_var_base.ts | 9 +- core/events/events_var_create.ts | 11 ++- core/events/events_var_delete.ts | 11 ++- core/events/events_var_rename.ts | 9 +- core/field_variable.ts | 44 +++++----- .../i_variable_backed_parameter_model.ts | 4 +- core/names.ts | 2 +- core/serialization/blocks.ts | 7 +- core/variable_map.ts | 86 +++++++++++++------ core/variable_model.ts | 10 ++- core/variables.ts | 81 +++++++++++------ core/variables_dynamic.ts | 3 +- core/workspace.ts | 18 ++-- core/workspace_svg.ts | 7 +- core/xml.ts | 15 ++-- generators/php/procedures.ts | 2 +- generators/python/procedures.ts | 2 +- tests/mocha/xml_test.js | 6 ++ 22 files changed, 248 insertions(+), 141 deletions(-) diff --git a/blocks/loops.ts b/blocks/loops.ts index c7cb710d7..5835ab8be 100644 --- a/blocks/loops.ts +++ b/blocks/loops.ts @@ -269,7 +269,7 @@ const CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = { } const varField = this.getField('VAR') as FieldVariable; const variable = varField.getVariable()!; - const varName = variable.name; + const varName = variable.getName(); if (!this.isCollapsed() && varName !== null) { const getVarBlockState = { type: 'variables_get', diff --git a/blocks/procedures.ts b/blocks/procedures.ts index 1214eb55e..583ca9d20 100644 --- a/blocks/procedures.ts +++ b/blocks/procedures.ts @@ -32,7 +32,10 @@ import {FieldTextInput} from '../core/field_textinput.js'; import {Msg} from '../core/msg.js'; import {MutatorIcon as Mutator} from '../core/icons/mutator_icon.js'; import {Names} from '../core/names.js'; -import type {VariableModel} from '../core/variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../core/interfaces/i_variable_model.js'; import type {Workspace} from '../core/workspace.js'; import type {WorkspaceSvg} from '../core/workspace_svg.js'; import {config} from '../core/config.js'; @@ -48,7 +51,7 @@ export const blocks: {[key: string]: BlockDefinition} = {}; type ProcedureBlock = Block & ProcedureMixin; interface ProcedureMixin extends ProcedureMixinType { arguments_: string[]; - argumentVarModels_: VariableModel[]; + argumentVarModels_: IVariableModel[]; callType_: string; paramIds_: string[]; hasStatements_: boolean; @@ -128,7 +131,7 @@ const PROCEDURE_DEF_COMMON = { for (let i = 0; i < this.argumentVarModels_.length; i++) { const parameter = xmlUtils.createElement('arg'); const argModel = this.argumentVarModels_[i]; - parameter.setAttribute('name', argModel.name); + parameter.setAttribute('name', argModel.getName()); parameter.setAttribute('varid', argModel.getId()); if (opt_paramIds && this.paramIds_) { parameter.setAttribute('paramId', this.paramIds_[i]); @@ -196,7 +199,7 @@ const PROCEDURE_DEF_COMMON = { state['params'].push({ // We don't need to serialize the name, but just in case we decide // to separate params from variables. - 'name': this.argumentVarModels_[i].name, + 'name': this.argumentVarModels_[i].getName(), 'id': this.argumentVarModels_[i].getId(), }); } @@ -224,7 +227,7 @@ const PROCEDURE_DEF_COMMON = { param['name'], '', ); - this.arguments_.push(variable.name); + this.arguments_.push(variable.getName()); this.argumentVarModels_.push(variable); } } @@ -352,7 +355,9 @@ const PROCEDURE_DEF_COMMON = { * * @returns List of variable models. */ - getVarModels: function (this: ProcedureBlock): VariableModel[] { + getVarModels: function ( + this: ProcedureBlock, + ): IVariableModel[] { return this.argumentVarModels_; }, /** @@ -370,23 +375,23 @@ const PROCEDURE_DEF_COMMON = { newId: string, ) { const oldVariable = this.workspace.getVariableById(oldId)!; - if (oldVariable.type !== '') { + if (oldVariable.getType() !== '') { // Procedure arguments always have the empty type. return; } - const oldName = oldVariable.name; + const oldName = oldVariable.getName(); const newVar = this.workspace.getVariableById(newId)!; let change = false; for (let i = 0; i < this.argumentVarModels_.length; i++) { if (this.argumentVarModels_[i].getId() === oldId) { - this.arguments_[i] = newVar.name; + this.arguments_[i] = newVar.getName(); this.argumentVarModels_[i] = newVar; change = true; } } if (change) { - this.displayRenamedVar_(oldName, newVar.name); + this.displayRenamedVar_(oldName, newVar.getName()); Procedures.mutateCallers(this); } }, @@ -398,9 +403,9 @@ const PROCEDURE_DEF_COMMON = { */ updateVarName: function ( this: ProcedureBlock & BlockSvg, - variable: VariableModel, + variable: IVariableModel, ) { - const newName = variable.name; + const newName = variable.getName(); let change = false; let oldName; for (let i = 0; i < this.argumentVarModels_.length; i++) { @@ -473,12 +478,16 @@ const PROCEDURE_DEF_COMMON = { const getVarBlockState = { type: 'variables_get', fields: { - VAR: {name: argVar.name, id: argVar.getId(), type: argVar.type}, + VAR: { + name: argVar.getName(), + id: argVar.getId(), + type: argVar.getType(), + }, }, }; options.push({ enabled: true, - text: Msg['VARIABLES_SET_CREATE_GET'].replace('%1', argVar.name), + text: Msg['VARIABLES_SET_CREATE_GET'].replace('%1', argVar.getName()), callback: ContextMenu.callbackFactory(this, getVarBlockState), }); } @@ -623,7 +632,7 @@ type ArgumentMixinType = typeof PROCEDURES_MUTATORARGUMENT; // TODO(#6920): This is kludgy. type FieldTextInputForArgument = FieldTextInput & { oldShowEditorFn_(_e?: Event, quietInput?: boolean): void; - createdVariables_: VariableModel[]; + createdVariables_: IVariableModel[]; }; const PROCEDURES_MUTATORARGUMENT = { @@ -708,7 +717,7 @@ const PROCEDURES_MUTATORARGUMENT = { } let model = outerWs.getVariable(varName, ''); - if (model && model.name !== varName) { + if (model && model.getName() !== varName) { // Rename the variable (case change) outerWs.renameVariableById(model.getId(), varName); } @@ -739,7 +748,7 @@ const PROCEDURES_MUTATORARGUMENT = { } for (let i = 0; i < this.createdVariables_.length; i++) { const model = this.createdVariables_[i]; - if (model.name !== newText) { + if (model.getName() !== newText) { outerWs.deleteVariableById(model.getId()); } } @@ -750,7 +759,7 @@ blocks['procedures_mutatorarg'] = PROCEDURES_MUTATORARGUMENT; /** Type of a block using the PROCEDURE_CALL_COMMON mixin. */ type CallBlock = Block & CallMixin; interface CallMixin extends CallMixinType { - argumentVarModels_: VariableModel[]; + argumentVarModels_: IVariableModel[]; arguments_: string[]; defType_: string; quarkIds_: string[] | null; @@ -1029,7 +1038,7 @@ const PROCEDURE_CALL_COMMON = { * * @returns List of variable models. */ - getVarModels: function (this: CallBlock): VariableModel[] { + getVarModels: function (this: CallBlock): IVariableModel[] { return this.argumentVarModels_; }, /** diff --git a/blocks/variables_dynamic.ts b/blocks/variables_dynamic.ts index e74cae423..ff94d8c96 100644 --- a/blocks/variables_dynamic.ts +++ b/blocks/variables_dynamic.ts @@ -144,9 +144,9 @@ const CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = { const id = this.getFieldValue('VAR'); const variableModel = Variables.getVariable(this.workspace, id)!; if (this.type === 'variables_get_dynamic') { - this.outputConnection!.setCheck(variableModel.type); + this.outputConnection!.setCheck(variableModel.getType()); } else { - this.getInput('VALUE')!.connection!.setCheck(variableModel.type); + this.getInput('VALUE')!.connection!.setCheck(variableModel.getType()); } }, }; diff --git a/core/block.ts b/core/block.ts index 52191d63c..c08b75a69 100644 --- a/core/block.ts +++ b/core/block.ts @@ -45,7 +45,10 @@ import * as idGenerator from './utils/idgenerator.js'; import * as parsing from './utils/parsing.js'; import * as registry from './registry.js'; import {Size} from './utils/size.js'; -import type {VariableModel} from './variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import type {Workspace} from './workspace.js'; import {DummyInput} from './inputs/dummy_input.js'; import {EndRowInput} from './inputs/end_row_input.js'; @@ -1133,7 +1136,7 @@ export class Block implements IASTNodeLocation { * @returns List of variable models. * @internal */ - getVarModels(): VariableModel[] { + getVarModels(): IVariableModel[] { const vars = []; for (let i = 0, input; (input = this.inputList[i]); i++) { for (let j = 0, field; (field = input.fieldRow[j]); j++) { @@ -1159,7 +1162,7 @@ export class Block implements IASTNodeLocation { * @param variable The variable being renamed. * @internal */ - updateVarName(variable: VariableModel) { + updateVarName(variable: IVariableModel) { for (let i = 0, input; (input = this.inputList[i]); i++) { for (let j = 0, field; (field = input.fieldRow[j]); j++) { if ( diff --git a/core/events/events_var_base.ts b/core/events/events_var_base.ts index 74537f144..1ec59ac6c 100644 --- a/core/events/events_var_base.ts +++ b/core/events/events_var_base.ts @@ -11,7 +11,10 @@ */ // Former goog.module ID: Blockly.Events.VarBase -import type {VariableModel} from '../variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; import { Abstract as AbstractEvent, @@ -31,13 +34,13 @@ export class VarBase extends AbstractEvent { * @param opt_variable The variable this event corresponds to. Undefined for * a blank event. */ - constructor(opt_variable?: VariableModel) { + constructor(opt_variable?: IVariableModel) { super(); this.isBlank = typeof opt_variable === 'undefined'; if (!opt_variable) return; this.varId = opt_variable.getId(); - this.workspaceId = opt_variable.workspace.id; + this.workspaceId = opt_variable.getWorkspace().id; } /** diff --git a/core/events/events_var_create.ts b/core/events/events_var_create.ts index a719cad98..0685b8ad8 100644 --- a/core/events/events_var_create.ts +++ b/core/events/events_var_create.ts @@ -12,7 +12,10 @@ // Former goog.module ID: Blockly.Events.VarCreate import * as registry from '../registry.js'; -import type {VariableModel} from '../variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; import {VarBase, VarBaseJson} from './events_var_base.js'; import * as eventUtils from './utils.js'; @@ -33,14 +36,14 @@ export class VarCreate extends VarBase { /** * @param opt_variable The created variable. Undefined for a blank event. */ - constructor(opt_variable?: VariableModel) { + constructor(opt_variable?: IVariableModel) { super(opt_variable); if (!opt_variable) { return; // Blank event to be populated by fromJson. } - this.varType = opt_variable.type; - this.varName = opt_variable.name; + this.varType = opt_variable.getType(); + this.varName = opt_variable.getName(); } /** diff --git a/core/events/events_var_delete.ts b/core/events/events_var_delete.ts index fc19461d4..d469db806 100644 --- a/core/events/events_var_delete.ts +++ b/core/events/events_var_delete.ts @@ -7,7 +7,10 @@ // Former goog.module ID: Blockly.Events.VarDelete import * as registry from '../registry.js'; -import type {VariableModel} from '../variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; import {VarBase, VarBaseJson} from './events_var_base.js'; import * as eventUtils from './utils.js'; @@ -28,14 +31,14 @@ export class VarDelete extends VarBase { /** * @param opt_variable The deleted variable. Undefined for a blank event. */ - constructor(opt_variable?: VariableModel) { + constructor(opt_variable?: IVariableModel) { super(opt_variable); if (!opt_variable) { return; // Blank event to be populated by fromJson. } - this.varType = opt_variable.type; - this.varName = opt_variable.name; + this.varType = opt_variable.getType(); + this.varName = opt_variable.getName(); } /** diff --git a/core/events/events_var_rename.ts b/core/events/events_var_rename.ts index 3bb1e90eb..0de56c544 100644 --- a/core/events/events_var_rename.ts +++ b/core/events/events_var_rename.ts @@ -7,7 +7,10 @@ // Former goog.module ID: Blockly.Events.VarRename import * as registry from '../registry.js'; -import type {VariableModel} from '../variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; import {VarBase, VarBaseJson} from './events_var_base.js'; import * as eventUtils from './utils.js'; @@ -31,13 +34,13 @@ export class VarRename extends VarBase { * @param opt_variable The renamed variable. Undefined for a blank event. * @param newName The new name the variable will be changed to. */ - constructor(opt_variable?: VariableModel, newName?: string) { + constructor(opt_variable?: IVariableModel, newName?: string) { super(opt_variable); if (!opt_variable) { return; // Blank event to be populated by fromJson. } - this.oldName = opt_variable.name; + this.oldName = opt_variable.getName(); this.newName = typeof newName === 'undefined' ? '' : newName; } diff --git a/core/field_variable.ts b/core/field_variable.ts index d0a929bf0..a40a21ccc 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -30,7 +30,7 @@ import type {MenuItem} from './menuitem.js'; import {Msg} from './msg.js'; import * as parsing from './utils/parsing.js'; import {Size} from './utils/size.js'; -import {VariableModel} from './variable_model.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; import * as Xml from './xml.js'; @@ -52,7 +52,7 @@ export class FieldVariable extends FieldDropdown { protected override size_: Size; /** The variable model associated with this field. */ - private variable: VariableModel | null = null; + private variable: IVariableModel | null = null; /** * Serializable fields are saved by the serializer, non-serializable fields @@ -196,12 +196,12 @@ export class FieldVariable extends FieldDropdown { ); // This should never happen :) - if (variableType !== null && variableType !== variable.type) { + if (variableType !== null && variableType !== variable.getType()) { throw Error( "Serialized variable type with id '" + variable.getId() + "' had type " + - variable.type + + variable.getType() + ', and ' + 'does not match variable field that references it: ' + Xml.domToText(fieldElement) + @@ -224,9 +224,9 @@ export class FieldVariable extends FieldDropdown { this.initModel(); fieldElement.id = this.variable!.getId(); - fieldElement.textContent = this.variable!.name; - if (this.variable!.type) { - fieldElement.setAttribute('variabletype', this.variable!.type); + fieldElement.textContent = this.variable!.getName(); + if (this.variable!.getType()) { + fieldElement.setAttribute('variabletype', this.variable!.getType()); } return fieldElement; } @@ -249,8 +249,8 @@ export class FieldVariable extends FieldDropdown { this.initModel(); const state = {'id': this.variable!.getId()}; if (doFullSerialization) { - (state as AnyDuringMigration)['name'] = this.variable!.name; - (state as AnyDuringMigration)['type'] = this.variable!.type; + (state as AnyDuringMigration)['name'] = this.variable!.getName(); + (state as AnyDuringMigration)['type'] = this.variable!.getType(); } return state; } @@ -307,7 +307,7 @@ export class FieldVariable extends FieldDropdown { * is selected. */ override getText(): string { - return this.variable ? this.variable.name : ''; + return this.variable ? this.variable.getName() : ''; } /** @@ -318,7 +318,7 @@ export class FieldVariable extends FieldDropdown { * @returns The selected variable, or null if none was selected. * @internal */ - getVariable(): VariableModel | null { + getVariable(): IVariableModel | null { return this.variable; } @@ -365,7 +365,7 @@ export class FieldVariable extends FieldDropdown { return null; } // Type Checks. - const type = variable.type; + const type = variable.getType(); if (!this.typeIsAllowed(type)) { console.warn("Variable type doesn't match this field! Type was " + type); return null; @@ -499,16 +499,13 @@ export class FieldVariable extends FieldDropdown { const id = menuItem.getValue(); // Handle special cases. if (this.sourceBlock_ && !this.sourceBlock_.isDeadOrDying()) { - if (id === internalConstants.RENAME_VARIABLE_ID) { + if (id === internalConstants.RENAME_VARIABLE_ID && this.variable) { // Rename variable. - Variables.renameVariable( - this.sourceBlock_.workspace, - this.variable as VariableModel, - ); + Variables.renameVariable(this.sourceBlock_.workspace, this.variable); return; - } else if (id === internalConstants.DELETE_VARIABLE_ID) { + } else if (id === internalConstants.DELETE_VARIABLE_ID && this.variable) { // Delete variable. - this.sourceBlock_.workspace.deleteVariableById(this.variable!.getId()); + this.sourceBlock_.workspace.deleteVariableById(this.variable.getId()); return; } } @@ -560,7 +557,7 @@ export class FieldVariable extends FieldDropdown { ); } const name = this.getText(); - let variableModelList: VariableModel[] = []; + let variableModelList: IVariableModel[] = []; if (this.sourceBlock_ && !this.sourceBlock_.isDeadOrDying()) { const variableTypes = this.getVariableTypes(); // Get a copy of the list, so that adding rename and new variable options @@ -572,12 +569,15 @@ export class FieldVariable extends FieldDropdown { variableModelList = variableModelList.concat(variables); } } - variableModelList.sort(VariableModel.compareByName); + variableModelList.sort(Variables.compareByName); const options: [string, string][] = []; for (let i = 0; i < variableModelList.length; i++) { // Set the UUID as the internal representation of the variable. - options[i] = [variableModelList[i].name, variableModelList[i].getId()]; + options[i] = [ + variableModelList[i].getName(), + variableModelList[i].getId(), + ]; } options.push([ Msg['RENAME_VARIABLE'], diff --git a/core/interfaces/i_variable_backed_parameter_model.ts b/core/interfaces/i_variable_backed_parameter_model.ts index b2042bfb2..4fda2df46 100644 --- a/core/interfaces/i_variable_backed_parameter_model.ts +++ b/core/interfaces/i_variable_backed_parameter_model.ts @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {VariableModel} from '../variable_model.js'; +import type {IVariableModel, IVariableState} from './i_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; + getVariableModel(): IVariableModel; } /** diff --git a/core/names.ts b/core/names.ts index 4f4c72faa..9d724bff9 100644 --- a/core/names.ts +++ b/core/names.ts @@ -95,7 +95,7 @@ export class Names { } const variable = this.variableMap.getVariableById(id); if (variable) { - return variable.name; + return variable.getName(); } return null; } diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index dbb58cffb..355e53cac 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -30,7 +30,10 @@ import { import * as priorities from './priorities.js'; import * as serializationRegistry from './registry.js'; import * as Variables from '../variables.js'; -import {VariableModel} from '../variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; // TODO(#5160): Remove this once lint is fixed. /* eslint-disable no-use-before-define */ @@ -503,7 +506,7 @@ function appendPrivate( */ function checkNewVariables( workspace: Workspace, - originalVariables: VariableModel[], + originalVariables: IVariableModel[], ) { if (eventUtils.isEnabled()) { const newVariables = Variables.getAddedVariables( diff --git a/core/variable_map.ts b/core/variable_map.ts index b8e2e4e0a..1483e0c37 100644 --- a/core/variable_map.ts +++ b/core/variable_map.ts @@ -23,7 +23,7 @@ import * as registry from './registry.js'; import {Msg} from './msg.js'; import {Names} from './names.js'; import * as idGenerator from './utils/idgenerator.js'; -import {VariableModel} from './variable_model.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import type {Workspace} from './workspace.js'; import type {IVariableMap} from './interfaces/i_variable_map.js'; @@ -32,13 +32,18 @@ import type {IVariableMap} from './interfaces/i_variable_map.js'; * variable types as keys and lists of variables as values. The list of * variables are the type indicated by the key. */ -export class VariableMap implements IVariableMap { +export class VariableMap + implements IVariableMap> +{ /** * A map from variable type to map of IDs to variables. The maps contain * all of the named variables in the workspace, including variables that are * not currently in use. */ - private variableMap = new Map>(); + private variableMap = new Map< + string, + Map> + >(); /** @param workspace The workspace this map belongs to. */ constructor(public workspace: Workspace) {} @@ -63,9 +68,12 @@ export class VariableMap implements IVariableMap { * @param newName New variable name. * @returns The newly renamed variable. */ - renameVariable(variable: VariableModel, newName: string): VariableModel { - if (variable.name === newName) return variable; - const type = variable.type; + renameVariable( + variable: IVariableModel, + newName: string, + ): IVariableModel { + if (variable.getName() === newName) return variable; + const type = variable.getType(); const conflictVar = this.getVariable(newName, type); const blocks = this.workspace.getAllBlocks(false); const existingGroup = eventUtils.getGroup(); @@ -91,11 +99,15 @@ export class VariableMap implements IVariableMap { return variable; } - changeVariableType(variable: VariableModel, newType: string): VariableModel { + changeVariableType( + variable: IVariableModel, + newType: string, + ): IVariableModel { this.variableMap.get(variable.getType())?.delete(variable.getId()); variable.setType(newType); const newTypeVariables = - this.variableMap.get(newType) ?? new Map(); + this.variableMap.get(newType) ?? + new Map>(); newTypeVariables.set(variable.getId(), variable); if (!this.variableMap.has(newType)) { this.variableMap.set(newType, newTypeVariables); @@ -129,14 +141,14 @@ export class VariableMap implements IVariableMap { * @param blocks The list of all blocks in the workspace. */ private renameVariableAndUses_( - variable: VariableModel, + variable: IVariableModel, newName: string, blocks: Block[], ) { eventUtils.fire( new (eventUtils.get(eventUtils.VAR_RENAME))(variable, newName), ); - variable.name = newName; + variable.setName(newName); for (let i = 0; i < blocks.length; i++) { blocks[i].updateVarName(variable); } @@ -154,13 +166,13 @@ export class VariableMap implements IVariableMap { * @param blocks The list of all blocks in the workspace. */ private renameVariableWithConflict_( - variable: VariableModel, + variable: IVariableModel, newName: string, - conflictVar: VariableModel, + conflictVar: IVariableModel, blocks: Block[], ) { - const type = variable.type; - const oldCase = conflictVar.name; + const type = variable.getType(); + const oldCase = conflictVar.getName(); if (newName !== oldCase) { // Simple rename to change the case and update references. @@ -194,7 +206,7 @@ export class VariableMap implements IVariableMap { name: string, opt_type?: string, opt_id?: string, - ): VariableModel { + ): IVariableModel { let variable = this.getVariable(name, opt_type); if (variable) { if (opt_id && variable.getId() !== opt_id) { @@ -217,10 +229,19 @@ export class VariableMap implements IVariableMap { } const id = opt_id || idGenerator.genUid(); const type = opt_type || ''; + const VariableModel = registry.getObject( + registry.Type.VARIABLE_MODEL, + registry.DEFAULT, + true, + ); + if (!VariableModel) { + throw new Error('No variable model is registered.'); + } variable = new VariableModel(this.workspace, name, type, id); const variables = - this.variableMap.get(type) ?? new Map(); + this.variableMap.get(type) ?? + new Map>(); variables.set(variable.getId(), variable); if (!this.variableMap.has(type)) { this.variableMap.set(type, variables); @@ -235,10 +256,13 @@ export class VariableMap implements IVariableMap { * * @param variable The variable to add. */ - addVariable(variable: VariableModel) { + addVariable(variable: IVariableModel) { const type = variable.getType(); if (!this.variableMap.has(type)) { - this.variableMap.set(type, new Map()); + this.variableMap.set( + type, + new Map>(), + ); } this.variableMap.get(type)?.set(variable.getId(), variable); } @@ -249,13 +273,13 @@ export class VariableMap implements IVariableMap { * * @param variable Variable to delete. */ - deleteVariable(variable: VariableModel) { - const variables = this.variableMap.get(variable.type); + deleteVariable(variable: IVariableModel) { + const variables = this.variableMap.get(variable.getType()); if (!variables || !variables.has(variable.getId())) return; variables.delete(variable.getId()); eventUtils.fire(new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); if (variables.size === 0) { - this.variableMap.delete(variable.type); + this.variableMap.delete(variable.getType()); } } @@ -269,7 +293,7 @@ export class VariableMap implements IVariableMap { const variable = this.getVariableById(id); if (variable) { // Check whether this variable is a function parameter before deleting. - const variableName = variable.name; + const variableName = variable.getName(); const uses = this.getVariableUsesById(id); for (let i = 0, block; (block = uses[i]); i++) { if ( @@ -312,7 +336,10 @@ export class VariableMap implements IVariableMap { * @param uses An array of uses of the variable. * @internal */ - deleteVariableInternal(variable: VariableModel, uses: Block[]) { + deleteVariableInternal( + variable: IVariableModel, + uses: Block[], + ) { const existingGroup = eventUtils.getGroup(); if (!existingGroup) { eventUtils.setGroup(true); @@ -336,7 +363,10 @@ export class VariableMap implements IVariableMap { * the empty string, which is a specific type. * @returns The variable with the given name, or null if it was not found. */ - getVariable(name: string, opt_type?: string): VariableModel | null { + getVariable( + name: string, + opt_type?: string, + ): IVariableModel | null { const type = opt_type || ''; const variables = this.variableMap.get(type); if (!variables) return null; @@ -354,7 +384,7 @@ export class VariableMap implements IVariableMap { * @param id The ID to check for. * @returns The variable with the given ID. */ - getVariableById(id: string): VariableModel | null { + getVariableById(id: string): IVariableModel | null { for (const variables of this.variableMap.values()) { if (variables.has(id)) { return variables.get(id) ?? null; @@ -371,7 +401,7 @@ export class VariableMap implements IVariableMap { * @returns The sought after variables of the passed in type. An empty array * if none are found. */ - getVariablesOfType(type: string | null): VariableModel[] { + getVariablesOfType(type: string | null): IVariableModel[] { type = type || ''; const variables = this.variableMap.get(type); if (!variables) return []; @@ -416,8 +446,8 @@ export class VariableMap implements IVariableMap { * * @returns List of variable models. */ - getAllVariables(): VariableModel[] { - let allVariables: VariableModel[] = []; + getAllVariables(): IVariableModel[] { + let allVariables: IVariableModel[] = []; for (const variables of this.variableMap.values()) { allVariables = allVariables.concat(...variables.values()); } diff --git a/core/variable_model.ts b/core/variable_model.ts index 017b02c60..15ad5abf9 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -26,7 +26,7 @@ import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; * @see {Blockly.FieldVariable} */ export class VariableModel implements IVariableModel { - type: string; + private type: string; private readonly id_: string; /** @@ -39,8 +39,8 @@ export class VariableModel implements IVariableModel { * @param opt_id The unique ID of the variable. This will default to a UUID. */ constructor( - public workspace: Workspace, - public name: string, + private workspace: Workspace, + private name: string, opt_type?: string, opt_id?: string, ) { @@ -130,7 +130,9 @@ export class VariableModel implements IVariableModel { * @internal */ static compareByName(var1: VariableModel, var2: VariableModel): number { - return var1.name.localeCompare(var2.name, undefined, {sensitivity: 'base'}); + return var1 + .getName() + .localeCompare(var2.getName(), undefined, {sensitivity: 'base'}); } } diff --git a/core/variables.ts b/core/variables.ts index da9d28bff..9809feca2 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -12,7 +12,7 @@ import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_par 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 {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; @@ -34,9 +34,11 @@ export const CATEGORY_NAME = 'VARIABLE'; * @param ws The workspace to search for variables. * @returns Array of variable models. */ -export function allUsedVarModels(ws: Workspace): VariableModel[] { +export function allUsedVarModels( + ws: Workspace, +): IVariableModel[] { const blocks = ws.getAllBlocks(false); - const variables = new Set(); + const variables = new Set>(); // Iterate through every block and add each variable to the set. for (let i = 0; i < blocks.length; i++) { const blockVariables = blocks[i].getVarModels(); @@ -142,7 +144,7 @@ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { } if (Blocks['variables_get']) { - variableModelList.sort(VariableModel.compareByName); + variableModelList.sort(compareByName); for (let i = 0, variable; (variable = variableModelList[i]); i++) { const block = utilsXml.createElement('block'); block.setAttribute('type', 'variables_get'); @@ -266,11 +268,13 @@ export function createVariableButtonHandler( } let msg; - if (existing.type === type) { - msg = Msg['VARIABLE_ALREADY_EXISTS'].replace('%1', existing.name); + if (existing.getType() === type) { + msg = Msg['VARIABLE_ALREADY_EXISTS'].replace('%1', existing.getName()); } else { msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']; - msg = msg.replace('%1', existing.name).replace('%2', existing.type); + msg = msg + .replace('%1', existing.getName()) + .replace('%2', existing.getType()); } dialog.alert(msg, function () { promptAndCheckWithAlert(text); @@ -293,14 +297,14 @@ export function createVariableButtonHandler( */ export function renameVariable( workspace: Workspace, - variable: VariableModel, + variable: IVariableModel, opt_callback?: (p1?: string | null) => void, ) { // This function needs to be named so it can be called recursively. function promptAndCheckWithAlert(defaultName: string) { const promptText = Msg['RENAME_VARIABLE_TITLE'].replace( '%1', - variable.name, + variable.getName(), ); promptName(promptText, defaultName, function (newName) { if (!newName) { @@ -309,9 +313,13 @@ export function renameVariable( return; } - const existing = nameUsedWithOtherType(newName, variable.type, workspace); + const existing = nameUsedWithOtherType( + newName, + variable.getType(), + workspace, + ); const procedure = nameUsedWithConflictingParam( - variable.name, + variable.getName(), newName, workspace, ); @@ -325,8 +333,8 @@ export function renameVariable( let msg = ''; if (existing) { msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'] - .replace('%1', existing.name) - .replace('%2', existing.type); + .replace('%1', existing.getName()) + .replace('%2', existing.getType()); } else if (procedure) { msg = Msg['VARIABLE_ALREADY_EXISTS_FOR_A_PARAMETER'] .replace('%1', newName) @@ -380,12 +388,15 @@ function nameUsedWithOtherType( name: string, type: string, workspace: Workspace, -): VariableModel | null { +): IVariableModel | null { const allVariables = workspace.getVariableMap().getAllVariables(); name = name.toLowerCase(); for (let i = 0, variable; (variable = allVariables[i]); i++) { - if (variable.name.toLowerCase() === name && variable.type !== type) { + if ( + variable.getName().toLowerCase() === name && + variable.getType() !== type + ) { return variable; } } @@ -402,12 +413,12 @@ function nameUsedWithOtherType( export function nameUsedWithAnyType( name: string, workspace: Workspace, -): VariableModel | null { +): IVariableModel | null { const allVariables = workspace.getVariableMap().getAllVariables(); name = name.toLowerCase(); for (let i = 0, variable; (variable = allVariables[i]); i++) { - if (variable.name.toLowerCase() === name) { + if (variable.getName().toLowerCase() === name) { return variable; } } @@ -453,7 +464,7 @@ function checkForConflictingParamWithProcedureModels( const params = procedure .getParameters() .filter(isVariableBackedParameterModel) - .map((param) => param.getVariableModel().name); + .map((param) => param.getVariableModel().getName()); if (!params) continue; const procHasOld = params.some((param) => param.toLowerCase() === oldName); const procHasNew = params.some((param) => param.toLowerCase() === newName); @@ -493,7 +504,7 @@ function checkForConflictingParamWithLegacyProcedures( * @returns The generated DOM. */ export function generateVariableFieldDom( - variableModel: VariableModel, + variableModel: IVariableModel, ): Element { /* Generates the following XML: * foo @@ -501,8 +512,8 @@ export function generateVariableFieldDom( const field = utilsXml.createElement('field'); field.setAttribute('name', 'VAR'); field.setAttribute('id', variableModel.getId()); - field.setAttribute('variabletype', variableModel.type); - const name = utilsXml.createTextNode(variableModel.name); + field.setAttribute('variabletype', variableModel.getType()); + const name = utilsXml.createTextNode(variableModel.getName()); field.appendChild(name); return field; } @@ -524,7 +535,7 @@ export function getOrCreateVariablePackage( id: string | null, opt_name?: string, opt_type?: string, -): VariableModel { +): IVariableModel { let variable = getVariable(workspace, id, opt_name, opt_type); if (!variable) { variable = createVariable(workspace, id, opt_name, opt_type); @@ -552,7 +563,7 @@ export function getVariable( id: string | null, opt_name?: string, opt_type?: string, -): VariableModel | null { +): IVariableModel | null { const potentialVariableMap = workspace.getPotentialVariableMap(); let variable = null; // Try to just get the variable, by ID if possible. @@ -597,7 +608,7 @@ function createVariable( id: string | null, opt_name?: string, opt_type?: string, -): VariableModel { +): IVariableModel { const potentialVariableMap = workspace.getPotentialVariableMap(); // Variables without names get uniquely named for this workspace. if (!opt_name) { @@ -637,8 +648,8 @@ function createVariable( */ export function getAddedVariables( workspace: Workspace, - originalVariables: VariableModel[], -): VariableModel[] { + originalVariables: IVariableModel[], +): IVariableModel[] { const allCurrentVariables = workspace.getAllVariables(); const addedVariables = []; if (originalVariables.length !== allCurrentVariables.length) { @@ -654,6 +665,24 @@ export function getAddedVariables( return addedVariables; } +/** + * A custom compare function for the VariableModel objects. + * + * @param var1 First variable to compare. + * @param var2 Second variable to compare. + * @returns -1 if name of var1 is less than name of var2, 0 if equal, and 1 if + * greater. + * @internal + */ +export function compareByName( + var1: IVariableModel, + var2: IVariableModel, +): number { + return var1 + .getName() + .localeCompare(var2.getName(), undefined, {sensitivity: 'base'}); +} + export const TEST_ONLY = { generateUniqueNameInternal, }; diff --git a/core/variables_dynamic.ts b/core/variables_dynamic.ts index 6c4457549..5f1e2492c 100644 --- a/core/variables_dynamic.ts +++ b/core/variables_dynamic.ts @@ -9,7 +9,6 @@ import {Blocks} from './blocks.js'; import {Msg} from './msg.js'; import * as xml from './utils/xml.js'; -import {VariableModel} from './variable_model.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; @@ -129,7 +128,7 @@ export function flyoutCategoryBlocks(workspace: Workspace): Element[] { xmlList.push(block); } if (Blocks['variables_get_dynamic']) { - variableModelList.sort(VariableModel.compareByName); + variableModelList.sort(Variables.compareByName); for (let i = 0, variable; (variable = variableModelList[i]); i++) { const block = xml.createElement('block'); block.setAttribute('type', 'variables_get_dynamic'); diff --git a/core/workspace.ts b/core/workspace.ts index 71a2e4af9..063144995 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -29,7 +29,10 @@ import * as idGenerator from './utils/idgenerator.js'; import * as math from './utils/math.js'; import type * as toolbox from './utils/toolbox.js'; import {VariableMap} from './variable_map.js'; -import type {VariableModel} from './variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import {WorkspaceComment} from './comments/workspace_comment.js'; import {IProcedureMap} from './interfaces/i_procedure_map.js'; import {ObservableProcedureMap} from './observable_procedure_map.js'; @@ -399,7 +402,7 @@ export class Workspace implements IASTNodeLocation { name: string, opt_type?: string | null, opt_id?: string | null, - ): VariableModel { + ): IVariableModel { return this.variableMap.createVariable( name, opt_type ?? undefined, @@ -436,7 +439,10 @@ export class Workspace implements IASTNodeLocation { * the empty string, which is a specific type. * @returns The variable with the given name. */ - getVariable(name: string, opt_type?: string): VariableModel | null { + getVariable( + name: string, + opt_type?: string, + ): IVariableModel | null { // TODO (#1559): Possibly delete this function after resolving #1559. return this.variableMap.getVariable(name, opt_type); } @@ -447,7 +453,7 @@ export class Workspace implements IASTNodeLocation { * @param id The ID to check for. * @returns The variable with the given ID. */ - getVariableById(id: string): VariableModel | null { + getVariableById(id: string): IVariableModel | null { return this.variableMap.getVariableById(id); } @@ -459,7 +465,7 @@ export class Workspace implements IASTNodeLocation { * @returns The sought after variables of the passed in type. An empty array * if none are found. */ - getVariablesOfType(type: string | null): VariableModel[] { + getVariablesOfType(type: string | null): IVariableModel[] { return this.variableMap.getVariablesOfType(type ?? ''); } @@ -478,7 +484,7 @@ export class Workspace implements IASTNodeLocation { * * @returns List of variable models. */ - getAllVariables(): VariableModel[] { + getAllVariables(): IVariableModel[] { return this.variableMap.getAllVariables(); } diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index aad748105..55a7540bd 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -62,7 +62,10 @@ import {Svg} from './utils/svg.js'; import * as svgMath from './utils/svg_math.js'; import * as toolbox from './utils/toolbox.js'; import * as userAgent from './utils/useragent.js'; -import type {VariableModel} from './variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; import * as VariablesDynamic from './variables_dynamic.js'; import * as WidgetDiv from './widgetdiv.js'; @@ -1354,7 +1357,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { name: string, opt_type?: string | null, opt_id?: string | null, - ): VariableModel { + ): IVariableModel { const newVar = super.createVariable(name, opt_type, opt_id); this.refreshToolboxSelection(); return newVar; diff --git a/core/xml.ts b/core/xml.ts index b8ecf6433..48d43c6f0 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -17,7 +17,10 @@ import {inputTypes} from './inputs/input_types.js'; import * as dom from './utils/dom.js'; import {Size} from './utils/size.js'; import * as utilsXml from './utils/xml.js'; -import type {VariableModel} from './variable_model.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; import {WorkspaceSvg} from './workspace_svg.js'; @@ -86,14 +89,16 @@ export function saveWorkspaceComment( * @param variableList List of all variable models. * @returns Tree of XML elements. */ -export function variablesToDom(variableList: VariableModel[]): Element { +export function variablesToDom( + variableList: IVariableModel[], +): Element { const variables = utilsXml.createElement('variables'); for (let i = 0; i < variableList.length; i++) { const variable = variableList[i]; const element = utilsXml.createElement('variable'); - element.appendChild(utilsXml.createTextNode(variable.name)); - if (variable.type) { - element.setAttribute('type', variable.type); + element.appendChild(utilsXml.createTextNode(variable.getName())); + if (variable.getType()) { + element.setAttribute('type', variable.getType()); } element.id = variable.getId(); variables.appendChild(element); diff --git a/generators/php/procedures.ts b/generators/php/procedures.ts index acf84aea6..9e3edd31f 100644 --- a/generators/php/procedures.ts +++ b/generators/php/procedures.ts @@ -25,7 +25,7 @@ export function procedures_defreturn(block: Block, generator: PhpGenerator) { const workspace = block.workspace; const usedVariables = Variables.allUsedVarModels(workspace) || []; for (const variable of usedVariables) { - const varName = variable.name; + const varName = variable.getName(); // getVars returns parameter names, not ids, for procedure blocks if (!block.getVars().includes(varName)) { globals.push(generator.getVariableName(varName)); diff --git a/generators/python/procedures.ts b/generators/python/procedures.ts index 51d2ee9a3..39c50698b 100644 --- a/generators/python/procedures.ts +++ b/generators/python/procedures.ts @@ -25,7 +25,7 @@ export function procedures_defreturn(block: Block, generator: PythonGenerator) { const workspace = block.workspace; const usedVariables = Variables.allUsedVarModels(workspace) || []; for (const variable of usedVariables) { - const varName = variable.name; + const varName = variable.getName(); // getVars returns parameter names, not ids, for procedure blocks if (!block.getVars().includes(varName)) { globals.push(generator.getVariableName(varName)); diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index c3ca2d416..d30716edb 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -922,6 +922,12 @@ suite('XML', function () { getId: function () { return varId; }, + getName: function () { + return name; + }, + getType: function () { + return type; + }, }; const generatedXml = Blockly.Xml.domToText( From 21c0a7d9998730717ed0bde24706404552073302 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 22 Jul 2024 09:17:40 -0700 Subject: [PATCH 025/102] refactor!: Use IVariableMap instead of VariableMap (#8401) * refactor: use IVariableMap in place of VariableMap. * refactor!: move variable deletion prompting out of VariableMap. * chore: Remove unused imports. --- core/names.ts | 12 ++- core/variable_map.ts | 127 ++++++++++--------------------- core/variables.ts | 69 +++++++++++++++++ core/workspace.ts | 55 ++++++++++--- tests/mocha/variable_map_test.js | 2 +- 5 files changed, 162 insertions(+), 103 deletions(-) diff --git a/core/names.ts b/core/names.ts index 9d724bff9..9976da224 100644 --- a/core/names.ts +++ b/core/names.ts @@ -12,8 +12,11 @@ // Former goog.module ID: Blockly.Names import {Msg} from './msg.js'; -// import * as Procedures from './procedures.js'; -import type {VariableMap} from './variable_map.js'; +import type {IVariableMap} from './interfaces/i_variable_map.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; @@ -39,7 +42,8 @@ export class Names { /** * The variable map from the workspace, containing Blockly variable models. */ - private variableMap: VariableMap | null = null; + private variableMap: IVariableMap> | null = + null; /** * @param reservedWordsList A comma-separated string of words that are illegal @@ -70,7 +74,7 @@ export class Names { * * @param map The map to track. */ - setVariableMap(map: VariableMap) { + setVariableMap(map: IVariableMap>) { this.variableMap = map; } diff --git a/core/variable_map.ts b/core/variable_map.ts index 1483e0c37..dd59311dc 100644 --- a/core/variable_map.ts +++ b/core/variable_map.ts @@ -17,10 +17,10 @@ import './events/events_var_delete.js'; import './events/events_var_rename.js'; import type {Block} from './block.js'; -import * as dialog from './dialog.js'; +import * as deprecation from './utils/deprecation.js'; import * as eventUtils from './events/utils.js'; import * as registry from './registry.js'; -import {Msg} from './msg.js'; +import * as Variables from './variables.js'; import {Names} from './names.js'; import * as idGenerator from './utils/idgenerator.js'; import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; @@ -247,7 +247,6 @@ export class VariableMap this.variableMap.set(type, variables); } eventUtils.fire(new (eventUtils.get(eventUtils.VAR_CREATE))(variable)); - return variable; } @@ -269,77 +268,12 @@ export class VariableMap /* Begin functions for variable deletion. */ /** - * Delete a variable. + * Delete a variable and all of its uses without confirmation. * * @param variable Variable to delete. */ deleteVariable(variable: IVariableModel) { - const variables = this.variableMap.get(variable.getType()); - if (!variables || !variables.has(variable.getId())) return; - variables.delete(variable.getId()); - eventUtils.fire(new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); - if (variables.size === 0) { - this.variableMap.delete(variable.getType()); - } - } - - /** - * Delete a variables by the passed in ID and all of its uses from this - * workspace. May prompt the user for confirmation. - * - * @param id ID of variable to delete. - */ - deleteVariableById(id: string) { - const variable = this.getVariableById(id); - if (variable) { - // Check whether this variable is a function parameter before deleting. - const variableName = variable.getName(); - const uses = this.getVariableUsesById(id); - for (let i = 0, block; (block = uses[i]); i++) { - if ( - block.type === 'procedures_defnoreturn' || - block.type === 'procedures_defreturn' - ) { - const procedureName = String(block.getFieldValue('NAME')); - const deleteText = Msg['CANNOT_DELETE_VARIABLE_PROCEDURE'] - .replace('%1', variableName) - .replace('%2', procedureName); - dialog.alert(deleteText); - return; - } - } - - if (uses.length > 1) { - // Confirm before deleting multiple blocks. - const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION'] - .replace('%1', String(uses.length)) - .replace('%2', variableName); - dialog.confirm(confirmText, (ok) => { - if (ok && variable) { - this.deleteVariableInternal(variable, uses); - } - }); - } else { - // No confirmation necessary for a single block. - this.deleteVariableInternal(variable, uses); - } - } else { - console.warn("Can't delete non-existent variable: " + id); - } - } - - /** - * Deletes a variable and all of its uses from this workspace without asking - * the user for confirmation. - * - * @param variable Variable to delete. - * @param uses An array of uses of the variable. - * @internal - */ - deleteVariableInternal( - variable: IVariableModel, - uses: Block[], - ) { + const uses = this.getVariableUsesById(variable.getId()); const existingGroup = eventUtils.getGroup(); if (!existingGroup) { eventUtils.setGroup(true); @@ -348,11 +282,37 @@ export class VariableMap for (let i = 0; i < uses.length; i++) { uses[i].dispose(true); } - this.deleteVariable(variable); + const variables = this.variableMap.get(variable.getType()); + if (!variables || !variables.has(variable.getId())) return; + variables.delete(variable.getId()); + eventUtils.fire(new (eventUtils.get(eventUtils.VAR_DELETE))(variable)); + if (variables.size === 0) { + this.variableMap.delete(variable.getType()); + } } finally { eventUtils.setGroup(existingGroup); } } + + /** + * @deprecated v12 - Delete a variables by the passed in ID and all of its + * uses from this workspace. May prompt the user for confirmation. + * + * @param id ID of variable to delete. + */ + deleteVariableById(id: string) { + deprecation.warn( + 'VariableMap.deleteVariableById', + 'v12', + 'v13', + 'Blockly.Variables.deleteVariable', + ); + const variable = this.getVariableById(id); + if (variable) { + Variables.deleteVariable(this.workspace, variable); + } + } + /* End functions for variable deletion. */ /** * Find the variable by the given name and type and return it. Return null if @@ -431,7 +391,7 @@ export class VariableMap getVariableTypes(ws: Workspace | null): string[] { const variableTypes = new Set(this.variableMap.keys()); if (ws && ws.getPotentialVariableMap()) { - for (const key of ws.getPotentialVariableMap()!.variableMap.keys()) { + for (const key of ws.getPotentialVariableMap()!.getTypes()) { variableTypes.add(key); } } @@ -470,26 +430,19 @@ export class VariableMap } /** - * Find all the uses of a named variable. + * @deprecated v12 - Find all the uses of a named variable. * * @param id ID of the variable to find. * @returns Array of block usages. */ getVariableUsesById(id: string): Block[] { - const uses = []; - const blocks = this.workspace.getAllBlocks(false); - // Iterate through every block and check the name. - for (let i = 0; i < blocks.length; i++) { - const blockVariables = blocks[i].getVarModels(); - if (blockVariables) { - for (let j = 0; j < blockVariables.length; j++) { - if (blockVariables[j].getId() === id) { - uses.push(blocks[i]); - } - } - } - } - return uses; + deprecation.warn( + 'VariableMap.getVariableUsesById', + 'v12', + 'v13', + 'Blockly.Variables.getVariableUsesById', + ); + return Variables.getVariableUsesById(this.workspace, id); } } diff --git a/core/variables.ts b/core/variables.ts index 9809feca2..5da228f6c 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -6,6 +6,7 @@ // Former goog.module ID: Blockly.Variables +import type {Block} from './block.js'; import {Blocks} from './blocks.js'; import * as dialog from './dialog.js'; import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; @@ -683,6 +684,74 @@ export function compareByName( .localeCompare(var2.getName(), undefined, {sensitivity: 'base'}); } +/** + * Find all the uses of a named variable. + * + * @param workspace The workspace to search for the variable. + * @param id ID of the variable to find. + * @returns Array of block usages. + */ +export function getVariableUsesById(workspace: Workspace, id: string): Block[] { + const uses = []; + const blocks = workspace.getAllBlocks(false); + // Iterate through every block and check the name. + for (let i = 0; i < blocks.length; i++) { + const blockVariables = blocks[i].getVarModels(); + if (blockVariables) { + for (let j = 0; j < blockVariables.length; j++) { + if (blockVariables[j].getId() === id) { + uses.push(blocks[i]); + } + } + } + } + return uses; +} + +/** + * Delete a variable and all of its uses from the given workspace. May prompt + * the user for confirmation. + * + * @param workspace The workspace from which to delete the variable. + * @param variable The variable to delete. + */ +export function deleteVariable( + workspace: Workspace, + variable: IVariableModel, +) { + // Check whether this variable is a function parameter before deleting. + const variableName = variable.getName(); + const uses = getVariableUsesById(workspace, variable.getId()); + for (let i = 0, block; (block = uses[i]); i++) { + if ( + block.type === 'procedures_defnoreturn' || + block.type === 'procedures_defreturn' + ) { + const procedureName = String(block.getFieldValue('NAME')); + const deleteText = Msg['CANNOT_DELETE_VARIABLE_PROCEDURE'] + .replace('%1', variableName) + .replace('%2', procedureName); + dialog.alert(deleteText); + return; + } + } + + if (uses.length > 1) { + // Confirm before deleting multiple blocks. + const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION'] + .replace('%1', String(uses.length)) + .replace('%2', variableName); + dialog.confirm(confirmText, (ok) => { + if (ok && variable) { + workspace.getVariableMap().deleteVariable(variable); + } + }); + } else { + // No confirmation necessary for a single block. + workspace.getVariableMap().deleteVariable(variable); + } +} + export const TEST_ONLY = { generateUniqueNameInternal, }; diff --git a/core/workspace.ts b/core/workspace.ts index 063144995..2981fc6ad 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -28,7 +28,8 @@ import * as arrayUtils from './utils/array.js'; import * as idGenerator from './utils/idgenerator.js'; import * as math from './utils/math.js'; import type * as toolbox from './utils/toolbox.js'; -import {VariableMap} from './variable_map.js'; +import * as Variables from './variables.js'; +import type {IVariableMap} from './interfaces/i_variable_map.js'; import type { IVariableModel, IVariableState, @@ -110,7 +111,7 @@ export class Workspace implements IASTNodeLocation { protected redoStack_: Abstract[] = []; private readonly blockDB = new Map(); private readonly typedBlocksDB = new Map(); - private variableMap: VariableMap; + private variableMap: IVariableMap>; private procedureMap: IProcedureMap = new ObservableProcedureMap(); /** @@ -121,7 +122,9 @@ export class Workspace implements IASTNodeLocation { * these by tracking "potential" variables in the flyout. These variables * become real when references to them are dragged into the main workspace. */ - private potentialVariableMap: VariableMap | null = null; + private potentialVariableMap: IVariableMap< + IVariableModel + > | null = null; /** @param opt_options Dictionary of options. */ constructor(opt_options?: Options) { @@ -147,6 +150,7 @@ export class Workspace implements IASTNodeLocation { * all of the named variables in the workspace, including variables that are * not currently in use. */ + const VariableMap = this.getVariableMapClass(); this.variableMap = new VariableMap(this); } @@ -384,7 +388,9 @@ export class Workspace implements IASTNodeLocation { * @param newName New variable name. */ renameVariableById(id: string, newName: string) { - this.variableMap.renameVariableById(id, newName); + const variable = this.variableMap.getVariableById(id); + if (!variable) return; + this.variableMap.renameVariable(variable, newName); } /** @@ -417,7 +423,7 @@ export class Workspace implements IASTNodeLocation { * @returns Array of block usages. */ getVariableUsesById(id: string): Block[] { - return this.variableMap.getVariableUsesById(id); + return Variables.getVariableUsesById(this, id); } /** @@ -427,7 +433,12 @@ export class Workspace implements IASTNodeLocation { * @param id ID of variable to delete. */ deleteVariableById(id: string) { - this.variableMap.deleteVariableById(id); + const variable = this.variableMap.getVariableById(id); + if (!variable) { + console.warn(`Can't delete non-existent variable: ${id}`); + return; + } + Variables.deleteVariable(this, variable); } /** @@ -476,7 +487,12 @@ export class Workspace implements IASTNodeLocation { * @internal */ getVariableTypes(): string[] { - return this.variableMap.getVariableTypes(this); + const variableTypes = new Set(this.variableMap.getTypes()); + (this.potentialVariableMap?.getTypes() ?? []).forEach((t) => + variableTypes.add(t), + ); + variableTypes.add(''); + return Array.from(variableTypes.values()); } /** @@ -494,7 +510,7 @@ export class Workspace implements IASTNodeLocation { * @returns List of all variable names of all types. */ getAllVariableNames(): string[] { - return this.variableMap.getAllVariableNames(); + return this.variableMap.getAllVariables().map((v) => v.getName()); } /* End functions that are just pass-throughs to the variable map. */ /** @@ -789,7 +805,9 @@ export class Workspace implements IASTNodeLocation { * @returns The potential variable map. * @internal */ - getPotentialVariableMap(): VariableMap | null { + getPotentialVariableMap(): IVariableMap< + IVariableModel + > | null { return this.potentialVariableMap; } @@ -799,6 +817,7 @@ export class Workspace implements IASTNodeLocation { * @internal */ createPotentialVariableMap() { + const VariableMap = this.getVariableMapClass(); this.potentialVariableMap = new VariableMap(this); } @@ -807,7 +826,7 @@ export class Workspace implements IASTNodeLocation { * * @returns The variable map. */ - getVariableMap(): VariableMap { + getVariableMap(): IVariableMap> { return this.variableMap; } @@ -817,7 +836,7 @@ export class Workspace implements IASTNodeLocation { * @param variableMap The variable map. * @internal */ - setVariableMap(variableMap: VariableMap) { + setVariableMap(variableMap: IVariableMap>) { this.variableMap = variableMap; } @@ -866,4 +885,18 @@ export class Workspace implements IASTNodeLocation { static getAll(): Workspace[] { return common.getAllWorkspaces(); } + + protected getVariableMapClass(): new ( + ...p1: any[] + ) => IVariableMap> { + const VariableMap = registry.getClassFromOptions( + registry.Type.VARIABLE_MAP, + this.options, + true, + ); + if (!VariableMap) { + throw new Error('No variable map is registered.'); + } + return VariableMap; + } } diff --git a/tests/mocha/variable_map_test.js b/tests/mocha/variable_map_test.js index 13a474245..76c1702cc 100644 --- a/tests/mocha/variable_map_test.js +++ b/tests/mocha/variable_map_test.js @@ -21,7 +21,7 @@ suite('Variable Map', function () { setup(function () { sharedTestSetup.call(this); this.workspace = new Blockly.Workspace(); - this.variableMap = new Blockly.VariableMap(this.workspace); + this.variableMap = this.workspace.getVariableMap(); }); teardown(function () { From 26e6d80e155e1070425ca74f82d610355f4b7931 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 22 Jul 2024 10:51:56 -0700 Subject: [PATCH 026/102] refactor: clean up VariableModel. (#8416) --- core/variable_model.ts | 37 +++++++++++++++++++++++------- tests/mocha/variable_model_test.js | 28 +++++++++++----------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/core/variable_model.ts b/core/variable_model.ts index 15ad5abf9..f29848084 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -15,6 +15,7 @@ import './events/events_var_create.js'; import * as idGenerator from './utils/idgenerator.js'; +import * as eventUtils from './events/utils.js'; import * as registry from './registry.js'; import type {Workspace} from './workspace.js'; import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; @@ -27,7 +28,7 @@ import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; */ export class VariableModel implements IVariableModel { private type: string; - private readonly id_: string; + private readonly id: string; /** * @param workspace The variable's workspace. @@ -39,7 +40,7 @@ export class VariableModel implements IVariableModel { * @param opt_id The unique ID of the variable. This will default to a UUID. */ constructor( - private workspace: Workspace, + private readonly workspace: Workspace, private name: string, opt_type?: string, opt_id?: string, @@ -58,12 +59,12 @@ export class VariableModel implements IVariableModel { * not change, even if the name changes. In most cases this should be a * UUID. */ - this.id_ = opt_id || idGenerator.genUid(); + this.id = opt_id || idGenerator.genUid(); } /** @returns The ID for the variable. */ getId(): string { - return this.id_; + return this.id; } /** @returns The name of this variable. */ @@ -96,10 +97,20 @@ export class VariableModel implements IVariableModel { return this; } + /** + * Returns the workspace this VariableModel belongs to. + * + * @returns The workspace this VariableModel belongs to. + */ getWorkspace(): Workspace { return this.workspace; } + /** + * Serializes this VariableModel. + * + * @returns a JSON representation of this VariableModel. + */ save(): IVariableState { const state: IVariableState = { 'name': this.getName(), @@ -113,11 +124,21 @@ export class VariableModel implements IVariableModel { return state; } + /** + * Loads the persisted state into a new variable in the given workspace. + * + * @param state The serialized state of a variable model from save(). + * @param workspace The workspace to create the new variable in. + */ static load(state: IVariableState, workspace: Workspace) { - // TODO(adodson): Once VariableMap implements IVariableMap, directly - // construct a variable, retrieve the variable map from the workspace, - // add the variable to that variable map, and fire a VAR_CREATE event. - workspace.createVariable(state['name'], state['type'], state['id']); + const variable = new this( + workspace, + state['name'], + state['type'], + state['id'], + ); + workspace.getVariableMap().addVariable(variable); + eventUtils.fire(new (eventUtils.get(eventUtils.VAR_CREATE))(variable)); } /** diff --git a/tests/mocha/variable_model_test.js b/tests/mocha/variable_model_test.js index 207c580de..cd2a89db4 100644 --- a/tests/mocha/variable_model_test.js +++ b/tests/mocha/variable_model_test.js @@ -27,9 +27,9 @@ suite('Variable Model', function () { 'test_type', 'test_id', ); - assert.equal(variable.name, 'test'); - assert.equal(variable.type, 'test_type'); - assert.equal(variable.id_, 'test_id'); + assert.equal(variable.getName(), 'test'); + assert.equal(variable.getType(), 'test_type'); + assert.equal(variable.getId(), 'test_id'); }); test('Null type', function () { @@ -39,7 +39,7 @@ suite('Variable Model', function () { null, 'test_id', ); - assert.equal(variable.type, ''); + assert.equal(variable.getType(), ''); }); test('Undefined type', function () { @@ -49,7 +49,7 @@ suite('Variable Model', function () { undefined, 'test_id', ); - assert.equal(variable.type, ''); + assert.equal(variable.getType(), ''); }); test('Null id', function () { @@ -59,9 +59,9 @@ suite('Variable Model', function () { 'test_type', null, ); - assert.equal(variable.name, 'test'); - assert.equal(variable.type, 'test_type'); - assert.exists(variable.id_); + assert.equal(variable.getName(), 'test'); + assert.equal(variable.getType(), 'test_type'); + assert.exists(variable.getId()); }); test('Undefined id', function () { @@ -71,15 +71,15 @@ suite('Variable Model', function () { 'test_type', undefined, ); - assert.equal(variable.name, 'test'); - assert.equal(variable.type, 'test_type'); - assert.exists(variable.id_); + assert.equal(variable.getName(), 'test'); + assert.equal(variable.getType(), 'test_type'); + assert.exists(variable.getId()); }); test('Only name provided', function () { const variable = new Blockly.VariableModel(this.workspace, 'test'); - assert.equal(variable.name, 'test'); - assert.equal(variable.type, ''); - assert.exists(variable.id_); + assert.equal(variable.getName(), 'test'); + assert.equal(variable.getType(), ''); + assert.exists(variable.getId()); }); }); From 58abf6ef892a452e71727d4adcddd52f6c836c86 Mon Sep 17 00:00:00 2001 From: Gabriel Fleury <55366345+ga-fleury@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:14:17 -0300 Subject: [PATCH 027/102] fix: Remove references to getFastTextWidth (#8277) (#8307) * feat: Remove references to getFastTextWidth (#8277) * format --- core/field.ts | 7 +------ core/field_dropdown.ts | 14 ++------------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/core/field.ts b/core/field.ts index eed34e613..68f4e2bb4 100644 --- a/core/field.ts +++ b/core/field.ts @@ -835,12 +835,7 @@ export abstract class Field let contentWidth = 0; if (this.textElement_) { - contentWidth = dom.getFastTextWidth( - this.textElement_, - constants!.FIELD_TEXT_FONTSIZE, - constants!.FIELD_TEXT_FONTWEIGHT, - constants!.FIELD_TEXT_FONTFAMILY, - ); + contentWidth = dom.getTextWidth(this.textElement_); totalWidth += contentWidth; } if (!this.isFullBlockField()) { diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index 58a4b0732..5f26ac3b4 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -532,12 +532,7 @@ export class FieldDropdown extends Field { height / 2 - this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_SIZE / 2, ); } else { - arrowWidth = dom.getFastTextWidth( - this.arrow as SVGTSpanElement, - this.getConstants()!.FIELD_TEXT_FONTSIZE, - this.getConstants()!.FIELD_TEXT_FONTWEIGHT, - this.getConstants()!.FIELD_TEXT_FONTFAMILY, - ); + arrowWidth = dom.getTextWidth(this.arrow as SVGTSpanElement); } this.size_.width = imageWidth + arrowWidth + xPadding * 2; this.size_.height = height; @@ -570,12 +565,7 @@ export class FieldDropdown extends Field { hasBorder ? this.getConstants()!.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0, this.getConstants()!.FIELD_TEXT_HEIGHT, ); - const textWidth = dom.getFastTextWidth( - this.getTextElement(), - this.getConstants()!.FIELD_TEXT_FONTSIZE, - this.getConstants()!.FIELD_TEXT_FONTWEIGHT, - this.getConstants()!.FIELD_TEXT_FONTFAMILY, - ); + const textWidth = dom.getTextWidth(this.getTextElement()); const xPadding = hasBorder ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING : 0; From 348313a1b6d371344ca2cefcd128de1ececb3d1b Mon Sep 17 00:00:00 2001 From: Gabriel Fleury <55366345+ga-fleury@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:14:45 -0300 Subject: [PATCH 028/102] feat: Add a blocklyCollapsed CSS class to collapsed blocks' root SVG (#8264) (#8308) * feat: Add a blocklyCollapsed CSS class to collapsed blocks' root SVG (#8264) * format --- core/block_svg.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index 5e96657f4..5a059e47b 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -524,9 +524,12 @@ export class BlockSvg if (!collapsed) { this.updateDisabled(); this.removeInput(collapsedInputName); + dom.removeClass(this.svgGroup_, 'blocklyCollapsed'); return; } + dom.addClass(this.svgGroup_, 'blocklyCollapsed'); + const text = this.toString(internalConstants.COLLAPSE_CHARS); const field = this.getField(collapsedFieldName); if (field) { From e29d7abfdb706ed7db1dc14acd935c3c3950bdbc Mon Sep 17 00:00:00 2001 From: Gabriel Fleury <55366345+ga-fleury@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:38:40 -0300 Subject: [PATCH 029/102] fix!: Rename editing CSS class to blocklyEditing (#8287) (#8301) * chore!: Rename editing CSS class to blocklyEditing (#8287) * further changes --- core/field_input.ts | 4 ++-- core/renderers/common/constants.ts | 2 +- core/renderers/zelos/constants.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/field_input.ts b/core/field_input.ts index 85431cc5b..3326cd35f 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -405,7 +405,7 @@ export abstract class FieldInput extends Field< const clickTarget = this.getClickTarget_(); if (!clickTarget) throw new Error('A click target has not been set.'); - dom.addClass(clickTarget, 'editing'); + dom.addClass(clickTarget, 'blocklyEditing'); const htmlInput = document.createElement('input'); htmlInput.className = 'blocklyHtmlInput'; @@ -500,7 +500,7 @@ export abstract class FieldInput extends Field< const clickTarget = this.getClickTarget_(); if (!clickTarget) throw new Error('A click target has not been set.'); - dom.removeClass(clickTarget, 'editing'); + dom.removeClass(clickTarget, 'blocklyEditing'); } /** diff --git a/core/renderers/common/constants.ts b/core/renderers/common/constants.ts index 078fc01d6..568b7f444 100644 --- a/core/renderers/common/constants.ts +++ b/core/renderers/common/constants.ts @@ -1154,7 +1154,7 @@ export class ConstantProvider { `}`, // Editable field hover. - `${selector} .blocklyEditableText:not(.editing):hover>rect {`, + `${selector} .blocklyEditableText:not(.blocklyEditing):hover>rect {`, `stroke: #fff;`, `stroke-width: 2;`, `}`, diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index c50e66510..22e3f3782 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -825,9 +825,9 @@ export class ConstantProvider extends BaseConstantProvider { // Editable field hover. `${selector} .blocklyDraggable:not(.blocklyDisabled)`, - ` .blocklyEditableText:not(.editing):hover>rect,`, + ` .blocklyEditableText:not(.blocklyEditing):hover>rect,`, `${selector} .blocklyDraggable:not(.blocklyDisabled)`, - ` .blocklyEditableText:not(.editing):hover>.blocklyPath {`, + ` .blocklyEditableText:not(.blocklyEditing):hover>.blocklyPath {`, `stroke: #fff;`, `stroke-width: 2;`, `}`, From 76eebc2f24c0002a9ee1927249fae8c600244b8b Mon Sep 17 00:00:00 2001 From: Chaitanya Yeole <77329060+ChaitanyaYeole02@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:05:19 -0400 Subject: [PATCH 030/102] feat: Add a blocklyBlock CSS class to the block's root SVG (#8397) --- core/renderers/common/path_object.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/renderers/common/path_object.ts b/core/renderers/common/path_object.ts index 8ca8cd193..c5ac5db20 100644 --- a/core/renderers/common/path_object.ts +++ b/core/renderers/common/path_object.ts @@ -66,6 +66,8 @@ export class PathObject implements IPathObject { {'class': 'blocklyPath'}, this.svgRoot, ); + + this.setClass_('blocklyBlock', true); } /** From fb82c9c9bb4acb08a1a5a0c4bd72088e9c594295 Mon Sep 17 00:00:00 2001 From: Shreyans Pathak Date: Mon, 22 Jul 2024 19:09:10 -0400 Subject: [PATCH 031/102] feat: add `blocklyMiniWorkspaceBubble` css class (#8390) --- core/bubbles/mini_workspace_bubble.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/bubbles/mini_workspace_bubble.ts b/core/bubbles/mini_workspace_bubble.ts index 74317d57b..d11efb280 100644 --- a/core/bubbles/mini_workspace_bubble.ts +++ b/core/bubbles/mini_workspace_bubble.ts @@ -80,6 +80,7 @@ export class MiniWorkspaceBubble extends Bubble { flyout?.show(options.languageTree); } + dom.addClass(this.svgRoot, 'blocklyMiniWorkspaceBubble'); this.miniWorkspace.addChangeListener(this.onWorkspaceChange.bind(this)); this.miniWorkspace .getFlyout() From 91892ac303b28e56f145075437ef13ee83861b36 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 22 Jul 2024 17:13:20 -0700 Subject: [PATCH 032/102] refactor: deprecate and clean up variable-related methods. (#8415) * refactor: deprecate and clean up variable-related methods. * chore: Add deprecation JSDoc. --- core/field_variable.ts | 2 +- core/variable_map.ts | 60 +++++++++------------- core/variable_model.ts | 15 ------ core/workspace.ts | 82 +++++++++++++++++++++++------- tests/mocha/field_variable_test.js | 3 +- tests/mocha/variable_map_test.js | 18 ------- 6 files changed, 91 insertions(+), 89 deletions(-) diff --git a/core/field_variable.ts b/core/field_variable.ts index a40a21ccc..9dbba4ca3 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -420,7 +420,7 @@ export class FieldVariable extends FieldDropdown { if (variableTypes === null) { // If variableTypes is null, return all variable types. if (this.sourceBlock_ && !this.sourceBlock_.isDeadOrDying()) { - return this.sourceBlock_.workspace.getVariableTypes(); + return this.sourceBlock_.workspace.getVariableMap().getTypes(); } } variableTypes = variableTypes || ['']; diff --git a/core/variable_map.ts b/core/variable_map.ts index dd59311dc..c9e49b664 100644 --- a/core/variable_map.ts +++ b/core/variable_map.ts @@ -84,14 +84,9 @@ export class VariableMap // The IDs may match if the rename is a simple case change (name1 -> // Name1). if (!conflictVar || conflictVar.getId() === variable.getId()) { - this.renameVariableAndUses_(variable, newName, blocks); + this.renameVariableAndUses(variable, newName, blocks); } else { - this.renameVariableWithConflict_( - variable, - newName, - conflictVar, - blocks, - ); + this.renameVariableWithConflict(variable, newName, conflictVar, blocks); } } finally { eventUtils.setGroup(existingGroup); @@ -120,10 +115,17 @@ export class VariableMap * Rename a variable by updating its name in the variable map. Identify the * variable to rename with the given ID. * + * @deprecated v12, use VariableMap.renameVariable. * @param id ID of the variable to rename. * @param newName New variable name. */ renameVariableById(id: string, newName: string) { + deprecation.warn( + 'VariableMap.renameVariableById', + 'v12', + 'v13', + 'VariableMap.renameVariable', + ); const variable = this.getVariableById(id); if (!variable) { throw Error("Tried to rename a variable that didn't exist. ID: " + id); @@ -140,7 +142,7 @@ export class VariableMap * @param newName New variable name. * @param blocks The list of all blocks in the workspace. */ - private renameVariableAndUses_( + private renameVariableAndUses( variable: IVariableModel, newName: string, blocks: Block[], @@ -165,7 +167,7 @@ export class VariableMap * @param conflictVar The variable that was already using newName. * @param blocks The list of all blocks in the workspace. */ - private renameVariableWithConflict_( + private renameVariableWithConflict( variable: IVariableModel, newName: string, conflictVar: IVariableModel, @@ -176,7 +178,7 @@ export class VariableMap if (newName !== oldCase) { // Simple rename to change the case and update references. - this.renameVariableAndUses_(conflictVar, newName, blocks); + this.renameVariableAndUses(conflictVar, newName, blocks); } // These blocks now refer to a different variable. @@ -295,9 +297,10 @@ export class VariableMap } /** - * @deprecated v12 - Delete a variables by the passed in ID and all of its - * uses from this workspace. May prompt the user for confirmation. + * Delete a variables by the passed in ID and all of its uses from this + * workspace. May prompt the user for confirmation. * + * @deprecated v12, use Blockly.Variables.deleteVariable. * @param id ID of variable to delete. */ deleteVariableById(id: string) { @@ -378,29 +381,6 @@ export class VariableMap return [...this.variableMap.keys()]; } - /** - * Return all variable and potential variable types. This list always - * contains the empty string. - * - * @param ws The workspace used to look for potential variables. This can be - * different than the workspace stored on this object if the passed in ws - * is a flyout workspace. - * @returns List of variable types. - * @internal - */ - getVariableTypes(ws: Workspace | null): string[] { - const variableTypes = new Set(this.variableMap.keys()); - if (ws && ws.getPotentialVariableMap()) { - for (const key of ws.getPotentialVariableMap()!.getTypes()) { - variableTypes.add(key); - } - } - if (!variableTypes.has('')) { - variableTypes.add(''); - } - return Array.from(variableTypes.values()); - } - /** * Return all variables of all types. * @@ -417,9 +397,16 @@ export class VariableMap /** * Returns all of the variable names of all types. * + * @deprecated v12, use Blockly.Variables.getAllVariables. * @returns All of the variable names of all types. */ getAllVariableNames(): string[] { + deprecation.warn( + 'VariableMap.getAllVariableNames', + 'v12', + 'v13', + 'Blockly.Variables.getAllVariables', + ); const names: string[] = []; for (const variables of this.variableMap.values()) { for (const variable of variables.values()) { @@ -430,8 +417,9 @@ export class VariableMap } /** - * @deprecated v12 - Find all the uses of a named variable. + * Find all the uses of a named variable. * + * @deprecated v12, use Blockly.Variables.getVariableUsesById. * @param id ID of the variable to find. * @returns Array of block usages. */ diff --git a/core/variable_model.ts b/core/variable_model.ts index f29848084..5be8d54b3 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -140,21 +140,6 @@ export class VariableModel implements IVariableModel { workspace.getVariableMap().addVariable(variable); eventUtils.fire(new (eventUtils.get(eventUtils.VAR_CREATE))(variable)); } - - /** - * A custom compare function for the VariableModel objects. - * - * @param var1 First variable to compare. - * @param var2 Second variable to compare. - * @returns -1 if name of var1 is less than name of var2, 0 if equal, and 1 if - * greater. - * @internal - */ - static compareByName(var1: VariableModel, var2: VariableModel): number { - return var1 - .getName() - .localeCompare(var2.getName(), undefined, {sensitivity: 'base'}); - } } registry.register( diff --git a/core/workspace.ts b/core/workspace.ts index 2981fc6ad..9e7d7c884 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -25,6 +25,7 @@ import type {IConnectionChecker} from './interfaces/i_connection_checker.js'; import {Options} from './options.js'; import * as registry from './registry.js'; import * as arrayUtils from './utils/array.js'; +import * as deprecation from './utils/deprecation.js'; import * as idGenerator from './utils/idgenerator.js'; import * as math from './utils/math.js'; import type * as toolbox from './utils/toolbox.js'; @@ -381,13 +382,19 @@ export class Workspace implements IASTNodeLocation { /* Begin functions that are just pass-throughs to the variable map. */ /** - * Rename a variable by updating its name in the variable map. Identify the - * variable to rename with the given ID. + * @deprecated v12 - Rename a variable by updating its name in the variable + * map. Identify the variable to rename with the given ID. * * @param id ID of the variable to rename. * @param newName New variable name. */ renameVariableById(id: string, newName: string) { + deprecation.warn( + 'Blockly.Workspace.renameVariableById', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().renameVariable', + ); const variable = this.variableMap.getVariableById(id); if (!variable) return; this.variableMap.renameVariable(variable, newName); @@ -396,6 +403,7 @@ export class Workspace implements IASTNodeLocation { /** * Create a variable with a given name, optional type, and optional ID. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().createVariable. * @param name The name of the variable. This must be unique across variables * and procedures. * @param opt_type The type of the variable like 'int' or 'string'. @@ -409,6 +417,12 @@ export class Workspace implements IASTNodeLocation { opt_type?: string | null, opt_id?: string | null, ): IVariableModel { + deprecation.warn( + 'Blockly.Workspace.createVariable', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().createVariable', + ); return this.variableMap.createVariable( name, opt_type ?? undefined, @@ -419,10 +433,17 @@ export class Workspace implements IASTNodeLocation { /** * Find all the uses of the given variable, which is identified by ID. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getVariableUsesById * @param id ID of the variable to find. * @returns Array of block usages. */ getVariableUsesById(id: string): Block[] { + deprecation.warn( + 'Blockly.Workspace.getVariableUsesById', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getVariableUsesById', + ); return Variables.getVariableUsesById(this, id); } @@ -430,9 +451,16 @@ export class Workspace implements IASTNodeLocation { * Delete a variables by the passed in ID and all of its uses from this * workspace. May prompt the user for confirmation. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().deleteVariable. * @param id ID of variable to delete. */ deleteVariableById(id: string) { + deprecation.warn( + 'Blockly.Workspace.deleteVariableById', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().deleteVariable', + ); const variable = this.variableMap.getVariableById(id); if (!variable) { console.warn(`Can't delete non-existent variable: ${id}`); @@ -445,6 +473,7 @@ export class Workspace implements IASTNodeLocation { * Find the variable by the given name and return it. Return null if not * found. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getVariable. * @param name The name to check for. * @param opt_type The type of the variable. If not provided it defaults to * the empty string, which is a specific type. @@ -454,6 +483,12 @@ export class Workspace implements IASTNodeLocation { name: string, opt_type?: string, ): IVariableModel | null { + deprecation.warn( + 'Blockly.Workspace.getVariable', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getVariable', + ); // TODO (#1559): Possibly delete this function after resolving #1559. return this.variableMap.getVariable(name, opt_type); } @@ -461,10 +496,17 @@ export class Workspace implements IASTNodeLocation { /** * Find the variable by the given ID and return it. Return null if not found. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getVariableById. * @param id The ID to check for. * @returns The variable with the given ID. */ getVariableById(id: string): IVariableModel | null { + deprecation.warn( + 'Blockly.Workspace.getVariableById', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getVariableById', + ); return this.variableMap.getVariableById(id); } @@ -472,44 +514,50 @@ export class Workspace implements IASTNodeLocation { * Find the variable with the specified type. If type is null, return list of * variables with empty string type. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getVariablesOfType. * @param type Type of the variables to find. * @returns The sought after variables of the passed in type. An empty array * if none are found. */ getVariablesOfType(type: string | null): IVariableModel[] { - return this.variableMap.getVariablesOfType(type ?? ''); - } - - /** - * Return all variable types. - * - * @returns List of variable types. - * @internal - */ - getVariableTypes(): string[] { - const variableTypes = new Set(this.variableMap.getTypes()); - (this.potentialVariableMap?.getTypes() ?? []).forEach((t) => - variableTypes.add(t), + deprecation.warn( + 'Blockly.Workspace.getVariablesOfType', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getVariablesOfType', ); - variableTypes.add(''); - return Array.from(variableTypes.values()); + return this.variableMap.getVariablesOfType(type ?? ''); } /** * Return all variables of all types. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getAllVariables. * @returns List of variable models. */ getAllVariables(): IVariableModel[] { + deprecation.warn( + 'Blockly.Workspace.getAllVariables', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getAllVariables', + ); return this.variableMap.getAllVariables(); } /** * Returns all variable names of all types. * + * @deprecated v12, use Blockly.Workspace.getVariableMap().getAllVariables. * @returns List of all variable names of all types. */ getAllVariableNames(): string[] { + deprecation.warn( + 'Blockly.Workspace.getAllVariableNames', + 'v12', + 'v13', + 'Blockly.Workspace.getVariableMap().getAllVariables', + ); return this.variableMap.getAllVariables().map((v) => v.getName()); } /* End functions that are just pass-throughs to the variable map. */ diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js index 63dd644c3..fa332957b 100644 --- a/tests/mocha/field_variable_test.js +++ b/tests/mocha/field_variable_test.js @@ -388,8 +388,7 @@ suite('Variable Fields', function () { fieldVariable.variableTypes = null; const resultTypes = fieldVariable.getVariableTypes(); - // The empty string is always one of the options. - assert.deepEqual(resultTypes, ['type1', 'type2', '']); + assert.deepEqual(resultTypes, ['type1', 'type2']); }); test('variableTypes is the empty list', function () { const fieldVariable = new Blockly.FieldVariable('name1'); diff --git a/tests/mocha/variable_map_test.js b/tests/mocha/variable_map_test.js index 76c1702cc..8b60093fc 100644 --- a/tests/mocha/variable_map_test.js +++ b/tests/mocha/variable_map_test.js @@ -187,24 +187,6 @@ suite('Variable Map', function () { }); }); - suite('getVariableTypes', function () { - test('Trivial', function () { - this.variableMap.createVariable('name1', 'type1', 'id1'); - this.variableMap.createVariable('name2', 'type1', 'id2'); - this.variableMap.createVariable('name3', 'type2', 'id3'); - this.variableMap.createVariable('name4', 'type3', 'id4'); - const resultArray = this.variableMap.getVariableTypes(); - // The empty string is always an option. - assert.deepEqual(resultArray, ['type1', 'type2', 'type3', '']); - }); - - test('None', function () { - // The empty string is always an option. - const resultArray = this.variableMap.getVariableTypes(); - assert.deepEqual(resultArray, ['']); - }); - }); - suite('getVariablesOfType', function () { test('Trivial', function () { const var1 = this.variableMap.createVariable('name1', 'type1', 'id1'); From 2619fb803c185a1ce61715d3ec8b15ae9264c613 Mon Sep 17 00:00:00 2001 From: dianaprahoveanu23 <142212685+dianaprahoveanu23@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:33:59 +0100 Subject: [PATCH 033/102] feat: Add a blocklyNotEditable CSS class to the block's root SVG (#8391) * feat: added blockyNotEditable CSS class to the block's root SVG * Run linter to fix code style issues --- core/block_svg.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index 5a059e47b..a289db556 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -732,6 +732,13 @@ export class BlockSvg */ override setEditable(editable: boolean) { super.setEditable(editable); + + if (editable) { + dom.removeClass(this.svgGroup_, 'blocklyNotEditable'); + } else { + dom.addClass(this.svgGroup_, 'blocklyNotEditable'); + } + const icons = this.getIcons(); for (let i = 0; i < icons.length; i++) { icons[i].updateEditable(); From 5d825f0a60f6009cc2f55dfb5ea14b6b151d4c8c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 25 Jul 2024 10:07:48 -0700 Subject: [PATCH 034/102] chore: Removed @internal annotation from public Field methods. (#8426) * chore: Removed @internal annotation from public Field methods. * chore: make forceRerender non-internal. --- core/field.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/field.ts b/core/field.ts index 68f4e2bb4..229c3626d 100644 --- a/core/field.ts +++ b/core/field.ts @@ -408,7 +408,6 @@ export abstract class Field * called by Blockly.Xml. * * @param fieldElement The element containing info about the field's state. - * @internal */ fromXml(fieldElement: Element) { // Any because gremlins live here. No touchie! @@ -421,7 +420,6 @@ export abstract class Field * @param fieldElement The element to populate with info about the field's * state. * @returns The element containing info about the field's state. - * @internal */ toXml(fieldElement: Element): Element { // Any because gremlins live here. No touchie! @@ -440,7 +438,6 @@ export abstract class Field * {@link https://developers.devsite.google.com/blockly/guides/create-custom-blocks/fields/customizing-fields/creating#full_serialization_and_backing_data | field serialization docs} * for more information. * @returns JSON serializable state. - * @internal */ saveState(_doFullSerialization?: boolean): AnyDuringMigration { const legacyState = this.saveLegacyState(Field); @@ -455,7 +452,6 @@ export abstract class Field * called by the serialization system. * * @param state The state we want to apply to the field. - * @internal */ loadState(state: AnyDuringMigration) { if (this.loadLegacyState(Field, state)) { @@ -518,8 +514,6 @@ export abstract class Field /** * Dispose of all DOM objects and events belonging to this editable field. - * - * @internal */ dispose() { dropDownDiv.hideIfOwner(this); @@ -1054,8 +1048,6 @@ export abstract class Field * rerender this field and adjust for any sizing changes. * Other fields on the same block will not rerender, because their sizes have * already been recorded. - * - * @internal */ forceRerender() { this.isDirty_ = true; @@ -1303,7 +1295,6 @@ export abstract class Field * Subclasses may override this. * * @returns True if this field has any variable references. - * @internal */ referencesVariables(): boolean { return false; @@ -1312,8 +1303,6 @@ export abstract class Field /** * Refresh the variable name referenced by this field if this field references * variables. - * - * @internal */ refreshVariableName() {} // NOP From af0a724b3e0294d05608876f43caebbfefb2b5f5 Mon Sep 17 00:00:00 2001 From: Skye <81345074+Skye967@users.noreply.github.com> Date: Fri, 26 Jul 2024 19:16:22 -0600 Subject: [PATCH 035/102] fix: use `:focus` pseudo class instead of `blocklyFocused` (#8360) * bug: removed blocklyFocused from menu.ts and dropdown.ts, changed css style to :focus * removed blocklyFocused from menu.ts * resubmit * core css removed blocklyFocused * fix core css * menu file import cleanup, linting error --- core/css.ts | 5 ++--- core/dropdowndiv.ts | 6 ------ core/menu.ts | 3 --- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/core/css.ts b/core/css.ts index 20c573093..7a0053604 100644 --- a/core/css.ts +++ b/core/css.ts @@ -5,7 +5,6 @@ */ // Former goog.module ID: Blockly.Css - /** Has CSS already been injected? */ let injected = false; @@ -119,7 +118,7 @@ let content = ` box-shadow: 0 0 3px 1px rgba(0,0,0,.3); } -.blocklyDropDownDiv.blocklyFocused { +.blocklyDropDownDiv:focus { box-shadow: 0 0 6px 1px rgba(0,0,0,.3); } @@ -445,7 +444,7 @@ input[type=number] { z-index: 20000; /* Arbitrary, but some apps depend on it... */ } -.blocklyWidgetDiv .blocklyMenu.blocklyFocused { +.blocklyWidgetDiv .blocklyMenu:focus { box-shadow: 0 0 6px 1px rgba(0,0,0,.3); } diff --git a/core/dropdowndiv.ts b/core/dropdowndiv.ts index c90661c4e..35eb6eaed 100644 --- a/core/dropdowndiv.ts +++ b/core/dropdowndiv.ts @@ -136,12 +136,6 @@ export function createDom() { // Handle focusin/out events to add a visual indicator when // a child is focused or blurred. - div.addEventListener('focusin', function () { - dom.addClass(div, 'blocklyFocused'); - }); - div.addEventListener('focusout', function () { - dom.removeClass(div, 'blocklyFocused'); - }); } /** diff --git a/core/menu.ts b/core/menu.ts index 29615925b..31eda5c3d 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -15,7 +15,6 @@ import * as browserEvents from './browser_events.js'; 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 type {Size} from './utils/size.js'; import * as style from './utils/style.js'; @@ -156,7 +155,6 @@ export class Menu { const el = this.getElement(); if (el) { el.focus({preventScroll: true}); - dom.addClass(el, 'blocklyFocused'); } } @@ -165,7 +163,6 @@ export class Menu { const el = this.getElement(); if (el) { el.blur(); - dom.removeClass(el, 'blocklyFocused'); } } From 82c7aad4e7382f4cabfaed1000bd78725a665f07 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 29 Jul 2024 12:00:52 -0700 Subject: [PATCH 036/102] feat: Add a VarTypeChange event. (#8402) * feat: Add a VarTypeChange event. * chore: Update copyright date. * refactor: Inline fields in the constructor. --- core/events/events.ts | 4 + core/events/events_var_type_change.ts | 122 ++++++++++++++++++++++ core/events/utils.ts | 5 + tests/mocha/event_var_type_change_test.js | 43 ++++++++ tests/mocha/index.html | 1 + 5 files changed, 175 insertions(+) create mode 100644 core/events/events_var_type_change.ts create mode 100644 tests/mocha/event_var_type_change_test.js diff --git a/core/events/events.ts b/core/events/events.ts index b31cf7dc7..67c78203f 100644 --- a/core/events/events.ts +++ b/core/events/events.ts @@ -43,6 +43,7 @@ import {VarBase, VarBaseJson} from './events_var_base.js'; import {VarCreate, VarCreateJson} from './events_var_create.js'; import {VarDelete, VarDeleteJson} from './events_var_delete.js'; import {VarRename, VarRenameJson} from './events_var_rename.js'; +import {VarTypeChange, VarTypeChangeJson} from './events_var_type_change.js'; import {ViewportChange, ViewportChangeJson} from './events_viewport.js'; import * as eventUtils from './utils.js'; import {FinishedLoading} from './workspace_events.js'; @@ -105,6 +106,8 @@ export {VarDelete}; export {VarDeleteJson}; export {VarRename}; export {VarRenameJson}; +export {VarTypeChange}; +export {VarTypeChangeJson}; export {ViewportChange}; export {ViewportChangeJson}; @@ -140,6 +143,7 @@ export const UI = eventUtils.UI; export const VAR_CREATE = eventUtils.VAR_CREATE; export const VAR_DELETE = eventUtils.VAR_DELETE; export const VAR_RENAME = eventUtils.VAR_RENAME; +export const VAR_TYPE_CHAGE = eventUtils.VAR_TYPE_CHANGE; export const VIEWPORT_CHANGE = eventUtils.VIEWPORT_CHANGE; // Event utils. diff --git a/core/events/events_var_type_change.ts b/core/events/events_var_type_change.ts new file mode 100644 index 000000000..ab8686620 --- /dev/null +++ b/core/events/events_var_type_change.ts @@ -0,0 +1,122 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Class for a variable type change event. + * + * @class + */ + +import * as registry from '../registry.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; + +import {VarBase, VarBaseJson} from './events_var_base.js'; +import * as eventUtils from './utils.js'; +import type {Workspace} from '../workspace.js'; + +/** + * Notifies listeners that a variable's type has changed. + */ +export class VarTypeChange extends VarBase { + override type = eventUtils.VAR_TYPE_CHANGE; + + /** + * @param variable The variable whose type changed. Undefined for a blank event. + * @param oldType The old type of the variable. Undefined for a blank event. + * @param newType The new type of the variable. Undefined for a blank event. + */ + constructor( + variable?: IVariableModel, + public oldType?: string, + public newType?: string, + ) { + super(variable); + } + + /** + * Encode the event as JSON. + * + * @returns JSON representation. + */ + override toJson(): VarTypeChangeJson { + const json = super.toJson() as VarTypeChangeJson; + if (!this.oldType || !this.newType) { + throw new Error( + "The variable's types are undefined. Either pass them to " + + 'the constructor, or call fromJson', + ); + } + json['oldType'] = this.oldType; + json['newType'] = this.newType; + return json; + } + + /** + * Deserializes the JSON event. + * + * @param event The event to append new properties to. Should be a subclass + * of VarTypeChange, but we can't specify that due to the fact that + * parameters to static methods in subclasses must be supertypes of + * parameters to static methods in superclasses. + * @internal + */ + static fromJson( + json: VarTypeChangeJson, + workspace: Workspace, + event?: any, + ): VarTypeChange { + const newEvent = super.fromJson( + json, + workspace, + event ?? new VarTypeChange(), + ) as VarTypeChange; + newEvent.oldType = json['oldType']; + newEvent.newType = json['newType']; + return newEvent; + } + + /** + * Run a variable type change event. + * + * @param forward True if run forward, false if run backward (undo). + */ + override run(forward: boolean) { + const workspace = this.getEventWorkspace_(); + if (!this.varId) { + throw new Error( + 'The var ID is undefined. Either pass a variable to ' + + 'the constructor, or call fromJson', + ); + } + if (!this.oldType || !this.newType) { + throw new Error( + "The variable's types are undefined. Either pass them to " + + 'the constructor, or call fromJson', + ); + } + const variable = workspace.getVariableMap().getVariableById(this.varId); + if (!variable) return; + if (forward) { + workspace.getVariableMap().changeVariableType(variable, this.newType); + } else { + workspace.getVariableMap().changeVariableType(variable, this.oldType); + } + } +} + +export interface VarTypeChangeJson extends VarBaseJson { + oldType: string; + newType: string; +} + +registry.register( + registry.Type.EVENT, + eventUtils.VAR_TYPE_CHANGE, + VarTypeChange, +); diff --git a/core/events/utils.ts b/core/events/utils.ts index 2d434594b..dc05b632e 100644 --- a/core/events/utils.ts +++ b/core/events/utils.ts @@ -111,6 +111,11 @@ export const VAR_DELETE = 'var_delete'; */ export const VAR_RENAME = 'var_rename'; +/** + * Name of event that changes a variable's type. + */ +export const VAR_TYPE_CHANGE = 'var_type_change'; + /** * Name of generic event that records a UI change. */ diff --git a/tests/mocha/event_var_type_change_test.js b/tests/mocha/event_var_type_change_test.js new file mode 100644 index 000000000..d19b0421a --- /dev/null +++ b/tests/mocha/event_var_type_change_test.js @@ -0,0 +1,43 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {assert} from '../../node_modules/chai/chai.js'; +import { + sharedTestSetup, + sharedTestTeardown, +} from './test_helpers/setup_teardown.js'; + +suite('Var Type Change Event', function () { + setup(function () { + sharedTestSetup.call(this); + this.workspace = new Blockly.Workspace(); + }); + + teardown(function () { + sharedTestTeardown.call(this); + }); + + suite('Serialization', function () { + test('variable type change events round-trip through JSON', function () { + const varModel = new Blockly.VariableModel( + this.workspace, + 'name', + 'foo', + 'id', + ); + const origEvent = new Blockly.Events.VarTypeChange( + varModel, + 'foo', + 'bar', + ); + + const json = origEvent.toJson(); + const newEvent = new Blockly.Events.fromJson(json, this.workspace); + + assert.deepEqual(newEvent, origEvent); + }); + }); +}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index ff3467907..58a71e0ac 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -76,6 +76,7 @@ import './event_var_create_test.js'; import './event_var_delete_test.js'; import './event_var_rename_test.js'; + import './event_var_type_change_test.js'; import './event_viewport_test.js'; import './extensions_test.js'; import './field_checkbox_test.js'; From 4b95cb77af7f79ee2b393b30edbf52ff21a5a623 Mon Sep 17 00:00:00 2001 From: Bhargav <143892094+vexora-0@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:01:37 +0530 Subject: [PATCH 037/102] feat: Added blocklyImageField CSS class to image fields https://github.com/google/blockly/issues/8314 (#8439) --- core/field_image.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/field_image.ts b/core/field_image.ts index 6e83e3405..650575f59 100644 --- a/core/field_image.ts +++ b/core/field_image.ts @@ -151,6 +151,10 @@ export class FieldImage extends Field { this.value_ as string, ); + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyImageField'); + } + if (this.clickHandler) { this.imageElement.style.cursor = 'pointer'; } From dc1f276759e55ba3d36fe2eb675e71c25159e277 Mon Sep 17 00:00:00 2001 From: dakshkanaujia <58256644+dakshkanaujia@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:54:15 +0530 Subject: [PATCH 038/102] fix!: Redundant blockly non selectable #8328 (#8433) * Remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes * Removed .gitpod file * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes https://github.com/google/blockly/issues/8328 * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes #8328 * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes #8328 * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes #8328 * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes #8328 * fix: remove redundant blocklyNonSelectable class and integrate non-selectability into existing classes --- core/css.ts | 12 ++++++------ core/menu.ts | 3 ++- core/toolbox/toolbox.ts | 4 +++- tests/mocha/toolbox_test.js | 5 +---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/css.ts b/core/css.ts index 7a0053604..00d4f1be4 100644 --- a/core/css.ts +++ b/core/css.ts @@ -80,12 +80,6 @@ let content = ` touch-action: none; } -.blocklyNonSelectable { - user-select: none; - -ms-user-select: none; - -webkit-user-select: none; -} - .blocklyBlockCanvas.blocklyCanvasTransitioning, .blocklyBubbleCanvas.blocklyCanvasTransitioning { transition: transform .5s; @@ -430,6 +424,9 @@ input[type=number] { } .blocklyWidgetDiv .blocklyMenu { + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; background: #fff; border: 1px solid transparent; box-shadow: 0 0 3px 1px rgba(0,0,0,.3); @@ -449,6 +446,9 @@ input[type=number] { } .blocklyDropDownDiv .blocklyMenu { + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; background: inherit; /* Compatibility with gapi, reset from goog-menu */ border: inherit; /* Compatibility with gapi, reset from goog-menu */ font: normal 13px "Helvetica Neue", Helvetica, sans-serif; diff --git a/core/menu.ts b/core/menu.ts index 31eda5c3d..6085d9274 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -82,9 +82,10 @@ export class Menu { * @param container Element upon which to append this menu. * @returns The menu's root DOM element. */ + render(container: Element): HTMLDivElement { const element = document.createElement('div'); - element.className = 'blocklyMenu blocklyNonSelectable'; + element.className = 'blocklyMenu'; element.tabIndex = 0; if (this.roleName) { aria.setRole(element, this.roleName); diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index 1e2a5970f..cd91b2d8a 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -199,7 +199,6 @@ export class Toolbox const toolboxContainer = document.createElement('div'); toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v'); dom.addClass(toolboxContainer, 'blocklyToolboxDiv'); - dom.addClass(toolboxContainer, 'blocklyNonSelectable'); toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); return toolboxContainer; } @@ -1104,6 +1103,9 @@ Css.register(` /* Category tree in Toolbox. */ .blocklyToolboxDiv { + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; background-color: #ddd; overflow-x: visible; overflow-y: auto; diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index b3cd45090..755f08cf8 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -47,10 +47,7 @@ suite('Toolbox', function () { test('Init called -> HtmlDiv is inserted before parent node', function () { const toolboxDiv = Blockly.common.getMainWorkspace().getInjectionDiv() .childNodes[0]; - assert.equal( - toolboxDiv.className, - 'blocklyToolboxDiv blocklyNonSelectable', - ); + assert.equal(toolboxDiv.className, 'blocklyToolboxDiv'); }); test('Init called -> Toolbox is subscribed to background and foreground colour', function () { const themeManager = this.toolbox.workspace_.getThemeManager(); From 9c88970d463b851820455d85de7b74e73d2209c4 Mon Sep 17 00:00:00 2001 From: Shreshtha Sharma <145495563+Shreshthaaa@users.noreply.github.com> Date: Wed, 31 Jul 2024 05:20:38 +0530 Subject: [PATCH 039/102] feat: added blocklyNotDetetable class to block_svg (#8406) * feat: added blocklynotdetetable class to block_svg * feat: added blocklynotdetetable class to block_svg --- core/block_svg.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index a289db556..7bdbd5b79 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -1079,6 +1079,20 @@ export class BlockSvg } } + /** + * Add blocklyNotDeletable class when block is not deletable + * Or remove class when block is deletable + */ + override setDeletable(deletable: boolean) { + super.setDeletable(deletable); + + if (deletable) { + dom.removeClass(this.svgGroup_, 'blocklyNotDeletable'); + } else { + dom.addClass(this.svgGroup_, 'blocklyNotDeletable'); + } + } + /** * Set whether the block is highlighted or not. Block highlighting is * often used to visually mark blocks currently being executed. From 203e422977a39efca29ed1fb00c74d6eaa3f973d Mon Sep 17 00:00:00 2001 From: Tejas Ghatule <141946130+CodeMaverick2@users.noreply.github.com> Date: Wed, 31 Jul 2024 06:42:48 +0530 Subject: [PATCH 040/102] feat: add the block's type as a CSS class to the block's root SVG (#8428) * feat: Added the block's type as a CSS class to the block's root SVG https://github.com/google/blockly/issues/8268 * fix: Added the block type as a CSS class to the blocks root SVG https://github.com/google/blockly/issues/8268 --- core/block_svg.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/block_svg.ts b/core/block_svg.ts index 7bdbd5b79..acead527a 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -184,6 +184,9 @@ export class BlockSvg this.workspace = workspace; this.svgGroup_ = dom.createSvgElement(Svg.G, {}); + if (prototypeName) { + dom.addClass(this.svgGroup_, prototypeName); + } /** A block style object. */ this.style = workspace.getRenderer().getConstants().getBlockStyle(null); From 6393ab39ce2c9aaafd01c3b7247d1f675a30e642 Mon Sep 17 00:00:00 2001 From: surajguduru <140954256+surajguduru@users.noreply.github.com> Date: Wed, 31 Jul 2024 06:56:17 +0530 Subject: [PATCH 041/102] feat: add blocklyLabelField CSS class to label fields (#8423) --- core/field_label.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/field_label.ts b/core/field_label.ts index 2b77b0d25..0a73d0fb2 100644 --- a/core/field_label.ts +++ b/core/field_label.ts @@ -74,6 +74,9 @@ export class FieldLabel extends Field { if (this.class) { dom.addClass(this.getTextElement(), this.class); } + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyLabelField'); + } } /** From 17db6039b5ec1230741746b1df14e0225c7252d2 Mon Sep 17 00:00:00 2001 From: UtkershBasnet <119008923+UtkershBasnet@users.noreply.github.com> Date: Thu, 1 Aug 2024 04:03:25 +0530 Subject: [PATCH 042/102] fix!: Rename blocklyTreeIconOpen to blocklyToolboxCategoryIconOpen (#8440) --- core/toolbox/category.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index b47ba657c..653d848ec 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -138,7 +138,7 @@ export class ToolboxCategory 'label': 'blocklyTreeLabel', 'contents': 'blocklyToolboxCategoryGroup', 'selected': 'blocklyTreeSelected', - 'openicon': 'blocklyTreeIconOpen', + 'openicon': 'blocklyToolboxCategoryIconOpen', 'closedicon': 'blocklyTreeIconClosed', }; } @@ -708,11 +708,11 @@ Css.register(` background-position: 0 -17px; } -.blocklyTreeIconOpen { +.blocklyToolboxCategoryIconOpen { background-position: -16px -1px; } -.blocklyTreeSelected>.blocklyTreeIconOpen { +.blocklyTreeSelected>.blocklyToolboxCategoryIconOpen { background-position: -16px -17px; } From 8a1b01568ef6cb4f181c49d8e958d60f82c85c06 Mon Sep 17 00:00:00 2001 From: Aayush Khopade <145590889+Apocalypse96@users.noreply.github.com> Date: Thu, 1 Aug 2024 04:04:14 +0530 Subject: [PATCH 043/102] feat: Add a blocklyNumberField CSS class to number fields (#8414) * feat: Add a blocklyNumberField CSS class to number fields https://github.com/google/blockly/issues/8313 * feat: add 'blocklyNumberField' CSS class to FieldNumber Fixes https://github.com/google/blockly/issues/8313 --- core/field_number.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/field_number.ts b/core/field_number.ts index e8e51d060..5aaf94c4c 100644 --- a/core/field_number.ts +++ b/core/field_number.ts @@ -19,6 +19,7 @@ import { FieldInputValidator, } from './field_input.js'; import * as aria from './utils/aria.js'; +import * as dom from './utils/dom.js'; /** * Class for an editable number field. @@ -307,6 +308,19 @@ export class FieldNumber extends FieldInput { return htmlInput; } + /** + * Initialize the field's DOM. + * + * @override + */ + + public override initView() { + super.initView(); + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyNumberField'); + } + } + /** * Construct a FieldNumber from a JSON arg object. * From 6887940e22262d7d571fd5df2546e4bf0cb244b3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 2 Aug 2024 10:57:15 -0700 Subject: [PATCH 044/102] feat: add a method for subclasses of FieldVariable to get the default type. (#8453) --- core/field_variable.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/field_variable.ts b/core/field_variable.ts index 9dbba4ca3..23ea7c15a 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -322,6 +322,15 @@ export class FieldVariable extends FieldDropdown { return this.variable; } + /** + * Gets the type of this field's default variable. + * + * @returns The default type for this variable field. + */ + protected getDefaultType(): string { + return this.defaultType; + } + /** * Gets the validation function for this field, or null if not set. * Returns null if the variable is not set, because validators should not From f10c3b0ee8f579f92b3faffffac1fe42a9f8de45 Mon Sep 17 00:00:00 2001 From: omwagh28 <151948718+omwagh28@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:56:05 +0530 Subject: [PATCH 045/102] fix!: Renamed the blocklyTreeSelected CSS class to blocklyToolboxSelected https://github.com/google/blockly/issues/8351 (#8459) --- core/toolbox/category.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index 653d848ec..06f219e5e 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -137,7 +137,7 @@ export class ToolboxCategory 'icon': 'blocklyToolboxCategoryIcon', 'label': 'blocklyTreeLabel', 'contents': 'blocklyToolboxCategoryGroup', - 'selected': 'blocklyTreeSelected', + 'selected': 'blocklyToolboxSelected', 'openicon': 'blocklyToolboxCategoryIconOpen', 'closedicon': 'blocklyTreeIconClosed', }; @@ -659,7 +659,7 @@ export type CssConfig = ToolboxCategory.CssConfig; /** CSS for Toolbox. See css.js for use. */ Css.register(` -.blocklyToolboxCategory:not(.blocklyTreeSelected):hover { +.blocklyToolboxCategory:not(.blocklyToolboxSelected):hover { background-color: rgba(255, 255, 255, .2); } @@ -700,11 +700,11 @@ Css.register(` background-position: 0 -1px; } -.blocklyTreeSelected>.blocklyTreeIconClosed { +.blocklyToolboxSelected>.blocklyTreeIconClosed { background-position: -32px -17px; } -.blocklyToolboxDiv[dir="RTL"] .blocklyTreeSelected>.blocklyTreeIconClosed { +.blocklyToolboxDiv[dir="RTL"] .blocklyToolboxSelected>.blocklyTreeIconClosed { background-position: 0 -17px; } @@ -712,7 +712,7 @@ Css.register(` background-position: -16px -1px; } -.blocklyTreeSelected>.blocklyToolboxCategoryIconOpen { +.blocklyToolboxSelected>.blocklyToolboxCategoryIconOpen { background-position: -16px -17px; } @@ -727,7 +727,7 @@ Css.register(` cursor: url("<<>>/handdelete.cur"), auto; } -.blocklyTreeSelected .blocklyTreeLabel { +.blocklyToolboxSelected .blocklyTreeLabel { color: #fff; } `); From 9374c028d4461512419c72243d254402efcd164a Mon Sep 17 00:00:00 2001 From: Shreshtha Sharma <145495563+Shreshthaaa@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:05:35 +0530 Subject: [PATCH 046/102] feat: added block's style as a CSS class to block's root SVG (#8436) * fix: added block's style as a CSS class to block's root SVG * fix: added block's style as a CSS class to block's root SVG * fix: added block's style as a CSS class to block's root SVG --- core/block_svg.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/block_svg.ts b/core/block_svg.ts index acead527a..0da81f01d 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -1178,7 +1178,10 @@ export class BlockSvg .getRenderer() .getConstants() .getBlockStyle(blockStyleName); - this.styleName_ = blockStyleName; + + if (this.styleName_) { + dom.removeClass(this.svgGroup_, this.styleName_); + } if (blockStyle) { this.hat = blockStyle.hat; @@ -1188,6 +1191,9 @@ export class BlockSvg this.style = blockStyle; this.applyColour(); + + dom.addClass(this.svgGroup_, blockStyleName); + this.styleName_ = blockStyleName; } else { throw Error('Invalid style name: ' + blockStyleName); } From 68dda116231f5dc347287a054098edfdaeba4de1 Mon Sep 17 00:00:00 2001 From: aishwaryavenkatesan <114367358+aishwaryavenkatesan@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:07:34 -0400 Subject: [PATCH 047/102] fix!: deleted styles without associated classes from css.ts, issue #8285 (#8465) --- core/css.ts | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/core/css.ts b/core/css.ts index 00d4f1be4..5d1f07499 100644 --- a/core/css.ts +++ b/core/css.ts @@ -134,18 +134,6 @@ let content = ` border-color: inherit; } -.blocklyDropDownButton { - display: inline-block; - float: left; - padding: 0; - margin: 4px; - border-radius: 4px; - outline: none; - border: 1px solid; - transition: box-shadow .1s; - cursor: pointer; -} - .blocklyArrowTop { border-top: 1px solid; border-left: 1px solid; @@ -160,21 +148,6 @@ let content = ` border-color: inherit; } -.blocklyResizeSE { - cursor: se-resize; - fill: #aaa; -} - -.blocklyResizeSW { - cursor: sw-resize; - fill: #aaa; -} - -.blocklyResizeLine { - stroke: #515A5A; - stroke-width: 1; -} - .blocklyHighlightedConnectionPath { fill: none; stroke: #fc3; @@ -270,10 +243,6 @@ let content = ` cursor: inherit; } -.blocklyHidden { - display: none; -} - .blocklyFieldDropdown:not(.blocklyHidden) { display: block; } From 59fab944f4ba61bb2e6e3685053ae467ccdb8056 Mon Sep 17 00:00:00 2001 From: Adityajaiswal03 <140907684+Adityajaiswal03@users.noreply.github.com> Date: Tue, 13 Aug 2024 01:40:38 +0530 Subject: [PATCH 048/102] feat: change blocklyEditableText to blocklyEditableField and blocklyNonEditableText to blocklyNonEditableField BREAKING CHANGE: The blocklyEditableText and blocklyNonEditableText identifiers have been renamed to blocklyEditableField and blocklyNonEditableField respectively. This change may require updates to any existing code that references the old identifiers. (#8475) --- core/css.ts | 2 +- core/field.ts | 8 ++++---- core/renderers/common/constants.ts | 10 +++++----- core/renderers/zelos/constants.ts | 16 ++++++++-------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/css.ts b/core/css.ts index 5d1f07499..c7ae55397 100644 --- a/core/css.ts +++ b/core/css.ts @@ -219,7 +219,7 @@ let content = ` font-family: monospace; } -.blocklyNonEditableText>text { +.blocklyNonEditableField>text { pointer-events: none; } diff --git a/core/field.ts b/core/field.ts index 229c3626d..2d50c04eb 100644 --- a/core/field.ts +++ b/core/field.ts @@ -534,12 +534,12 @@ export abstract class Field return; } if (this.enabled_ && block.isEditable()) { - dom.addClass(group, 'blocklyEditableText'); - dom.removeClass(group, 'blocklyNonEditableText'); + dom.addClass(group, 'blocklyEditableField'); + dom.removeClass(group, 'blocklyNonEditableField'); group.style.cursor = this.CURSOR; } else { - dom.addClass(group, 'blocklyNonEditableText'); - dom.removeClass(group, 'blocklyEditableText'); + dom.addClass(group, 'blocklyNonEditableField'); + dom.removeClass(group, 'blocklyEditableField'); group.style.cursor = ''; } } diff --git a/core/renderers/common/constants.ts b/core/renderers/common/constants.ts index 568b7f444..c4ea9b24e 100644 --- a/core/renderers/common/constants.ts +++ b/core/renderers/common/constants.ts @@ -1132,14 +1132,14 @@ export class ConstantProvider { `${selector} .blocklyText {`, `fill: #fff;`, `}`, - `${selector} .blocklyNonEditableText>rect,`, - `${selector} .blocklyEditableText>rect {`, + `${selector} .blocklyNonEditableField>rect,`, + `${selector} .blocklyEditableField>rect {`, `fill: ${this.FIELD_BORDER_RECT_COLOUR};`, `fill-opacity: .6;`, `stroke: none;`, `}`, - `${selector} .blocklyNonEditableText>text,`, - `${selector} .blocklyEditableText>text {`, + `${selector} .blocklyNonEditableField>text,`, + `${selector} .blocklyEditableField>text {`, `fill: #000;`, `}`, @@ -1154,7 +1154,7 @@ export class ConstantProvider { `}`, // Editable field hover. - `${selector} .blocklyEditableText:not(.blocklyEditing):hover>rect {`, + `${selector} .blocklyEditableField:not(.blocklyEditing):hover>rect {`, `stroke: #fff;`, `stroke-width: 2;`, `}`, diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index 22e3f3782..28c2cb4fc 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -802,14 +802,14 @@ export class ConstantProvider extends BaseConstantProvider { `${selector} .blocklyText {`, `fill: #fff;`, `}`, - `${selector} .blocklyNonEditableText>rect:not(.blocklyDropdownRect),`, - `${selector} .blocklyEditableText>rect:not(.blocklyDropdownRect) {`, + `${selector} .blocklyNonEditableField>rect:not(.blocklyDropdownRect),`, + `${selector} .blocklyEditableField>rect:not(.blocklyDropdownRect) {`, `fill: ${this.FIELD_BORDER_RECT_COLOUR};`, `}`, - `${selector} .blocklyNonEditableText>text,`, - `${selector} .blocklyEditableText>text,`, - `${selector} .blocklyNonEditableText>g>text,`, - `${selector} .blocklyEditableText>g>text {`, + `${selector} .blocklyNonEditableField>text,`, + `${selector} .blocklyEditableField>text,`, + `${selector} .blocklyNonEditableField>g>text,`, + `${selector} .blocklyEditableField>g>text {`, `fill: #575E75;`, `}`, @@ -825,9 +825,9 @@ export class ConstantProvider extends BaseConstantProvider { // Editable field hover. `${selector} .blocklyDraggable:not(.blocklyDisabled)`, - ` .blocklyEditableText:not(.blocklyEditing):hover>rect,`, + ` .blocklyEditableField:not(.blocklyEditing):hover>rect,`, `${selector} .blocklyDraggable:not(.blocklyDisabled)`, - ` .blocklyEditableText:not(.blocklyEditing):hover>.blocklyPath {`, + ` .blocklyEditableField:not(.blocklyEditing):hover>.blocklyPath {`, `stroke: #fff;`, `stroke-width: 2;`, `}`, From 731fb40faa38ad47e23963b27c36f33daac58711 Mon Sep 17 00:00:00 2001 From: Jeremiah Saunders <46662314+UCYT5040@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:14:05 -0500 Subject: [PATCH 049/102] feat: implement `WorkspaceSvg` class manipulation (#8473) * Implement addClass and removeClass functions * feat: implement `WorkspaceSvg` class manipulation * Update core/workspace_svg.ts * Update core/workspace_svg.ts --- core/workspace_svg.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 55a7540bd..910171007 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -2432,6 +2432,28 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { // We could call scroll here, but that has extra checks we don't need to do. this.translate(x, y); } + + /** + * Adds a CSS class to the workspace. + * + * @param className Name of class to add. + */ + addClass(className: string) { + if (this.injectionDiv) { + dom.addClass(this.injectionDiv, className); + } + } + + /** + * Removes a CSS class from the workspace. + * + * @param className Name of class to remove. + */ + removeClass(className: string) { + if (this.injectionDiv) { + dom.removeClass(this.injectionDiv, className); + } + } } /** From 64fd9ad89a5d48ccc18708d322340ed1523fa753 Mon Sep 17 00:00:00 2001 From: Shreshtha Sharma <145495563+Shreshthaaa@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:36:27 +0530 Subject: [PATCH 050/102] =?UTF-8?q?feat:=20added=20`blocklyHighlighted`=20?= =?UTF-8?q?CSS=20class=20to=20highlighted=20block's=20root=E2=80=A6=20(#84?= =?UTF-8?q?07)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: added 'blocklyHighlighted' CSS class to highlighted block's root svg * fix: added 'blocklyHighlighted' CSS class to highlighted block's root svg * fix: added 'blocklyHighlighted' CSS class to highlighted block's root svg * fix: added 'blocklyHighlighted' CSS class to highlighted block's root svg * fix: added 'blocklyHighlighted' CSS class to highlighted block's root svg --- core/renderers/common/path_object.ts | 3 +++ core/renderers/geras/path_object.ts | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/renderers/common/path_object.ts b/core/renderers/common/path_object.ts index c5ac5db20..12e23b6c4 100644 --- a/core/renderers/common/path_object.ts +++ b/core/renderers/common/path_object.ts @@ -170,14 +170,17 @@ export class PathObject implements IPathObject { * * @param enable True if highlighted. */ + updateHighlighted(enable: boolean) { if (enable) { this.svgPath.setAttribute( 'filter', 'url(#' + this.constants.embossFilterId + ')', ); + this.setClass_('blocklyHighlighted', true); } else { this.svgPath.setAttribute('filter', 'none'); + this.setClass_('blocklyHighlighted', false); } } diff --git a/core/renderers/geras/path_object.ts b/core/renderers/geras/path_object.ts index 6b058e5a7..321302a26 100644 --- a/core/renderers/geras/path_object.ts +++ b/core/renderers/geras/path_object.ts @@ -103,14 +103,10 @@ export class PathObject extends BasePathObject { } override updateHighlighted(highlighted: boolean) { + super.updateHighlighted(highlighted); if (highlighted) { - this.svgPath.setAttribute( - 'filter', - 'url(#' + this.constants.embossFilterId + ')', - ); this.svgPathLight.style.display = 'none'; } else { - this.svgPath.setAttribute('filter', 'none'); this.svgPathLight.style.display = 'inline'; } } From 14d119b204d1d3cbad054f413e9de971ea9cc7d4 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 19 Aug 2024 15:47:00 -0700 Subject: [PATCH 051/102] fix: improve prompting when deleting variables (#8529) * fix: improve variable deletion behaviors. * fix: don't prompt about deletion of only 1 variable block when triggered programmatically. * fix: include the triggering block in the count of referencing blocks * fix: only count the triggering block as a referencing block if it's not in the flyout --- blocks/variables.ts | 9 +++++---- blocks/variables_dynamic.ts | 9 +++++---- core/field_variable.ts | 7 ++++++- core/flyout_button.ts | 2 +- core/variables.ts | 18 ++++++++++++++---- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/blocks/variables.ts b/blocks/variables.ts index 8ac038fb2..987c5ab2f 100644 --- a/blocks/variables.ts +++ b/blocks/variables.ts @@ -165,11 +165,12 @@ const deleteOptionCallbackFactory = function ( block: VariableBlock, ): () => void { return function () { - const workspace = block.workspace; const variableField = block.getField('VAR') as FieldVariable; - const variable = variableField.getVariable()!; - workspace.deleteVariableById(variable.getId()); - (workspace as WorkspaceSvg).refreshToolboxSelection(); + const variable = variableField.getVariable(); + if (variable) { + Variables.deleteVariable(variable.getWorkspace(), variable, block); + } + (block.workspace as WorkspaceSvg).refreshToolboxSelection(); }; }; diff --git a/blocks/variables_dynamic.ts b/blocks/variables_dynamic.ts index ff94d8c96..9c1167a19 100644 --- a/blocks/variables_dynamic.ts +++ b/blocks/variables_dynamic.ts @@ -176,11 +176,12 @@ const renameOptionCallbackFactory = function (block: VariableBlock) { */ const deleteOptionCallbackFactory = function (block: VariableBlock) { return function () { - const workspace = block.workspace; const variableField = block.getField('VAR') as FieldVariable; - const variable = variableField.getVariable()!; - workspace.deleteVariableById(variable.getId()); - (workspace as WorkspaceSvg).refreshToolboxSelection(); + const variable = variableField.getVariable(); + if (variable) { + Variables.deleteVariable(variable.getWorkspace(), variable, block); + } + (block.workspace as WorkspaceSvg).refreshToolboxSelection(); }; }; diff --git a/core/field_variable.ts b/core/field_variable.ts index 23ea7c15a..042299dc2 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -27,6 +27,7 @@ import * as fieldRegistry from './field_registry.js'; import * as internalConstants from './internal_constants.js'; import type {Menu} from './menu.js'; import type {MenuItem} from './menuitem.js'; +import {WorkspaceSvg} from './workspace_svg.js'; import {Msg} from './msg.js'; import * as parsing from './utils/parsing.js'; import {Size} from './utils/size.js'; @@ -514,7 +515,11 @@ export class FieldVariable extends FieldDropdown { return; } else if (id === internalConstants.DELETE_VARIABLE_ID && this.variable) { // Delete variable. - this.sourceBlock_.workspace.deleteVariableById(this.variable.getId()); + const workspace = this.variable.getWorkspace(); + Variables.deleteVariable(workspace, this.variable, this.sourceBlock_); + if (workspace instanceof WorkspaceSvg) { + workspace.refreshToolboxSelection(); + } return; } } diff --git a/core/flyout_button.ts b/core/flyout_button.ts index e73403d77..dfc7b9507 100644 --- a/core/flyout_button.ts +++ b/core/flyout_button.ts @@ -179,7 +179,7 @@ export class FlyoutButton implements IASTNodeLocationSvg { fontWeight, fontFamily, ); - this.height = fontMetrics.height; + this.height = this.height || fontMetrics.height; if (!this.isFlyoutLabel) { this.width += 2 * FlyoutButton.TEXT_MARGIN_X; diff --git a/core/variables.ts b/core/variables.ts index 5da228f6c..bad87df0b 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -714,15 +714,20 @@ export function getVariableUsesById(workspace: Workspace, id: string): Block[] { * * @param workspace The workspace from which to delete the variable. * @param variable The variable to delete. + * @param triggeringBlock The block from which this deletion was triggered, if + * any. Used to exclude it from checking and warning about blocks + * referencing the variable being deleted. */ export function deleteVariable( workspace: Workspace, variable: IVariableModel, + triggeringBlock?: Block, ) { // Check whether this variable is a function parameter before deleting. const variableName = variable.getName(); const uses = getVariableUsesById(workspace, variable.getId()); - for (let i = 0, block; (block = uses[i]); i++) { + for (let i = uses.length - 1; i >= 0; i--) { + const block = uses[i]; if ( block.type === 'procedures_defnoreturn' || block.type === 'procedures_defreturn' @@ -734,12 +739,15 @@ export function deleteVariable( dialog.alert(deleteText); return; } + if (block === triggeringBlock) { + uses.splice(i, 1); + } } - if (uses.length > 1) { + if ((triggeringBlock && uses.length) || uses.length > 1) { // Confirm before deleting multiple blocks. const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION'] - .replace('%1', String(uses.length)) + .replace('%1', String(uses.length + (triggeringBlock ? 1 : 0))) .replace('%2', variableName); dialog.confirm(confirmText, (ok) => { if (ok && variable) { @@ -747,7 +755,9 @@ export function deleteVariable( } }); } else { - // No confirmation necessary for a single block. + // No confirmation necessary when the block that triggered the deletion is + // the only block referencing this variable or if only one block referencing + // this variable exists and the deletion was triggered programmatically. workspace.getVariableMap().deleteVariable(variable); } } From d6125d4fb94ac7f4ab9e57a2944a5aa1c6ead328 Mon Sep 17 00:00:00 2001 From: Arun Chandran <53257113+Arun-cn@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:31:07 +0530 Subject: [PATCH 052/102] fix!: Remove the blocklyMenuItemHighlight CSS class and use the hover (#8536) * fix!: Remove the blocklyMenuItemHighlight CSS class and use the hover * fix: Remove setHighlighted method in menuitem * fix: Remove blocklymenuitemhighlight css class --- core/css.ts | 3 +-- core/menu.ts | 2 -- core/menuitem.ts | 21 --------------------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/core/css.ts b/core/css.ts index c7ae55397..d18d930a9 100644 --- a/core/css.ts +++ b/core/css.ts @@ -445,8 +445,7 @@ input[type=number] { cursor: inherit; } -/* State: hover. */ -.blocklyMenuItemHighlight { +.blocklyMenuItem:hover { background-color: rgba(0,0,0,.1); } diff --git a/core/menu.ts b/core/menu.ts index 6085d9274..f01c1edfb 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -249,11 +249,9 @@ export class Menu { setHighlighted(item: MenuItem | null) { const currentHighlighted = this.highlightedItem; if (currentHighlighted) { - currentHighlighted.setHighlighted(false); this.highlightedItem = null; } if (item) { - item.setHighlighted(true); this.highlightedItem = item; // Bring the highlighted item into view. This has no effect if the menu is // not scrollable. diff --git a/core/menuitem.ts b/core/menuitem.ts index 7fff1a72b..3d5b28b70 100644 --- a/core/menuitem.ts +++ b/core/menuitem.ts @@ -12,7 +12,6 @@ // Former goog.module ID: Blockly.MenuItem import * as aria from './utils/aria.js'; -import * as dom from './utils/dom.js'; import * as idGenerator from './utils/idgenerator.js'; /** @@ -68,7 +67,6 @@ export class MenuItem { 'blocklyMenuItem ' + (this.enabled ? '' : 'blocklyMenuItemDisabled ') + (this.checked ? 'blocklyMenuItemSelected ' : '') + - (this.highlight ? 'blocklyMenuItemHighlight ' : '') + (this.rightToLeft ? 'blocklyMenuItemRtl ' : ''); const content = document.createElement('div'); @@ -177,25 +175,6 @@ export class MenuItem { this.checked = checked; } - /** - * Highlights or unhighlights the component. - * - * @param highlight Whether to highlight or unhighlight the component. - * @internal - */ - setHighlighted(highlight: boolean) { - this.highlight = highlight; - const el = this.getElement(); - if (el && this.isEnabled()) { - const name = 'blocklyMenuItemHighlight'; - if (highlight) { - dom.addClass(el, name); - } else { - dom.removeClass(el, name); - } - } - } - /** * Returns true if the menu item is enabled, false otherwise. * From ba0762348d76f7e31c4d2144f295a2613a9273c1 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 21 Aug 2024 13:57:32 -0700 Subject: [PATCH 053/102] fix: display the correct variable reference count when deleting a variable. (#8549) --- core/variables.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/variables.ts b/core/variables.ts index bad87df0b..8c06a8d91 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -747,7 +747,13 @@ export function deleteVariable( if ((triggeringBlock && uses.length) || uses.length > 1) { // Confirm before deleting multiple blocks. const confirmText = Msg['DELETE_VARIABLE_CONFIRMATION'] - .replace('%1', String(uses.length + (triggeringBlock ? 1 : 0))) + .replace( + '%1', + String( + uses.length + + (triggeringBlock && !triggeringBlock.workspace.isFlyout ? 1 : 0), + ), + ) .replace('%2', variableName); dialog.confirm(confirmText, (ok) => { if (ok && variable) { From cb1c055bffdeb4a2a3298b4c6b58b941c442d4bc Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 3 Sep 2024 13:25:18 -0700 Subject: [PATCH 054/102] refactor: use getters for flyout width and height. (#8564) --- core/flyout_horizontal.ts | 10 +++++----- core/flyout_vertical.ts | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index 6e77636e8..c23dede74 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -98,7 +98,7 @@ export class HorizontalFlyout extends Flyout { if (atTop) { y = toolboxMetrics.height; } else { - y = viewMetrics.height - this.height_; + y = viewMetrics.height - this.getHeight(); } } else { if (atTop) { @@ -116,7 +116,7 @@ export class HorizontalFlyout extends Flyout { // to align the bottom edge of the flyout with the bottom edge of the // blocklyDiv, we calculate the full height of the div minus the height // of the flyout. - y = viewMetrics.height + absoluteMetrics.top - this.height_; + y = viewMetrics.height + absoluteMetrics.top - this.getHeight(); } } @@ -133,13 +133,13 @@ export class HorizontalFlyout extends Flyout { this.width_ = targetWorkspaceViewMetrics.width; const edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS; - const edgeHeight = this.height_ - this.CORNER_RADIUS; + const edgeHeight = this.getHeight() - this.CORNER_RADIUS; this.setBackgroundPath(edgeWidth, edgeHeight); const x = this.getX(); const y = this.getY(); - this.positionAt_(this.width_, this.height_, x, y); + this.positionAt_(this.getWidth(), this.getHeight(), x, y); } /** @@ -380,7 +380,7 @@ export class HorizontalFlyout extends Flyout { flyoutHeight *= this.workspace_.scale; flyoutHeight += Scrollbar.scrollbarThickness; - if (this.height_ !== flyoutHeight) { + if (this.getHeight() !== flyoutHeight) { for (let i = 0, block; (block = blocks[i]); i++) { if (this.rectMap_.has(block)) { this.moveRectToBlock_(this.rectMap_.get(block)!, block); diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index 59682a390..374b0c33a 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -86,7 +86,7 @@ export class VerticalFlyout extends Flyout { if (this.toolboxPosition_ === toolbox.Position.LEFT) { x = toolboxMetrics.width; } else { - x = viewMetrics.width - this.width_; + x = viewMetrics.width - this.getWidth(); } } else { if (this.toolboxPosition_ === toolbox.Position.LEFT) { @@ -104,7 +104,7 @@ export class VerticalFlyout extends Flyout { // to align the right edge of the flyout with the right edge of the // blocklyDiv, we calculate the full width of the div minus the width // of the flyout. - x = viewMetrics.width + absoluteMetrics.left - this.width_; + x = viewMetrics.width + absoluteMetrics.left - this.getWidth(); } } @@ -130,7 +130,7 @@ export class VerticalFlyout extends Flyout { const targetWorkspaceViewMetrics = metricsManager.getViewMetrics(); this.height_ = targetWorkspaceViewMetrics.height; - const edgeWidth = this.width_ - this.CORNER_RADIUS; + const edgeWidth = this.getWidth() - this.CORNER_RADIUS; const edgeHeight = targetWorkspaceViewMetrics.height - 2 * this.CORNER_RADIUS; this.setBackgroundPath(edgeWidth, edgeHeight); @@ -138,7 +138,7 @@ export class VerticalFlyout extends Flyout { const x = this.getX(); const y = this.getY(); - this.positionAt_(this.width_, this.height_, x, y); + this.positionAt_(this.getWidth(), this.getHeight(), x, y); } /** @@ -349,7 +349,7 @@ export class VerticalFlyout extends Flyout { flyoutWidth *= this.workspace_.scale; flyoutWidth += Scrollbar.scrollbarThickness; - if (this.width_ !== flyoutWidth) { + if (this.getWidth() !== flyoutWidth) { for (let i = 0, block; (block = blocks[i]); i++) { if (this.RTL) { // With the flyoutWidth known, right-align the blocks. From def80b3f31beb379a42fdeed620265c7fbbd8ab9 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 11 Sep 2024 12:37:32 -0700 Subject: [PATCH 055/102] fix: improve flyout performance (#8571) * fix: improve flyout performance * refactor: don't call position() in show() The later call to reflow() itself winds up calling position(), so this calculation is redundant. --- core/flyout_base.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 18f84480c..2ea85a0df 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -402,7 +402,14 @@ export abstract class Flyout this.wheel_, ), ); - this.filterWrapper = this.filterForCapacity.bind(this); + this.filterWrapper = (event) => { + if ( + event.type === eventUtils.BLOCK_CREATE || + event.type === eventUtils.BLOCK_DELETE + ) { + this.filterForCapacity(); + } + }; this.targetWorkspace.addChangeListener(this.filterWrapper); // Dragging the flyout up and down. @@ -704,10 +711,17 @@ export abstract class Flyout this.filterForCapacity(); - // Correctly position the flyout's scrollbar when it opens. - this.position(); - - this.reflowWrapper = this.reflow.bind(this); + // Listen for block change events, and reflow the flyout in response. This + // accommodates e.g. resizing a non-autoclosing flyout in response to the + // user typing long strings into fields on the blocks in the flyout. + this.reflowWrapper = (event) => { + if ( + event.type === eventUtils.BLOCK_CHANGE || + event.type === eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE + ) { + this.reflow(); + } + }; this.workspace_.addChangeListener(this.reflowWrapper); this.emptyRecycledBlocks(); } From 732bd7f6160ce9da4cc3063b3f2b47b3d204f446 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 13 Sep 2024 09:58:57 -0700 Subject: [PATCH 056/102] fix: size text with computed styles even when hidden (#8572) * fix: size text with computed styles even when hidden * refactor: remove unneeded try/catch. --- core/utils/dom.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/core/utils/dom.ts b/core/utils/dom.ts index e318e7e91..87019dbb2 100644 --- a/core/utils/dom.ts +++ b/core/utils/dom.ts @@ -208,16 +208,14 @@ export function getTextWidth(textElement: SVGTextElement): number { } } - // Attempt to compute fetch the width of the SVG text element. - try { - width = textElement.getComputedTextLength(); - } catch (e) { - // In other cases where we fail to get the computed text. Instead, use an - // approximation and do not cache the result. At some later point in time - // when the block is inserted into the visible DOM, this method will be - // called again and, at that point in time, will not throw an exception. - return textElement.textContent!.length * 8; - } + // Compute the width of the SVG text element. + const style = window.getComputedStyle(textElement); + width = getFastTextWidthWithSizeString( + textElement, + style.fontSize, + style.fontWeight, + style.fontFamily, + ); // Cache the computed width and return. if (cacheWidths) { From 476d454c05b1c7b72f7a9c3489ba452d11513d99 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 16 Sep 2024 09:14:56 -0700 Subject: [PATCH 057/102] fix: include potential variables in variable dropdowns in the flyout (#8574) --- core/field_variable.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core/field_variable.ts b/core/field_variable.ts index 042299dc2..0c890f4d7 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -572,15 +572,23 @@ export class FieldVariable extends FieldDropdown { } const name = this.getText(); let variableModelList: IVariableModel[] = []; - if (this.sourceBlock_ && !this.sourceBlock_.isDeadOrDying()) { + const sourceBlock = this.getSourceBlock(); + if (sourceBlock && !sourceBlock.isDeadOrDying()) { + const workspace = sourceBlock.workspace; const variableTypes = this.getVariableTypes(); // Get a copy of the list, so that adding rename and new variable options // doesn't modify the workspace's list. for (let i = 0; i < variableTypes.length; i++) { const variableType = variableTypes[i]; - const variables = - this.sourceBlock_.workspace.getVariablesOfType(variableType); + const variables = workspace.getVariablesOfType(variableType); variableModelList = variableModelList.concat(variables); + if (workspace.isFlyout) { + variableModelList = variableModelList.concat( + workspace + .getPotentialVariableMap() + ?.getVariablesOfType(variableType) ?? [], + ); + } } } variableModelList.sort(Variables.compareByName); From c79610cea6f7f1cdfad06772e0b1be8f0c17d6b6 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 18 Sep 2024 11:58:39 -0700 Subject: [PATCH 058/102] refactor: remove redundant flyout positioning. (#8573) * refactor: remove redundant flyout positioning. * fix: handle the case where there is a flyout without a toolbox --- core/workspace_svg.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 910171007..7c57f47cd 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -1049,8 +1049,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { resize() { if (this.toolbox_) { this.toolbox_.position(); - } - if (this.flyout) { + } else if (this.flyout) { this.flyout.position(); } From 6ec1bc5ba50960d2ceefcc0370b43e3f86f99fcc Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 25 Sep 2024 10:23:25 -0700 Subject: [PATCH 059/102] feat: Add the IFlyoutInflater interface. (#8581) * feat: Add the IFlyoutInflater interface. * fix: Add a return type for IFlyoutInflater.disposeElement(). * refactor: Add the gapForElement method. --- core/interfaces/i_flyout_inflater.ts | 41 ++++++++++++++++++++++++++++ core/registry.ts | 3 ++ 2 files changed, 44 insertions(+) create mode 100644 core/interfaces/i_flyout_inflater.ts diff --git a/core/interfaces/i_flyout_inflater.ts b/core/interfaces/i_flyout_inflater.ts new file mode 100644 index 000000000..f4a3b6ee9 --- /dev/null +++ b/core/interfaces/i_flyout_inflater.ts @@ -0,0 +1,41 @@ +import type {IBoundedElement} from './i_bounded_element.js'; +import type {WorkspaceSvg} from '../workspace_svg.js'; + +export interface IFlyoutInflater { + /** + * Loads the object represented by the given state onto the workspace. + * + * Note that this method's interface is identical to that in ISerializer, to + * allow for code reuse. + * + * @param state A JSON representation of an element to inflate on the flyout. + * @param flyoutWorkspace The flyout's workspace, where the inflated element + * should be created. If the inflated element is an `IRenderedElement` it + * itself or the inflater should append it to the workspace; the flyout + * will not do so itself. The flyout is responsible for positioning the + * element, however. + * @returns The newly inflated flyout element. + */ + load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement; + + /** + * Returns the amount of spacing that should follow the element corresponding + * to the given JSON representation. + * + * @param state A JSON representation of the element preceding the gap. + * @param defaultGap The default gap for elements in this flyout. + * @returns The gap that should follow the given element. + */ + gapForElement(state: Object, defaultGap: number): number; + + /** + * Disposes of the given element. + * + * If the element in question resides on the flyout workspace, it should remove + * itself. Implementers are not otherwise required to fully dispose of the + * element; it may be e.g. cached for performance purposes. + * + * @param element The flyout element to dispose of. + */ + disposeElement(element: IBoundedElement): void; +} diff --git a/core/registry.ts b/core/registry.ts index c7e16e935..7d70fe2eb 100644 --- a/core/registry.ts +++ b/core/registry.ts @@ -10,6 +10,7 @@ import type {Abstract} from './events/events_abstract.js'; import type {Field} from './field.js'; import type {IConnectionChecker} from './interfaces/i_connection_checker.js'; import type {IFlyout} from './interfaces/i_flyout.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import type {IMetricsManager} from './interfaces/i_metrics_manager.js'; import type {IIcon} from './interfaces/i_icon.js'; import type {Input} from './inputs/input.js'; @@ -99,6 +100,8 @@ export class Type<_T> { 'flyoutsHorizontalToolbox', ); + static FLYOUT_INFLATER = new Type('flyoutInflater'); + static METRICS_MANAGER = new Type('metricsManager'); /** From 489aded31dcb352ae97acfeb3bb705e2da592e7a Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 27 Sep 2024 13:22:36 -0700 Subject: [PATCH 060/102] feat: Add inflaters for flyout labels and buttons. (#8593) * feat: Add inflaters for flyout labels and buttons. * chore: Temporarily re-add createDom(). * chore: fix JSDoc. * chore: Add license. * chore: Add TSDoc. --- core/button_flyout_inflater.ts | 63 +++++++++++++++++++++++++ core/flyout_button.ts | 85 ++++++++++++++++++++++++++-------- core/label_flyout_inflater.ts | 59 +++++++++++++++++++++++ 3 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 core/button_flyout_inflater.ts create mode 100644 core/label_flyout_inflater.ts diff --git a/core/button_flyout_inflater.ts b/core/button_flyout_inflater.ts new file mode 100644 index 000000000..703dc6069 --- /dev/null +++ b/core/button_flyout_inflater.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; +import {FlyoutButton} from './flyout_button.js'; +import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import * as registry from './registry.js'; + +/** + * Class responsible for creating buttons for flyouts. + */ +export class ButtonFlyoutInflater implements IFlyoutInflater { + /** + * Inflates a flyout button from the given state and adds it to the flyout. + * + * @param state A JSON representation of a flyout button. + * @param flyoutWorkspace The workspace to create the button on. + * @returns A newly created FlyoutButton. + */ + load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + const button = new FlyoutButton( + flyoutWorkspace, + flyoutWorkspace.targetWorkspace!, + state as ButtonOrLabelInfo, + false, + ); + button.show(); + return button; + } + + /** + * Returns the amount of space that should follow this button. + * + * @param state A JSON representation of a flyout button. + * @param defaultGap The default spacing for flyout items. + * @returns The amount of space that should follow this button. + */ + gapForElement(state: Object, defaultGap: number): number { + return defaultGap; + } + + /** + * Disposes of the given button. + * + * @param element The flyout button to dispose of. + */ + disposeElement(element: IBoundedElement): void { + if (element instanceof FlyoutButton) { + element.dispose(); + } + } +} + +registry.register( + registry.Type.FLYOUT_INFLATER, + 'button', + ButtonFlyoutInflater, +); diff --git a/core/flyout_button.ts b/core/flyout_button.ts index dfc7b9507..41c3636fe 100644 --- a/core/flyout_button.ts +++ b/core/flyout_button.ts @@ -20,12 +20,17 @@ import * as style from './utils/style.js'; import {Svg} from './utils/svg.js'; import type * as toolbox from './utils/toolbox.js'; import type {WorkspaceSvg} from './workspace_svg.js'; -import type {IASTNodeLocationSvg} from './blockly.js'; +import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {IRenderedElement} from './interfaces/i_rendered_element.js'; +import {Rect} from './utils/rect.js'; /** * Class for a button or label in the flyout. */ -export class FlyoutButton implements IASTNodeLocationSvg { +export class FlyoutButton + implements IASTNodeLocationSvg, IBoundedElement, IRenderedElement +{ /** The horizontal margin around the text in the button. */ static TEXT_MARGIN_X = 5; @@ -41,7 +46,8 @@ export class FlyoutButton implements IASTNodeLocationSvg { private readonly cssClass: string | null; /** Mouse up event data. */ - private onMouseUpWrapper: browserEvents.Data | null = null; + private onMouseDownWrapper: browserEvents.Data; + private onMouseUpWrapper: browserEvents.Data; info: toolbox.ButtonOrLabelInfo; /** The width of the button's rect. */ @@ -51,7 +57,7 @@ export class FlyoutButton implements IASTNodeLocationSvg { height = 0; /** The root SVG group for the button or label. */ - private svgGroup: SVGGElement | null = null; + private svgGroup: SVGGElement; /** The SVG element with the text of the label or button. */ private svgText: SVGTextElement | null = null; @@ -92,14 +98,6 @@ export class FlyoutButton implements IASTNodeLocationSvg { /** The JSON specifying the label / button. */ this.info = json; - } - - /** - * Create the button elements. - * - * @returns The button's SVG group. - */ - createDom(): SVGElement { let cssClass = this.isFlyoutLabel ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton'; @@ -198,15 +196,24 @@ export class FlyoutButton implements IASTNodeLocationSvg { this.updateTransform(); - // AnyDuringMigration because: Argument of type 'SVGGElement | null' is not - // assignable to parameter of type 'EventTarget'. + this.onMouseDownWrapper = browserEvents.conditionalBind( + this.svgGroup, + 'pointerdown', + this, + this.onMouseDown, + ); this.onMouseUpWrapper = browserEvents.conditionalBind( - this.svgGroup as AnyDuringMigration, + this.svgGroup, 'pointerup', this, this.onMouseUp, ); - return this.svgGroup!; + } + + createDom(): SVGElement { + // No-op, now handled in constructor. Will be removed in followup refactor + // PR that updates the flyout classes to use inflaters. + return this.svgGroup; } /** Correctly position the flyout button and make it visible. */ @@ -235,6 +242,17 @@ export class FlyoutButton implements IASTNodeLocationSvg { this.updateTransform(); } + /** + * Move the element by a relative offset. + * + * @param dx Horizontal offset in workspace units. + * @param dy Vertical offset in workspace units. + * @param _reason Why is this move happening? 'user', 'bump', 'snap'... + */ + moveBy(dx: number, dy: number, _reason?: string[]) { + this.moveTo(this.position.x + dx, this.position.y + dy); + } + /** @returns Whether or not the button is a label. */ isLabel(): boolean { return this.isFlyoutLabel; @@ -250,6 +268,21 @@ export class FlyoutButton implements IASTNodeLocationSvg { return this.position; } + /** + * Returns the coordinates of a bounded element describing the dimensions of + * the element. Coordinate system: workspace coordinates. + * + * @returns Object with coordinates of the bounded element. + */ + getBoundingRectangle() { + return new Rect( + this.position.y, + this.position.y + this.height, + this.position.x, + this.position.x + this.width, + ); + } + /** @returns Text of the button. */ getButtonText(): string { return this.text; @@ -275,9 +308,8 @@ export class FlyoutButton implements IASTNodeLocationSvg { /** Dispose of this button. */ dispose() { - if (this.onMouseUpWrapper) { - browserEvents.unbind(this.onMouseUpWrapper); - } + browserEvents.unbind(this.onMouseDownWrapper); + browserEvents.unbind(this.onMouseUpWrapper); if (this.svgGroup) { dom.removeNode(this.svgGroup); } @@ -342,6 +374,21 @@ export class FlyoutButton implements IASTNodeLocationSvg { } } } + + private onMouseDown(e: PointerEvent) { + const gesture = this.targetWorkspace.getGesture(e); + const flyout = this.targetWorkspace.getFlyout(); + if (gesture && flyout) { + gesture.handleFlyoutStart(e, flyout); + } + } + + /** + * @returns The root SVG element of this rendered element. + */ + getSvgRoot() { + return this.svgGroup; + } } /** CSS for buttons and labels. See css.js for use. */ diff --git a/core/label_flyout_inflater.ts b/core/label_flyout_inflater.ts new file mode 100644 index 000000000..67b02857a --- /dev/null +++ b/core/label_flyout_inflater.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; +import {FlyoutButton} from './flyout_button.js'; +import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import * as registry from './registry.js'; + +/** + * Class responsible for creating labels for flyouts. + */ +export class LabelFlyoutInflater implements IFlyoutInflater { + /** + * Inflates a flyout label from the given state and adds it to the flyout. + * + * @param state A JSON representation of a flyout label. + * @param flyoutWorkspace The workspace to create the label on. + * @returns A FlyoutButton configured as a label. + */ + load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + const label = new FlyoutButton( + flyoutWorkspace, + flyoutWorkspace.targetWorkspace!, + state as ButtonOrLabelInfo, + true, + ); + label.show(); + return label; + } + + /** + * Returns the amount of space that should follow this label. + * + * @param state A JSON representation of a flyout label. + * @param defaultGap The default spacing for flyout items. + * @returns The amount of space that should follow this label. + */ + gapForElement(state: Object, defaultGap: number): number { + return defaultGap; + } + + /** + * Disposes of the given label. + * + * @param element The flyout label to dispose of. + */ + disposeElement(element: IBoundedElement): void { + if (element instanceof FlyoutButton) { + element.dispose(); + } + } +} + +registry.register(registry.Type.FLYOUT_INFLATER, 'label', LabelFlyoutInflater); From bdc43bd0f74d42cc653d9566cd359af613bb6a63 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 27 Sep 2024 13:23:56 -0700 Subject: [PATCH 061/102] feat: Add support for inflating flyout separators. (#8592) * feat: Add support for inflating flyout separators. * chore: Add license. * chore: Add TSDoc. * refactor: Allow specifying an axis for flyout separators. --- core/flyout_separator.ts | 61 +++++++++++++++++++++++++++ core/separator_flyout_inflater.ts | 69 +++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 core/flyout_separator.ts create mode 100644 core/separator_flyout_inflater.ts diff --git a/core/flyout_separator.ts b/core/flyout_separator.ts new file mode 100644 index 000000000..733371007 --- /dev/null +++ b/core/flyout_separator.ts @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import {Rect} from './utils/rect.js'; + +/** + * Representation of a gap between elements in a flyout. + */ +export class FlyoutSeparator implements IBoundedElement { + private x = 0; + private y = 0; + + /** + * Creates a new separator. + * + * @param gap The amount of space this separator should occupy. + * @param axis The axis along which this separator occupies space. + */ + constructor( + private gap: number, + private axis: SeparatorAxis, + ) {} + + /** + * Returns the bounding box of this separator. + * + * @returns The bounding box of this separator. + */ + getBoundingRectangle(): Rect { + switch (this.axis) { + case SeparatorAxis.X: + return new Rect(this.y, this.y, this.x, this.x + this.gap); + case SeparatorAxis.Y: + return new Rect(this.y, this.y + this.gap, this.x, this.x); + } + } + + /** + * Repositions this separator. + * + * @param dx The distance to move this separator on the X axis. + * @param dy The distance to move this separator on the Y axis. + * @param _reason The reason this move was initiated. + */ + moveBy(dx: number, dy: number, _reason?: string[]) { + this.x += dx; + this.y += dy; + } +} + +/** + * Representation of an axis along which a separator occupies space. + */ +export const enum SeparatorAxis { + X = 'x', + Y = 'y', +} diff --git a/core/separator_flyout_inflater.ts b/core/separator_flyout_inflater.ts new file mode 100644 index 000000000..5ed02aeb9 --- /dev/null +++ b/core/separator_flyout_inflater.ts @@ -0,0 +1,69 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; +import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; +import type {SeparatorInfo} from './utils/toolbox.js'; +import * as registry from './registry.js'; + +/** + * Class responsible for creating separators for flyouts. + */ +export class SeparatorFlyoutInflater implements IFlyoutInflater { + /** + * Inflates a dummy flyout separator. + * + * The flyout automatically creates separators between every element with a + * size determined by calling gapForElement on the relevant inflater. + * Additionally, users can explicitly add separators in the flyout definition. + * When separators (implicitly or explicitly created) follow one another, the + * gap of the last one propagates backwards and flattens to one separator. + * This flattening is not additive; if there are initially separators of 2, 3, + * and 4 pixels, after normalization there will be one separator of 4 pixels. + * Therefore, this method returns a zero-width separator, which will be + * replaced by the one implicitly created by the flyout based on the value + * returned by gapForElement, which knows the default gap, unlike this method. + * + * @param _state A JSON representation of a flyout separator. + * @param flyoutWorkspace The workspace the separator belongs to. + * @returns A newly created FlyoutSeparator. + */ + load(_state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + const flyoutAxis = flyoutWorkspace.targetWorkspace?.getFlyout() + ?.horizontalLayout + ? SeparatorAxis.X + : SeparatorAxis.Y; + return new FlyoutSeparator(0, flyoutAxis); + } + + /** + * Returns the size of the separator. See `load` for more details. + * + * @param state A JSON representation of a flyout separator. + * @param defaultGap The default spacing for flyout items. + * @returns The desired size of the separator. + */ + gapForElement(state: Object, defaultGap: number): number { + const separatorState = state as SeparatorInfo; + const newGap = parseInt(String(separatorState['gap'])); + return newGap ?? defaultGap; + } + + /** + * Disposes of the given separator. Intentional no-op. + * + * @param _element The flyout separator to dispose of. + */ + disposeElement(_element: IBoundedElement): void {} +} + +registry.register( + registry.Type.FLYOUT_INFLATER, + 'sep', + SeparatorFlyoutInflater, +); From ec5b6e7f714e4a9fa67ecb57056079bba29e04d0 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 27 Sep 2024 14:12:59 -0700 Subject: [PATCH 062/102] feat: Add a BlockFlyoutInflater class. (#8591) * feat: Add a BlockFlyoutInflater class. * fix: Fix the capacity filter callback argument name. * fix: Fix addBlockListeners comment. * chore: Add license. * chore: Add TSDoc. * refactor: Make capacity filtering a normal method. * fix: Bind flyout filter to `this`. --- core/block_flyout_inflater.ts | 262 ++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 core/block_flyout_inflater.ts diff --git a/core/block_flyout_inflater.ts b/core/block_flyout_inflater.ts new file mode 100644 index 000000000..b22d2a821 --- /dev/null +++ b/core/block_flyout_inflater.ts @@ -0,0 +1,262 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFlyout} from './interfaces/i_flyout.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import {BlockSvg} from './block_svg.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; +import * as utilsXml from './utils/xml.js'; +import * as eventUtils from './events/utils.js'; +import * as Xml from './xml.js'; +import * as blocks from './serialization/blocks.js'; +import * as common from './common.js'; +import * as registry from './registry.js'; +import {MANUALLY_DISABLED} from './constants.js'; +import type {Abstract as AbstractEvent} from './events/events_abstract.js'; +import type {BlockInfo} from './utils/toolbox.js'; +import * as browserEvents from './browser_events.js'; + +/** + * The language-neutral ID for when the reason why a block is disabled is + * because the workspace is at block capacity. + */ +const WORKSPACE_AT_BLOCK_CAPACITY_DISABLED_REASON = + 'WORKSPACE_AT_BLOCK_CAPACITY'; + +/** + * Class responsible for creating blocks for flyouts. + */ +export class BlockFlyoutInflater implements IFlyoutInflater { + protected permanentlyDisabledBlocks = new Set(); + protected listeners = new Map(); + protected flyoutWorkspace?: WorkspaceSvg; + protected flyout?: IFlyout; + private capacityWrapper: (event: AbstractEvent) => void; + + /** + * Creates a new BlockFlyoutInflater instance. + */ + constructor() { + this.capacityWrapper = this.filterFlyoutBasedOnCapacity.bind(this); + } + + /** + * Inflates a flyout block from the given state and adds it to the flyout. + * + * @param state A JSON representation of a flyout block. + * @param flyoutWorkspace The workspace to create the block on. + * @returns A newly created block. + */ + load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + this.setFlyoutWorkspace(flyoutWorkspace); + this.flyout = flyoutWorkspace.targetWorkspace?.getFlyout() ?? undefined; + const block = this.createBlock(state as BlockInfo, flyoutWorkspace); + + if (!block.isEnabled()) { + // Record blocks that were initially disabled. + // Do not enable these blocks as a result of capacity filtering. + this.permanentlyDisabledBlocks.add(block); + } else { + this.updateStateBasedOnCapacity(block); + } + + // Mark blocks as being inside a flyout. This is used to detect and + // prevent the closure of the flyout if the user right-clicks on such + // a block. + block.getDescendants(false).forEach((b) => (b.isInFlyout = true)); + this.addBlockListeners(block); + + return block; + } + + /** + * Creates a block on the given workspace. + * + * @param blockDefinition A JSON representation of the block to create. + * @param workspace The workspace to create the block on. + * @returns The newly created block. + */ + createBlock(blockDefinition: BlockInfo, workspace: WorkspaceSvg): BlockSvg { + let block; + if (blockDefinition['blockxml']) { + const xml = ( + typeof blockDefinition['blockxml'] === 'string' + ? utilsXml.textToDom(blockDefinition['blockxml']) + : blockDefinition['blockxml'] + ) as Element; + block = Xml.domToBlockInternal(xml, workspace); + } else { + if (blockDefinition['enabled'] === undefined) { + blockDefinition['enabled'] = + blockDefinition['disabled'] !== 'true' && + blockDefinition['disabled'] !== true; + } + if ( + blockDefinition['disabledReasons'] === undefined && + blockDefinition['enabled'] === false + ) { + blockDefinition['disabledReasons'] = [MANUALLY_DISABLED]; + } + block = blocks.appendInternal(blockDefinition as blocks.State, workspace); + } + + return block as BlockSvg; + } + + /** + * Returns the amount of space that should follow this block. + * + * @param state A JSON representation of a flyout block. + * @param defaultGap The default spacing for flyout items. + * @returns The amount of space that should follow this block. + */ + gapForElement(state: Object, defaultGap: number): number { + const blockState = state as BlockInfo; + let gap; + if (blockState['gap']) { + gap = parseInt(String(blockState['gap'])); + } else if (blockState['blockxml']) { + const xml = ( + typeof blockState['blockxml'] === 'string' + ? utilsXml.textToDom(blockState['blockxml']) + : blockState['blockxml'] + ) as Element; + gap = parseInt(xml.getAttribute('gap')!); + } + + return !gap || isNaN(gap) ? defaultGap : gap; + } + + /** + * Disposes of the given block. + * + * @param element The flyout block to dispose of. + */ + disposeElement(element: IBoundedElement): void { + if (!(element instanceof BlockSvg)) return; + this.removeListeners(element.id); + element.dispose(false, false); + } + + /** + * Removes event listeners for the block with the given ID. + * + * @param blockId The ID of the block to remove event listeners from. + */ + protected removeListeners(blockId: string) { + const blockListeners = this.listeners.get(blockId) ?? []; + blockListeners.forEach((l) => browserEvents.unbind(l)); + this.listeners.delete(blockId); + } + + /** + * Updates this inflater's flyout workspace. + * + * @param workspace The workspace of the flyout that owns this inflater. + */ + protected setFlyoutWorkspace(workspace: WorkspaceSvg) { + if (this.flyoutWorkspace === workspace) return; + + if (this.flyoutWorkspace) { + this.flyoutWorkspace.targetWorkspace?.removeChangeListener( + this.capacityWrapper, + ); + } + this.flyoutWorkspace = workspace; + this.flyoutWorkspace.targetWorkspace?.addChangeListener( + this.capacityWrapper, + ); + } + + /** + * Updates the enabled state of the given block based on the capacity of the + * workspace. + * + * @param block The block to update the enabled/disabled state of. + */ + private updateStateBasedOnCapacity(block: BlockSvg) { + const enable = this.flyoutWorkspace?.targetWorkspace?.isCapacityAvailable( + common.getBlockTypeCounts(block), + ); + let currentBlock: BlockSvg | null = block; + while (currentBlock) { + currentBlock.setDisabledReason( + !enable, + WORKSPACE_AT_BLOCK_CAPACITY_DISABLED_REASON, + ); + currentBlock = currentBlock.getNextBlock(); + } + } + + /** + * Add listeners to a block that has been added to the flyout. + * + * @param block The block to add listeners for. + */ + protected addBlockListeners(block: BlockSvg) { + const blockListeners = []; + + blockListeners.push( + browserEvents.conditionalBind( + block.getSvgRoot(), + 'pointerdown', + block, + (e: PointerEvent) => { + const gesture = this.flyoutWorkspace?.targetWorkspace?.getGesture(e); + const flyout = this.flyoutWorkspace?.targetWorkspace?.getFlyout(); + if (gesture && flyout) { + gesture.setStartBlock(block); + gesture.handleFlyoutStart(e, flyout); + } + }, + ), + ); + + blockListeners.push( + browserEvents.bind(block.getSvgRoot(), 'pointerenter', null, () => { + if (!this.flyoutWorkspace?.targetWorkspace?.isDragging()) { + block.addSelect(); + } + }), + ); + blockListeners.push( + browserEvents.bind(block.getSvgRoot(), 'pointerleave', null, () => { + if (!this.flyoutWorkspace?.targetWorkspace?.isDragging()) { + block.removeSelect(); + } + }), + ); + + this.listeners.set(block.id, blockListeners); + } + + /** + * Updates the state of blocks in our owning flyout to be disabled/enabled + * based on the capacity of the workspace for more blocks of that type. + * + * @param event The event that triggered this update. + */ + private filterFlyoutBasedOnCapacity(event: AbstractEvent) { + if ( + !this.flyoutWorkspace || + (event && + !( + event.type === eventUtils.BLOCK_CREATE || + event.type === eventUtils.BLOCK_DELETE + )) + ) + return; + + this.flyoutWorkspace.getTopBlocks(false).forEach((block) => { + if (!this.permanentlyDisabledBlocks.has(block)) { + this.updateStateBasedOnCapacity(block); + } + }); + } +} + +registry.register(registry.Type.FLYOUT_INFLATER, 'block', BlockFlyoutInflater); From a4b522781cda9e6745c193da17da59f7732b4c73 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 2 Oct 2024 08:18:21 -0700 Subject: [PATCH 063/102] fix: Fix bug that prevented dismissing the widgetdiv in a mutator workspace. (#8600) * fix: Fix bug that prevented dismissing the widgetdiv in a mutator workspace. * fix: Check if the correct workspace is null. * fix: Remove errant this. --- core/widgetdiv.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/widgetdiv.ts b/core/widgetdiv.ts index 9f58bb1c5..b5edc9774 100644 --- a/core/widgetdiv.ts +++ b/core/widgetdiv.ts @@ -166,10 +166,22 @@ export function hideIfOwner(oldOwner: unknown) { * Destroy the widget and hide the div if it is being used by an object in the * specified workspace, or if it is used by an unknown workspace. * - * @param oldOwnerWorkspace The workspace that was using this container. + * @param workspace The workspace that was using this container. */ -export function hideIfOwnerIsInWorkspace(oldOwnerWorkspace: WorkspaceSvg) { - if (ownerWorkspace === null || ownerWorkspace === oldOwnerWorkspace) { +export function hideIfOwnerIsInWorkspace(workspace: WorkspaceSvg) { + let ownerIsInWorkspace = ownerWorkspace === null; + // Check if the given workspace is a parent workspace of the one containing + // our owner. + let currentWorkspace: WorkspaceSvg | null = workspace; + while (!ownerIsInWorkspace && currentWorkspace) { + if (currentWorkspace === workspace) { + ownerIsInWorkspace = true; + break; + } + currentWorkspace = workspace.options.parentWorkspace; + } + + if (ownerIsInWorkspace) { hide(); } } From e5c1a89cdfe0f5d76bc38c79fc7e1a202e9de3c8 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 2 Oct 2024 08:18:47 -0700 Subject: [PATCH 064/102] fix: Fix bug that caused fields in the flyout to use the main workspace's scale. (#8607) * fix: Fix bug that caused fields in the flyout to use the main workspace's scale. * chore: remove errant param in docs. --- core/field_input.ts | 2 +- core/workspace_svg.ts | 62 ++++++++++++++++++++++++++--- tests/mocha/field_textinput_test.js | 2 +- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/core/field_input.ts b/core/field_input.ts index 3326cd35f..dcc2ac29e 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -415,7 +415,7 @@ export abstract class FieldInput extends Field< 'spellcheck', this.spellcheck_ as AnyDuringMigration, ); - const scale = this.workspace_!.getScale(); + const scale = this.workspace_!.getAbsoluteScale(); const fontSize = this.getConstants()!.FIELD_TEXT_FONTSIZE * scale + 'pt'; div!.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 7c57f47cd..5447bdf51 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -29,6 +29,7 @@ import * as ContextMenu from './contextmenu.js'; import {ContextMenuRegistry} from './contextmenu_registry.js'; import * as dropDownDiv from './dropdowndiv.js'; import * as eventUtils from './events/utils.js'; +import {Flyout} from './flyout_base.js'; import type {FlyoutButton} from './flyout_button.js'; import {Gesture} from './gesture.js'; import {Grid} from './grid.js'; @@ -2022,18 +2023,69 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { } /** - * Get the workspace's zoom factor. If the workspace has a parent, we call - * into the parent to get the workspace scale. + * Get the workspace's zoom factor. * * @returns The workspace zoom factor. Units: (pixels / workspaceUnit). */ getScale(): number { - if (this.options.parentWorkspace) { - return this.options.parentWorkspace.getScale(); - } return this.scale; } + /** + * Returns the absolute scale of the workspace. + * + * Workspace scaling is multiplicative; if a workspace B (e.g. a mutator editor) + * with scale Y is nested within a root workspace A with scale X, workspace B's + * effective scale is X * Y, because, as a child of A, it is already transformed + * by A's scaling factor, and then further transforms itself by its own scaling + * factor. Normally this Just Works, but for global elements (e.g. field + * editors) that are visually associated with a particular workspace but live at + * the top level of the DOM rather than being a child of their associated + * workspace, the absolute/effective scale may be needed to render + * appropriately. + * + * @returns The absolute/effective scale of the given workspace. + */ + getAbsoluteScale() { + // Returns a workspace's own scale, without regard to multiplicative scaling. + const getLocalScale = (workspace: WorkspaceSvg): number => { + // Workspaces in flyouts may have a distinct scale; use this if relevant. + if (workspace.isFlyout) { + const flyout = workspace.targetWorkspace?.getFlyout(); + if (flyout instanceof Flyout) { + return flyout.getFlyoutScale(); + } + } + + return workspace.getScale(); + }; + + const computeScale = (workspace: WorkspaceSvg, scale: number): number => { + // If the workspace has no parent, or it does have a parent but is not + // actually a child of its parent workspace in the DOM (this is the case for + // flyouts in the main workspace), we're done; just return the scale so far + // multiplied by the workspace's own scale. + if ( + !workspace.options.parentWorkspace || + !workspace.options.parentWorkspace + .getSvgGroup() + .contains(workspace.getSvgGroup()) + ) { + return scale * getLocalScale(workspace); + } + + // If there is a parent workspace, and this workspace is a child of it in + // the DOM, scales are multiplicative, so recurse up the workspace + // hierarchy. + return computeScale( + workspace.options.parentWorkspace, + scale * getLocalScale(workspace), + ); + }; + + return computeScale(this, 1); + } + /** * Scroll the workspace to a specified offset (in pixels), keeping in the * workspace bounds. See comment on workspaceSvg.scrollX for more detail on diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index 7b0da1b4c..3561d360a 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -192,7 +192,7 @@ suite('Text Input Fields', function () { setup(function () { this.prepField = function (field) { const workspace = { - getScale: function () { + getAbsoluteScale: function () { return 1; }, getRenderer: function () { From e777086f1693e38fcb3eb3c2ee1b7e38d4c4917f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 2 Oct 2024 09:20:45 -0700 Subject: [PATCH 065/102] refactor!: Update flyouts to use inflaters. (#8601) * refactor: Update flyouts to use inflaters. * fix: Specify an axis when creating flyout separators. * chore: Remove unused import. * chore: Fix tests. * chore: Update documentation. * chore: Improve code readability. * refactor: Use null instead of undefined. --- core/blockly.ts | 12 + core/flyout_base.ts | 637 ++++++---------------------------- core/flyout_horizontal.ts | 69 +--- core/flyout_vertical.ts | 91 +---- core/keyboard_nav/ast_node.ts | 16 +- tests/mocha/flyout_test.js | 55 +-- 6 files changed, 176 insertions(+), 704 deletions(-) diff --git a/core/blockly.ts b/core/blockly.ts index 28eb0010a..fda49830f 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -96,6 +96,12 @@ import { } from './field_variable.js'; import {Flyout} from './flyout_base.js'; import {FlyoutButton} from './flyout_button.js'; +import {FlyoutSeparator} from './flyout_separator.js'; +import {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import {BlockFlyoutInflater} from './block_flyout_inflater.js'; +import {ButtonFlyoutInflater} from './button_flyout_inflater.js'; +import {LabelFlyoutInflater} from './label_flyout_inflater.js'; +import {SeparatorFlyoutInflater} from './separator_flyout_inflater.js'; import {HorizontalFlyout} from './flyout_horizontal.js'; import {FlyoutMetricsManager} from './flyout_metrics_manager.js'; import {VerticalFlyout} from './flyout_vertical.js'; @@ -510,6 +516,12 @@ export { export {Flyout}; export {FlyoutButton}; export {FlyoutMetricsManager}; +export {FlyoutSeparator}; +export {IFlyoutInflater}; +export {BlockFlyoutInflater}; +export {ButtonFlyoutInflater}; +export {LabelFlyoutInflater}; +export {SeparatorFlyoutInflater}; export {CodeGenerator}; export {CodeGenerator as Generator}; // Deprecated name, October 2022. export {Gesture}; diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 2ea85a0df..0c62f3b4c 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -12,21 +12,18 @@ // Former goog.module ID: Blockly.Flyout import type {Abstract as AbstractEvent} from './events/events_abstract.js'; -import type {Block} from './block.js'; import {BlockSvg} from './block_svg.js'; import * as browserEvents from './browser_events.js'; -import * as common from './common.js'; import {ComponentManager} from './component_manager.js'; import {DeleteArea} from './delete_area.js'; import * as eventUtils from './events/utils.js'; -import {FlyoutButton} from './flyout_button.js'; import {FlyoutMetricsManager} from './flyout_metrics_manager.js'; import type {IFlyout} from './interfaces/i_flyout.js'; -import {MANUALLY_DISABLED} from './constants.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; import type {Options} from './options.js'; import {ScrollbarPair} from './scrollbar_pair.js'; import * as blocks from './serialization/blocks.js'; -import * as Tooltip from './tooltip.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import * as idGenerator from './utils/idgenerator.js'; @@ -34,22 +31,10 @@ 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'; +import * as registry from './registry.js'; import * as renderManagement from './render_management.js'; import {IAutoHideable} from './interfaces/i_autohideable.js'; - -enum FlyoutItemType { - BLOCK = 'block', - BUTTON = 'button', -} - -/** - * The language-neutral ID for when the reason why a block is disabled is - * because the workspace is at block capacity. - */ -const WORKSPACE_AT_BLOCK_CAPACITY_DISABLED_REASON = - 'WORKSPACE_AT_BLOCK_CAPACITY'; +import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; /** * Class for a flyout. @@ -84,12 +69,11 @@ export abstract class Flyout protected abstract setMetrics_(xyRatio: {x?: number; y?: number}): void; /** - * Lay out the blocks in the flyout. + * Lay out the elements in the flyout. * - * @param contents The blocks and buttons to lay out. - * @param gaps The visible gaps between blocks. + * @param contents The flyout elements to lay out. */ - protected abstract layout_(contents: FlyoutItem[], gaps: number[]): void; + protected abstract layout_(contents: FlyoutItem[]): void; /** * Scroll the flyout. @@ -99,8 +83,8 @@ export abstract class Flyout protected abstract wheel_(e: WheelEvent): void; /** - * Compute height of flyout. Position mat under each block. - * For RTL: Lay out the blocks right-aligned. + * Compute bounds of flyout. + * For RTL: Lay out the elements right-aligned. */ protected abstract reflowInternal_(): void; @@ -123,11 +107,6 @@ export abstract class Flyout */ abstract scrollToStart(): void; - /** - * The type of a flyout content item. - */ - static FlyoutItemType = FlyoutItemType; - protected workspace_: WorkspaceSvg; RTL: boolean; /** @@ -147,43 +126,15 @@ export abstract class Flyout /** * Function that will be registered as a change listener on the workspace - * to reflow when blocks in the flyout workspace change. + * to reflow when elements in the flyout workspace change. */ private reflowWrapper: ((e: AbstractEvent) => void) | null = null; /** - * Function that disables blocks in the flyout based on max block counts - * allowed in the target workspace. Registered as a change listener on the - * target workspace. - */ - private filterWrapper: ((e: AbstractEvent) => void) | null = null; - - /** - * List of background mats that lurk behind each block to catch clicks - * landing in the blocks' lakes and bays. - */ - private mats: SVGElement[] = []; - - /** - * List of visible buttons. - */ - protected buttons_: FlyoutButton[] = []; - - /** - * List of visible buttons and blocks. + * List of flyout elements. */ protected contents: FlyoutItem[] = []; - /** - * List of event listeners. - */ - private listeners: browserEvents.Data[] = []; - - /** - * List of blocks that should always be disabled. - */ - private permanentlyDisabled: Block[] = []; - protected readonly tabWidth_: number; /** @@ -193,11 +144,6 @@ export abstract class Flyout */ targetWorkspace!: WorkspaceSvg; - /** - * A list of blocks that can be reused. - */ - private recycledBlocks: BlockSvg[] = []; - /** * Does the flyout automatically close when a block is created? */ @@ -212,7 +158,6 @@ export abstract class Flyout * Whether the workspace containing this flyout is visible. */ private containerVisible = true; - protected rectMap_: WeakMap; /** * Corner radius of the flyout background. @@ -270,6 +215,13 @@ export abstract class Flyout * The root SVG group for the button or label. */ protected svgGroup_: SVGGElement | null = null; + + /** + * Map from flyout content type to the corresponding inflater class + * responsible for creating concrete instances of the content type. + */ + protected inflaters = new Map(); + /** * @param workspaceOptions Dictionary of options for the * workspace. @@ -309,15 +261,7 @@ export abstract class Flyout this.tabWidth_ = this.workspace_.getRenderer().getConstants().TAB_WIDTH; /** - * A map from blocks to the rects which are beneath them to act as input - * targets. - * - * @internal - */ - this.rectMap_ = new WeakMap(); - - /** - * Margin around the edges of the blocks in the flyout. + * Margin around the edges of the elements in the flyout. */ this.MARGIN = this.CORNER_RADIUS; @@ -402,15 +346,6 @@ export abstract class Flyout this.wheel_, ), ); - this.filterWrapper = (event) => { - if ( - event.type === eventUtils.BLOCK_CREATE || - event.type === eventUtils.BLOCK_DELETE - ) { - this.filterForCapacity(); - } - }; - this.targetWorkspace.addChangeListener(this.filterWrapper); // Dragging the flyout up and down. this.boundEvents.push( @@ -454,9 +389,6 @@ export abstract class Flyout browserEvents.unbind(event); } this.boundEvents.length = 0; - if (this.filterWrapper) { - this.targetWorkspace.removeChangeListener(this.filterWrapper); - } if (this.workspace_) { this.workspace_.getThemeManager().unsubscribe(this.svgBackground_!); this.workspace_.dispose(); @@ -576,16 +508,16 @@ export abstract class Flyout } /** - * Get the list of buttons and blocks of the current flyout. + * Get the list of elements of the current flyout. * - * @returns The array of flyout buttons and blocks. + * @returns The array of flyout elements. */ getContents(): FlyoutItem[] { return this.contents; } /** - * Store the list of buttons and blocks on the flyout. + * Store the list of elements on the flyout. * * @param contents - The array of items for the flyout. */ @@ -660,16 +592,11 @@ export abstract class Flyout return; } this.setVisible(false); - // Delete all the event listeners. - for (const listen of this.listeners) { - browserEvents.unbind(listen); - } - this.listeners.length = 0; if (this.reflowWrapper) { this.workspace_.removeChangeListener(this.reflowWrapper); this.reflowWrapper = null; } - // Do NOT delete the blocks here. Wait until Flyout.show. + // Do NOT delete the flyout contents here. Wait until Flyout.show. // https://neil.fraser.name/news/2014/08/09/ } @@ -697,9 +624,9 @@ export abstract class Flyout renderManagement.triggerQueuedRenders(this.workspace_); - this.setContents(flyoutInfo.contents); + this.setContents(flyoutInfo); - this.layout_(flyoutInfo.contents, flyoutInfo.gaps); + this.layout_(flyoutInfo); if (this.horizontalLayout) { this.height_ = 0; @@ -709,8 +636,6 @@ export abstract class Flyout this.workspace_.setResizesEnabled(true); this.reflow(); - this.filterForCapacity(); - // Listen for block change events, and reflow the flyout in response. This // accommodates e.g. resizing a non-autoclosing flyout in response to the // user typing long strings into fields on the blocks in the flyout. @@ -723,7 +648,6 @@ export abstract class Flyout } }; this.workspace_.addChangeListener(this.reflowWrapper); - this.emptyRecycledBlocks(); } /** @@ -732,15 +656,12 @@ export abstract class Flyout * * @param parsedContent The array * of objects to show in the flyout. - * @returns The list of contents and gaps needed to lay out the flyout. + * @returns The list of contents needed to lay out the flyout. */ - private createFlyoutInfo(parsedContent: toolbox.FlyoutItemInfoArray): { - contents: FlyoutItem[]; - gaps: number[]; - } { + private createFlyoutInfo( + parsedContent: toolbox.FlyoutItemInfoArray, + ): FlyoutItem[] { const contents: FlyoutItem[] = []; - const gaps: number[] = []; - this.permanentlyDisabled.length = 0; const defaultGap = this.horizontalLayout ? this.GAP_X : this.GAP_Y; for (const info of parsedContent) { if ('custom' in info) { @@ -749,44 +670,58 @@ export abstract class Flyout const flyoutDef = this.getDynamicCategoryContents(categoryName); const parsedDynamicContent = toolbox.convertFlyoutDefToJsonArray(flyoutDef); - const {contents: dynamicContents, gaps: dynamicGaps} = - this.createFlyoutInfo(parsedDynamicContent); - contents.push(...dynamicContents); - gaps.push(...dynamicGaps); + contents.push(...this.createFlyoutInfo(parsedDynamicContent)); } - switch (info['kind'].toUpperCase()) { - case 'BLOCK': { - 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 = info as toolbox.SeparatorInfo; - this.addSeparatorGap(sepInfo, gaps, defaultGap); - break; - } - case 'LABEL': { - 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}); - gaps.push(defaultGap); - break; - } - case 'BUTTON': { - const buttonInfo = info as toolbox.ButtonInfo; - const button = this.createButton(buttonInfo, /** isLabel */ false); - contents.push({type: FlyoutItemType.BUTTON, button: button}); - gaps.push(defaultGap); - break; + const type = info['kind'].toLowerCase(); + const inflater = this.getInflaterForType(type); + if (inflater) { + const element = inflater.load(info, this.getWorkspace()); + contents.push({ + type, + element, + }); + const gap = inflater.gapForElement(info, defaultGap); + if (gap) { + contents.push({ + type: 'sep', + element: new FlyoutSeparator( + gap, + this.horizontalLayout ? SeparatorAxis.X : SeparatorAxis.Y, + ), + }); } } } - return {contents: contents, gaps: gaps}; + return this.normalizeSeparators(contents); + } + + /** + * Updates and returns the provided list of flyout contents to flatten + * separators as needed. + * + * When multiple separators occur one after another, the value of the last one + * takes precedence and the earlier separators in the group are removed. + * + * @param contents The list of flyout contents to flatten separators in. + * @returns An updated list of flyout contents with only one separator between + * each non-separator item. + */ + protected normalizeSeparators(contents: FlyoutItem[]): FlyoutItem[] { + for (let i = contents.length - 1; i > 0; i--) { + const elementType = contents[i].type.toLowerCase(); + const previousElementType = contents[i - 1].type.toLowerCase(); + if (elementType === 'sep' && previousElementType === 'sep') { + // Remove previousElement from the array, shifting the current element + // forward as a result. This preserves the behavior where explicit + // separator elements override the value of prior implicit (or explicit) + // separator elements. + contents.splice(i - 1, 1); + } + } + + return contents; } /** @@ -813,287 +748,18 @@ export abstract class Flyout } /** - * Creates a flyout button or a flyout label. - * - * @param btnInfo The object holding information about a button or a label. - * @param isLabel True if the button is a label, false otherwise. - * @returns The object used to display the button in the - * flyout. - */ - private createButton( - btnInfo: toolbox.ButtonOrLabelInfo, - isLabel: boolean, - ): FlyoutButton { - const curButton = new FlyoutButton( - this.workspace_, - this.targetWorkspace as WorkspaceSvg, - btnInfo, - isLabel, - ); - return curButton; - } - - /** - * Create a block from the xml and permanently disable any blocks that were - * defined as disabled. - * - * @param blockInfo The info of the block. - * @returns The block created from the blockInfo. - */ - private createFlyoutBlock(blockInfo: toolbox.BlockInfo): BlockSvg { - let block; - if (blockInfo['blockxml']) { - const xml = ( - typeof blockInfo['blockxml'] === 'string' - ? utilsXml.textToDom(blockInfo['blockxml']) - : blockInfo['blockxml'] - ) as Element; - block = this.getRecycledBlock(xml.getAttribute('type')!); - if (!block) { - block = Xml.domToBlockInternal(xml, this.workspace_); - } - } else { - block = this.getRecycledBlock(blockInfo['type']!); - if (!block) { - if (blockInfo['enabled'] === undefined) { - blockInfo['enabled'] = - blockInfo['disabled'] !== 'true' && blockInfo['disabled'] !== true; - } - if ( - blockInfo['disabledReasons'] === undefined && - blockInfo['enabled'] === false - ) { - blockInfo['disabledReasons'] = [MANUALLY_DISABLED]; - } - block = blocks.appendInternal( - blockInfo as blocks.State, - this.workspace_, - ); - } - } - - if (!block.isEnabled()) { - // Record blocks that were initially disabled. - // Do not enable these blocks as a result of capacity filtering. - this.permanentlyDisabled.push(block); - } - return block as BlockSvg; - } - - /** - * Returns a block from the array of recycled blocks with the given type, or - * undefined if one cannot be found. - * - * @param blockType The type of the block to try to recycle. - * @returns The recycled block, or undefined if - * one could not be recycled. - */ - private getRecycledBlock(blockType: string): BlockSvg | undefined { - let index = -1; - for (let i = 0; i < this.recycledBlocks.length; i++) { - if (this.recycledBlocks[i].type === blockType) { - index = i; - break; - } - } - return index === -1 ? undefined : this.recycledBlocks.splice(index, 1)[0]; - } - - /** - * Adds a gap in the flyout based on block info. - * - * @param blockInfo Information about a block. - * @param gaps The list of gaps between items in the flyout. - * @param defaultGap The default gap between one element and the - * next. - */ - private addBlockGap( - blockInfo: toolbox.BlockInfo, - gaps: number[], - defaultGap: number, - ) { - let gap; - if (blockInfo['gap']) { - gap = parseInt(String(blockInfo['gap'])); - } else if (blockInfo['blockxml']) { - const xml = ( - typeof blockInfo['blockxml'] === 'string' - ? utilsXml.textToDom(blockInfo['blockxml']) - : blockInfo['blockxml'] - ) as Element; - gap = parseInt(xml.getAttribute('gap')!); - } - gaps.push(!gap || isNaN(gap) ? defaultGap : gap); - } - - /** - * Add the necessary gap in the flyout for a separator. - * - * @param sepInfo The object holding - * information about a separator. - * @param gaps The list gaps between items in the flyout. - * @param defaultGap The default gap between the button and next - * element. - */ - private addSeparatorGap( - sepInfo: toolbox.SeparatorInfo, - gaps: number[], - defaultGap: number, - ) { - // Change the gap between two toolbox elements. - // - // The default gap is 24, can be set larger or smaller. - // This overwrites the gap attribute on the previous element. - const newGap = parseInt(String(sepInfo['gap'])); - // Ignore gaps before the first block. - if (!isNaN(newGap) && gaps.length > 0) { - gaps[gaps.length - 1] = newGap; - } else { - gaps.push(defaultGap); - } - } - - /** - * Delete blocks, mats and buttons from a previous showing of the flyout. + * Delete elements from a previous showing of the flyout. */ private clearOldBlocks() { - // Delete any blocks from a previous showing. - const oldBlocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; (block = oldBlocks[i]); i++) { - if (this.blockIsRecyclable_(block)) { - this.recycleBlock(block); - } else { - block.dispose(false, false); - } - } - // Delete any mats from a previous showing. - for (let j = 0; j < this.mats.length; j++) { - const rect = this.mats[j]; - if (rect) { - Tooltip.unbindMouseEvents(rect); - dom.removeNode(rect); - } - } - this.mats.length = 0; - // Delete any buttons from a previous showing. - for (let i = 0, button; (button = this.buttons_[i]); i++) { - button.dispose(); - } - this.buttons_.length = 0; + this.getContents().forEach((element) => { + const inflater = this.getInflaterForType(element.type); + inflater?.disposeElement(element.element); + }); // Clear potential variables from the previous showing. this.workspace_.getPotentialVariableMap()?.clear(); } - /** - * Empties all of the recycled blocks, properly disposing of them. - */ - private emptyRecycledBlocks() { - for (let i = 0; i < this.recycledBlocks.length; i++) { - this.recycledBlocks[i].dispose(); - } - this.recycledBlocks = []; - } - - /** - * Returns whether the given block can be recycled or not. - * - * @param _block The block to check for recyclability. - * @returns True if the block can be recycled. False otherwise. - */ - protected blockIsRecyclable_(_block: BlockSvg): boolean { - // By default, recycling is disabled. - return false; - } - - /** - * Puts a previously created block into the recycle bin and moves it to the - * top of the workspace. Used during large workspace swaps to limit the number - * of new DOM elements we need to create. - * - * @param block The block to recycle. - */ - private recycleBlock(block: BlockSvg) { - const xy = block.getRelativeToSurfaceXY(); - block.moveBy(-xy.x, -xy.y); - this.recycledBlocks.push(block); - } - - /** - * Add listeners to a block that has been added to the flyout. - * - * @param root The root node of the SVG group the block is in. - * @param block The block to add listeners for. - * @param rect The invisible rectangle under the block that acts - * as a mat for that block. - */ - protected addBlockListeners_( - root: SVGElement, - block: BlockSvg, - rect: SVGElement, - ) { - this.listeners.push( - browserEvents.conditionalBind( - root, - 'pointerdown', - null, - this.blockMouseDown(block), - ), - ); - this.listeners.push( - browserEvents.conditionalBind( - rect, - 'pointerdown', - null, - this.blockMouseDown(block), - ), - ); - this.listeners.push( - browserEvents.bind(root, 'pointerenter', block, () => { - if (!this.targetWorkspace.isDragging()) { - block.addSelect(); - } - }), - ); - this.listeners.push( - browserEvents.bind(root, 'pointerleave', block, () => { - if (!this.targetWorkspace.isDragging()) { - block.removeSelect(); - } - }), - ); - this.listeners.push( - browserEvents.bind(rect, 'pointerenter', block, () => { - if (!this.targetWorkspace.isDragging()) { - block.addSelect(); - } - }), - ); - this.listeners.push( - browserEvents.bind(rect, 'pointerleave', block, () => { - if (!this.targetWorkspace.isDragging()) { - block.removeSelect(); - } - }), - ); - } - - /** - * Handle a pointerdown on an SVG block in a non-closing flyout. - * - * @param block The flyout block to copy. - * @returns Function to call when block is clicked. - */ - private blockMouseDown(block: BlockSvg): Function { - return (e: PointerEvent) => { - const gesture = this.targetWorkspace.getGesture(e); - if (gesture) { - gesture.setStartBlock(block); - gesture.handleFlyoutStart(e, this); - } - }; - } - /** * Pointer down on the flyout background. Start a vertical scroll drag. * @@ -1162,123 +828,12 @@ export abstract class Flyout } if (this.autoClose) { this.hide(); - } else { - this.filterForCapacity(); } return newBlock; } /** - * Initialize the given button: move it to the correct location, - * add listeners, etc. - * - * @param button The button to initialize and place. - * @param x The x position of the cursor during this layout pass. - * @param y The y position of the cursor during this layout pass. - */ - protected initFlyoutButton_(button: FlyoutButton, x: number, y: number) { - const buttonSvg = button.createDom(); - button.moveTo(x, y); - button.show(); - // Clicking on a flyout button or label is a lot like clicking on the - // flyout background. - this.listeners.push( - browserEvents.conditionalBind( - buttonSvg, - 'pointerdown', - this, - this.onMouseDown, - ), - ); - - this.buttons_.push(button); - } - - /** - * Create and place a rectangle corresponding to the given block. - * - * @param block The block to associate the rect to. - * @param x The x position of the cursor during this layout pass. - * @param y The y position of the cursor during this layout pass. - * @param blockHW The height and width of - * the block. - * @param index The index into the mats list where this rect should - * be placed. - * @returns Newly created SVG element for the rectangle behind - * the block. - */ - protected createRect_( - block: BlockSvg, - x: number, - y: number, - blockHW: {height: number; width: number}, - index: number, - ): SVGElement { - // Create an invisible rectangle under the block to act as a button. Just - // using the block as a button is poor, since blocks have holes in them. - const rect = dom.createSvgElement(Svg.RECT, { - 'fill-opacity': 0, - 'x': x, - 'y': y, - 'height': blockHW.height, - 'width': blockHW.width, - }); - (rect as AnyDuringMigration).tooltip = block; - Tooltip.bindMouseEvents(rect); - // Add the rectangles under the blocks, so that the blocks' tooltips work. - this.workspace_.getCanvas().insertBefore(rect, block.getSvgRoot()); - - this.rectMap_.set(block, rect); - this.mats[index] = rect; - return rect; - } - - /** - * Move a rectangle to sit exactly behind a block, taking into account tabs, - * hats, and any other protrusions we invent. - * - * @param rect The rectangle to move directly behind the block. - * @param block The block the rectangle should be behind. - */ - protected moveRectToBlock_(rect: SVGElement, block: BlockSvg) { - const blockHW = block.getHeightWidth(); - rect.setAttribute('width', String(blockHW.width)); - rect.setAttribute('height', String(blockHW.height)); - - const blockXY = block.getRelativeToSurfaceXY(); - rect.setAttribute('y', String(blockXY.y)); - rect.setAttribute( - 'x', - String(this.RTL ? blockXY.x - blockHW.width : blockXY.x), - ); - } - - /** - * Filter the blocks on the flyout to disable the ones that are above the - * capacity limit. For instance, if the user may only place two more blocks - * on the workspace, an "a + b" block that has two shadow blocks would be - * disabled. - */ - private filterForCapacity() { - const blocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - if (!this.permanentlyDisabled.includes(block)) { - const enable = this.targetWorkspace.isCapacityAvailable( - common.getBlockTypeCounts(block), - ); - while (block) { - block.setDisabledReason( - !enable, - WORKSPACE_AT_BLOCK_CAPACITY_DISABLED_REASON, - ); - block = block.getNextBlock(); - } - } - } - } - - /** - * Reflow blocks and their mats. + * Reflow flyout contents. */ reflow() { if (this.reflowWrapper) { @@ -1377,13 +932,37 @@ export abstract class Flyout // No 'reason' provided since events are disabled. block.moveTo(new Coordinate(finalOffset.x, finalOffset.y)); } + + /** + * Returns the inflater responsible for constructing items of the given type. + * + * @param type The type of flyout content item to provide an inflater for. + * @returns An inflater object for the given type, or null if no inflater + * is registered for that type. + */ + protected getInflaterForType(type: string): IFlyoutInflater | null { + if (this.inflaters.has(type)) { + return this.inflaters.get(type) ?? null; + } + + const InflaterClass = registry.getClass( + registry.Type.FLYOUT_INFLATER, + type, + ); + if (InflaterClass) { + const inflater = new InflaterClass(); + this.inflaters.set(type, inflater); + return inflater; + } + + return null; + } } /** * A flyout content item. */ export interface FlyoutItem { - type: FlyoutItemType; - button?: FlyoutButton | undefined; - block?: BlockSvg | undefined; + type: string; + element: IBoundedElement; } diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index c23dede74..d19320c82 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -14,7 +14,6 @@ import * as browserEvents from './browser_events.js'; import * as dropDownDiv from './dropdowndiv.js'; import {Flyout, FlyoutItem} from './flyout_base.js'; -import type {FlyoutButton} from './flyout_button.js'; import type {Options} from './options.js'; import * as registry from './registry.js'; import {Scrollbar} from './scrollbar.js'; @@ -252,10 +251,9 @@ export class HorizontalFlyout extends Flyout { /** * Lay out the blocks in the flyout. * - * @param contents The blocks and buttons to lay out. - * @param gaps The visible gaps between blocks. + * @param contents The flyout items to lay out. */ - protected override layout_(contents: FlyoutItem[], gaps: number[]) { + protected override layout_(contents: FlyoutItem[]) { this.workspace_.scale = this.targetWorkspace!.scale; const margin = this.MARGIN; let cursorX = margin + this.tabWidth_; @@ -264,43 +262,11 @@ export class HorizontalFlyout extends Flyout { contents = contents.reverse(); } - for (let i = 0, item; (item = contents[i]); i++) { - if (item.type === 'block') { - const block = item.block; - - if (block === undefined || block === null) { - continue; - } - - const allBlocks = block.getDescendants(false); - - for (let j = 0, child; (child = allBlocks[j]); j++) { - // Mark blocks as being inside a flyout. This is used to detect and - // prevent the closure of the flyout if the user right-clicks on such - // a block. - child.isInFlyout = true; - } - const root = block.getSvgRoot(); - const blockHW = block.getHeightWidth(); - // Figure out where to place the block. - const tab = block.outputConnection ? this.tabWidth_ : 0; - let moveX; - if (this.RTL) { - moveX = cursorX + blockHW.width; - } else { - moveX = cursorX - tab; - } - block.moveBy(moveX, cursorY); - - const rect = this.createRect_(block, moveX, cursorY, blockHW, i); - cursorX += blockHW.width + gaps[i]; - - this.addBlockListeners_(root, block, rect); - } else if (item.type === 'button') { - const button = item.button as FlyoutButton; - this.initFlyoutButton_(button, cursorX, cursorY); - cursorX += button.width + gaps[i]; - } + for (const item of contents) { + const rect = item.element.getBoundingRectangle(); + const moveX = this.RTL ? cursorX + rect.getWidth() : cursorX; + item.element.moveBy(moveX, cursorY); + cursorX += item.element.getBoundingRectangle().getWidth(); } } @@ -367,26 +333,17 @@ export class HorizontalFlyout extends Flyout { */ protected override reflowInternal_() { this.workspace_.scale = this.getFlyoutScale(); - let flyoutHeight = 0; - const blocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - flyoutHeight = Math.max(flyoutHeight, block.getHeightWidth().height); - } - const buttons = this.buttons_; - for (let i = 0, button; (button = buttons[i]); i++) { - flyoutHeight = Math.max(flyoutHeight, button.height); - } + let flyoutHeight = this.getContents().reduce((maxHeightSoFar, item) => { + return Math.max( + maxHeightSoFar, + item.element.getBoundingRectangle().getHeight(), + ); + }, 0); flyoutHeight += this.MARGIN * 1.5; flyoutHeight *= this.workspace_.scale; flyoutHeight += Scrollbar.scrollbarThickness; if (this.getHeight() !== flyoutHeight) { - for (let i = 0, block; (block = blocks[i]); i++) { - if (this.rectMap_.has(block)) { - this.moveRectToBlock_(this.rectMap_.get(block)!, block); - } - } - // TODO(#7689): Remove this. // Workspace with no scrollbars where this is permanently open on the top. // If scrollbars exist they properly update the metrics. diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index 374b0c33a..8e7c1691c 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -14,7 +14,6 @@ import * as browserEvents from './browser_events.js'; import * as dropDownDiv from './dropdowndiv.js'; import {Flyout, FlyoutItem} from './flyout_base.js'; -import type {FlyoutButton} from './flyout_button.js'; import type {Options} from './options.js'; import * as registry from './registry.js'; import {Scrollbar} from './scrollbar.js'; @@ -221,51 +220,17 @@ export class VerticalFlyout extends Flyout { /** * Lay out the blocks in the flyout. * - * @param contents The blocks and buttons to lay out. - * @param gaps The visible gaps between blocks. + * @param contents The flyout items to lay out. */ - protected override layout_(contents: FlyoutItem[], gaps: number[]) { + protected override layout_(contents: FlyoutItem[]) { this.workspace_.scale = this.targetWorkspace!.scale; const margin = this.MARGIN; const cursorX = this.RTL ? margin : margin + this.tabWidth_; let cursorY = margin; - for (let i = 0, item; (item = contents[i]); i++) { - if (item.type === 'block') { - const block = item.block; - if (!block) { - continue; - } - const allBlocks = block.getDescendants(false); - for (let j = 0, child; (child = allBlocks[j]); j++) { - // Mark blocks as being inside a flyout. This is used to detect and - // prevent the closure of the flyout if the user right-clicks on such - // a block. - child.isInFlyout = true; - } - const root = block.getSvgRoot(); - const blockHW = block.getHeightWidth(); - const moveX = block.outputConnection - ? cursorX - this.tabWidth_ - : cursorX; - block.moveBy(moveX, cursorY); - - const rect = this.createRect_( - block, - this.RTL ? moveX - blockHW.width : moveX, - cursorY, - blockHW, - i, - ); - - this.addBlockListeners_(root, block, rect); - - cursorY += blockHW.height + gaps[i]; - } else if (item.type === 'button') { - const button = item.button as FlyoutButton; - this.initFlyoutButton_(button, cursorX, cursorY); - cursorY += button.height + gaps[i]; - } + for (const item of contents) { + item.element.moveBy(cursorX, cursorY); + cursorY += item.element.getBoundingRectangle().getHeight(); } } @@ -328,52 +293,32 @@ export class VerticalFlyout extends Flyout { } /** - * Compute width of flyout. toolbox.Position mat under each block. + * Compute width of flyout. * For RTL: Lay out the blocks and buttons to be right-aligned. */ protected override reflowInternal_() { this.workspace_.scale = this.getFlyoutScale(); - let flyoutWidth = 0; - const blocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - let width = block.getHeightWidth().width; - if (block.outputConnection) { - width -= this.tabWidth_; - } - flyoutWidth = Math.max(flyoutWidth, width); - } - for (let i = 0, button; (button = this.buttons_[i]); i++) { - flyoutWidth = Math.max(flyoutWidth, button.width); - } + let flyoutWidth = this.getContents().reduce((maxWidthSoFar, item) => { + return Math.max( + maxWidthSoFar, + item.element.getBoundingRectangle().getWidth(), + ); + }, 0); flyoutWidth += this.MARGIN * 1.5 + this.tabWidth_; flyoutWidth *= this.workspace_.scale; flyoutWidth += Scrollbar.scrollbarThickness; if (this.getWidth() !== flyoutWidth) { - for (let i = 0, block; (block = blocks[i]); i++) { - if (this.RTL) { - // With the flyoutWidth known, right-align the blocks. - const oldX = block.getRelativeToSurfaceXY().x; - let newX = flyoutWidth / this.workspace_.scale - this.MARGIN; - if (!block.outputConnection) { - newX -= this.tabWidth_; - } - block.moveBy(newX - oldX, 0); - } - if (this.rectMap_.has(block)) { - this.moveRectToBlock_(this.rectMap_.get(block)!, block); - } - } if (this.RTL) { - // With the flyoutWidth known, right-align the buttons. - for (let i = 0, button; (button = this.buttons_[i]); i++) { - const y = button.getPosition().y; - const x = + // With the flyoutWidth known, right-align the flyout contents. + for (const item of this.getContents()) { + const oldX = item.element.getBoundingRectangle().left; + const newX = flyoutWidth / this.workspace_.scale - - button.width - + item.element.getBoundingRectangle().getWidth() - this.MARGIN - this.tabWidth_; - button.moveTo(x, y); + item.element.moveBy(newX - oldX, 0); } } diff --git a/core/keyboard_nav/ast_node.ts b/core/keyboard_nav/ast_node.ts index 7985ac6dc..d71bef6a4 100644 --- a/core/keyboard_nav/ast_node.ts +++ b/core/keyboard_nav/ast_node.ts @@ -13,6 +13,7 @@ // Former goog.module ID: Blockly.ASTNode import {Block} from '../block.js'; +import {BlockSvg} from '../block_svg.js'; import type {Connection} from '../connection.js'; import {ConnectionType} from '../connection_type.js'; import type {Field} from '../field.js'; @@ -347,10 +348,10 @@ export class ASTNode { ); if (!nextItem) return null; - if (nextItem.type === 'button' && nextItem.button) { - return ASTNode.createButtonNode(nextItem.button); - } else if (nextItem.type === 'block' && nextItem.block) { - return ASTNode.createStackNode(nextItem.block); + if (nextItem.element instanceof FlyoutButton) { + return ASTNode.createButtonNode(nextItem.element); + } else if (nextItem.element instanceof BlockSvg) { + return ASTNode.createStackNode(nextItem.element); } return null; @@ -370,12 +371,15 @@ export class ASTNode { forward: boolean, ): FlyoutItem | null { const currentIndex = flyoutContents.findIndex((item: FlyoutItem) => { - if (currentLocation instanceof Block && item.block === currentLocation) { + if ( + currentLocation instanceof BlockSvg && + item.element === currentLocation + ) { return true; } if ( currentLocation instanceof FlyoutButton && - item.button === currentLocation + item.element === currentLocation ) { return true; } diff --git a/tests/mocha/flyout_test.js b/tests/mocha/flyout_test.js index 522efbdc6..2240f264e 100644 --- a/tests/mocha/flyout_test.js +++ b/tests/mocha/flyout_test.js @@ -317,16 +317,12 @@ suite('Flyout', function () { function checkFlyoutInfo(flyoutSpy) { const flyoutInfo = flyoutSpy.returnValues[0]; - const contents = flyoutInfo.contents; - const gaps = flyoutInfo.gaps; + const contents = flyoutInfo; - const expectedGaps = [20, 24, 24]; - assert.deepEqual(gaps, expectedGaps); - - assert.equal(contents.length, 3, 'Contents'); + assert.equal(contents.length, 6, 'Contents'); assert.equal(contents[0].type, 'block', 'Contents'); - const block = contents[0]['block']; + const block = contents[0]['element']; assert.instanceOf(block, Blockly.BlockSvg); assert.equal(block.getFieldValue('OP'), 'NEQ'); const childA = block.getInputTargetBlock('A'); @@ -336,11 +332,20 @@ suite('Flyout', function () { assert.equal(childA.getFieldValue('NUM'), 1); assert.equal(childB.getFieldValue('NUM'), 2); - assert.equal(contents[1].type, 'button', 'Contents'); - assert.instanceOf(contents[1]['button'], Blockly.FlyoutButton); + assert.equal(contents[1].type, 'sep'); + assert.equal(contents[1].element.getBoundingRectangle().getHeight(), 20); assert.equal(contents[2].type, 'button', 'Contents'); - assert.instanceOf(contents[2]['button'], Blockly.FlyoutButton); + assert.instanceOf(contents[2]['element'], Blockly.FlyoutButton); + + assert.equal(contents[3].type, 'sep'); + assert.equal(contents[3].element.getBoundingRectangle().getHeight(), 24); + + assert.equal(contents[4].type, 'label', 'Contents'); + assert.instanceOf(contents[4]['element'], Blockly.FlyoutButton); + + assert.equal(contents[5].type, 'sep'); + assert.equal(contents[5].element.getBoundingRectangle().getHeight(), 24); } suite('Direct show', function () { @@ -629,35 +634,5 @@ suite('Flyout', function () { const block = this.flyout.workspace_.getAllBlocks()[0]; assert.equal(block.getFieldValue('NUM'), 321); }); - - test('Recycling enabled', function () { - this.flyout.blockIsRecyclable_ = function () { - return true; - }; - this.flyout.show({ - 'contents': [ - { - 'kind': 'BLOCK', - 'type': 'math_number', - 'fields': { - 'NUM': 123, - }, - }, - ], - }); - this.flyout.show({ - 'contents': [ - { - 'kind': 'BLOCK', - 'type': 'math_number', - 'fields': { - 'NUM': 321, - }, - }, - ], - }); - const block = this.flyout.workspace_.getAllBlocks()[0]; - assert.equal(block.getFieldValue('NUM'), 123); - }); }); }); From 14c9b1abcbf365467f435108da03825dc726afb2 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 2 Oct 2024 09:52:16 -0700 Subject: [PATCH 066/102] chore: remove obsolete comment. (#8606) --- core/generator.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/generator.ts b/core/generator.ts index 869e29a6a..85763b3cf 100644 --- a/core/generator.ts +++ b/core/generator.ts @@ -252,8 +252,7 @@ export class CodeGenerator { return opt_thisOnly ? '' : this.blockToCode(block.getChildren(false)[0]); } - // Look up block generator function in dictionary - but fall back - // to looking up on this if not found, for backwards compatibility. + // Look up block generator function in dictionary. const func = this.forBlock[block.type]; if (typeof func !== 'function') { throw Error( From 2dfd8c30adcc6fd922d8084266be09c381bf0dc6 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 2 Oct 2024 10:32:44 -0700 Subject: [PATCH 067/102] feat: Allow specifying the placeholder text of workspace comments. (#8608) --- core/comments/comment_view.ts | 5 +++++ core/comments/rendered_workspace_comment.ts | 5 +++++ core/contextmenu_items.ts | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core/comments/comment_view.ts b/core/comments/comment_view.ts index bda2b9762..798f51f96 100644 --- a/core/comments/comment_view.ts +++ b/core/comments/comment_view.ts @@ -684,6 +684,11 @@ export class CommentView implements IRenderedElement { this.onTextChange(); } + /** Sets the placeholder text displayed for an empty comment. */ + setPlaceholderText(text: string) { + this.textArea.placeholder = text; + } + /** Registers a callback that listens for text changes. */ addTextChangeListener(listener: (oldText: string, newText: string) => void) { this.textChangeListeners.push(listener); diff --git a/core/comments/rendered_workspace_comment.ts b/core/comments/rendered_workspace_comment.ts index 79caf6a1d..3144702ae 100644 --- a/core/comments/rendered_workspace_comment.ts +++ b/core/comments/rendered_workspace_comment.ts @@ -104,6 +104,11 @@ export class RenderedWorkspaceComment this.view.setText(text); } + /** Sets the placeholder text displayed if the comment is empty. */ + setPlaceholderText(text: string): void { + this.view.setPlaceholderText(text); + } + /** Sets the size of the comment. */ override setSize(size: Size) { // setSize will trigger the change listener that updates diff --git a/core/contextmenu_items.ts b/core/contextmenu_items.ts index 254906ce7..f1d3293a4 100644 --- a/core/contextmenu_items.ts +++ b/core/contextmenu_items.ts @@ -617,7 +617,7 @@ export function registerCommentCreate() { if (!workspace) return; eventUtils.setGroup(true); const comment = new RenderedWorkspaceComment(workspace); - comment.setText(Msg['WORKSPACE_COMMENT_DEFAULT_TEXT']); + comment.setPlaceholderText(Msg['WORKSPACE_COMMENT_DEFAULT_TEXT']); comment.moveTo( pixelsToWorkspaceCoords( new Coordinate(e.clientX, e.clientY), From 9fc693140a251feddd7905f81c5f3edbdf982b5c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Oct 2024 08:19:27 -0700 Subject: [PATCH 068/102] fix: Correctly calculate the bounds of hat blocks. (#8616) --- core/renderers/common/constants.ts | 5 ++++- core/renderers/common/info.ts | 1 - core/renderers/zelos/constants.ts | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/renderers/common/constants.ts b/core/renderers/common/constants.ts index c4ea9b24e..01217edb7 100644 --- a/core/renderers/common/constants.ts +++ b/core/renderers/common/constants.ts @@ -727,7 +727,10 @@ export class ConstantProvider { svgPaths.point(70, -height), svgPaths.point(width, 0), ]); - return {height, width, path: mainPath}; + // Height is actually the Y position of the control points defining the + // curve of the hat; the hat's actual rendered height is 3/4 of the control + // points' Y position, per https://stackoverflow.com/a/5327329 + return {height: height * 0.75, width, path: mainPath}; } /** diff --git a/core/renderers/common/info.ts b/core/renderers/common/info.ts index 995124c1b..329c47442 100644 --- a/core/renderers/common/info.ts +++ b/core/renderers/common/info.ts @@ -232,7 +232,6 @@ export class RenderInfo { if (hasHat) { const hat = new Hat(this.constants_); this.topRow.elements.push(hat); - this.topRow.capline = hat.ascenderHeight; } else if (hasPrevious) { this.topRow.hasPreviousConnection = true; this.topRow.connection = new PreviousConnection( diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index 28c2cb4fc..ddb2bdeef 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -290,7 +290,10 @@ export class ConstantProvider extends BaseConstantProvider { svgPaths.point(71, -height), svgPaths.point(width, 0), ]); - return {height, width, path: mainPath}; + // Height is actually the Y position of the control points defining the + // curve of the hat; the hat's actual rendered height is 3/4 of the control + // points' Y position, per https://stackoverflow.com/a/5327329 + return {height: height * 0.75, width, path: mainPath}; } /** From edd02f6955d9d391a04be3ac6acc93f0344078ad Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Oct 2024 08:19:49 -0700 Subject: [PATCH 069/102] fix: Take the flyout into account when positioning the workspace after a toolbox change. (#8617) * fix: Take the flyout into account when positioning the workspace after a toolbox change. * fix: Accomodate top-positioned toolboxes. --- core/toolbox/toolbox.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index cd91b2d8a..0c5a8e2a4 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -734,13 +734,18 @@ export class Toolbox // relative to the new absolute edge (ie toolbox edge). const workspace = this.workspace_; const rect = this.HtmlDiv!.getBoundingClientRect(); + const flyout = this.getFlyout(); const newX = this.toolboxPosition === toolbox.Position.LEFT - ? workspace.scrollX + rect.width + ? workspace.scrollX + + rect.width + + (flyout?.isVisible() ? flyout.getWidth() : 0) : workspace.scrollX; const newY = this.toolboxPosition === toolbox.Position.TOP - ? workspace.scrollY + rect.height + ? workspace.scrollY + + rect.height + + (flyout?.isVisible() ? flyout.getHeight() : 0) : workspace.scrollY; workspace.translate(newX, newY); From aeb1a806720c815c2496bb9a02b5e8228af68c61 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Oct 2024 08:20:34 -0700 Subject: [PATCH 070/102] feat: Allow specifying the default size of comments. (#8618) --- core/comments/comment_view.ts | 6 +++++- core/comments/workspace_comment.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/comments/comment_view.ts b/core/comments/comment_view.ts index 798f51f96..7146f21ca 100644 --- a/core/comments/comment_view.ts +++ b/core/comments/comment_view.ts @@ -52,7 +52,7 @@ export class CommentView implements IRenderedElement { private textArea: HTMLTextAreaElement; /** The current size of the comment in workspace units. */ - private size: Size = new Size(120, 100); + private size: Size; /** Whether the comment is collapsed or not. */ private collapsed: boolean = false; @@ -102,6 +102,9 @@ export class CommentView implements IRenderedElement { /** Size of this comment when the resize drag was initiated. */ private preResizeSize?: Size; + /** The default size of newly created comments. */ + static defaultCommentSize = new Size(120, 100); + constructor(private readonly workspace: WorkspaceSvg) { this.svgRoot = dom.createSvgElement(Svg.G, { 'class': 'blocklyComment blocklyEditable blocklyDraggable', @@ -128,6 +131,7 @@ export class CommentView implements IRenderedElement { workspace.getLayerManager()?.append(this, layers.BLOCK); // Set size to the default size. + this.size = CommentView.defaultCommentSize; this.setSizeWithoutFiringEvents(this.size); // Set default transform (including inverted scale for RTL). diff --git a/core/comments/workspace_comment.ts b/core/comments/workspace_comment.ts index 0764b5168..9d50f74fc 100644 --- a/core/comments/workspace_comment.ts +++ b/core/comments/workspace_comment.ts @@ -11,6 +11,7 @@ import * as idGenerator from '../utils/idgenerator.js'; import * as eventUtils from '../events/utils.js'; import {CommentMove} from '../events/events_comment_move.js'; import {CommentResize} from '../events/events_comment_resize.js'; +import {CommentView} from './comment_view.js'; export class WorkspaceComment { /** The unique identifier for this comment. */ @@ -20,7 +21,7 @@ export class WorkspaceComment { private text = ''; /** The size of the comment in workspace units. */ - private size = new Size(120, 100); + private size: Size; /** Whether the comment is collapsed or not. */ private collapsed = false; @@ -55,6 +56,7 @@ export class WorkspaceComment { id?: string, ) { this.id = id && !workspace.getCommentById(id) ? id : idGenerator.genUid(); + this.size = CommentView.defaultCommentSize; workspace.addTopComment(this); From 089179bb016af6df063e25304bdb136242e43eeb Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 15 Oct 2024 13:45:39 -0700 Subject: [PATCH 071/102] fix: Fix exception when disposing of a workspace with a variable block obscuring a shadow block. (#8619) --- core/workspace.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/workspace.ts b/core/workspace.ts index 9e7d7c884..36ce720b8 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -371,7 +371,14 @@ export class Workspace implements IASTNodeLocation { this.topComments[this.topComments.length - 1].dispose(); } eventUtils.setGroup(existingGroup); - this.variableMap.clear(); + // If this is a flyout workspace, its variable map is shared with the + // parent workspace, so we either don't want to disturb it if we're just + // disposing the flyout, or if the flyout is being disposed because the + // main workspace is being disposed, then the main workspace will handle + // cleaning it up. + if (!this.isFlyout) { + this.variableMap.clear(); + } if (this.potentialVariableMap) { this.potentialVariableMap.clear(); } From e4eb9751cb10ed12c0201c5a8b1a27e2541ed60b Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 31 Oct 2024 11:31:53 -0700 Subject: [PATCH 072/102] fix: improve typings and export additional types (#8631) --- core/blockly.ts | 9 ++++++--- core/clipboard.ts | 4 ++-- core/dropdowndiv.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/blockly.ts b/core/blockly.ts index fda49830f..7163d10b0 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -60,6 +60,7 @@ import { FieldDropdownConfig, FieldDropdownFromJsonConfig, FieldDropdownValidator, + ImageProperties, MenuGenerator, MenuGeneratorFunction, MenuOption, @@ -94,7 +95,7 @@ import { FieldVariableFromJsonConfig, FieldVariableValidator, } from './field_variable.js'; -import {Flyout} from './flyout_base.js'; +import {Flyout, FlyoutItem} from './flyout_base.js'; import {FlyoutButton} from './flyout_button.js'; import {FlyoutSeparator} from './flyout_separator.js'; import {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; @@ -156,7 +157,7 @@ import {IStyleable} from './interfaces/i_styleable.js'; import {IToolbox} from './interfaces/i_toolbox.js'; import {IToolboxItem} from './interfaces/i_toolbox_item.js'; import {IVariableMap} from './interfaces/i_variable_map.js'; -import {IVariableModel} from './interfaces/i_variable_model.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import { IVariableBackedParameterModel, isVariableBackedParameterModel, @@ -488,6 +489,7 @@ export { FieldDropdownConfig, FieldDropdownFromJsonConfig, FieldDropdownValidator, + ImageProperties, MenuGenerator, MenuGeneratorFunction, MenuOption, @@ -513,7 +515,7 @@ export { FieldVariableFromJsonConfig, FieldVariableValidator, }; -export {Flyout}; +export {Flyout, FlyoutItem}; export {FlyoutButton}; export {FlyoutMetricsManager}; export {FlyoutSeparator}; @@ -568,6 +570,7 @@ export {IToolbox}; export {IToolboxItem}; export {IVariableMap}; export {IVariableModel}; +export {IVariableState}; export {IVariableBackedParameterModel, isVariableBackedParameterModel}; export {Marker}; export {MarkerManager}; diff --git a/core/clipboard.ts b/core/clipboard.ts index ed574d112..d63555d11 100644 --- a/core/clipboard.ts +++ b/core/clipboard.ts @@ -7,7 +7,7 @@ // Former goog.module ID: Blockly.clipboard import type {ICopyData, ICopyable} from './interfaces/i_copyable.js'; -import {BlockPaster} from './clipboard/block_paster.js'; +import {BlockPaster, BlockCopyData} from './clipboard/block_paster.js'; import * as globalRegistry from './registry.js'; import {WorkspaceSvg} from './workspace_svg.js'; import * as registry from './clipboard/registry.js'; @@ -110,4 +110,4 @@ export const TEST_ONLY = { copyInternal, }; -export {BlockPaster, registry}; +export {BlockPaster, BlockCopyData, registry}; diff --git a/core/dropdowndiv.ts b/core/dropdowndiv.ts index 35eb6eaed..a47e78c2a 100644 --- a/core/dropdowndiv.ts +++ b/core/dropdowndiv.ts @@ -160,7 +160,7 @@ export function getOwner(): Field | null { * * @returns Div to populate with content. */ -export function getContentDiv(): Element { +export function getContentDiv(): HTMLDivElement { return content; } From 631190c5cb90481a6e5c5f133ce040ea31ccc8de Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 31 Oct 2024 12:02:11 -0700 Subject: [PATCH 073/102] chore: Remove unneeded handling for @suppress and @alias. (#8633) --- tsdoc.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tsdoc.json b/tsdoc.json index 51900e7c3..5470830e7 100644 --- a/tsdoc.json +++ b/tsdoc.json @@ -3,10 +3,6 @@ // Include the definitions that are required for API Extractor "extends": ["@microsoft/api-extractor/extends/tsdoc-base.json"], "tagDefinitions": [ - { - "tagName": "@alias", - "syntaxKind": "block" - }, { "tagName": "@define", "syntaxKind": "block" @@ -18,18 +14,12 @@ { "tagName": "@nocollapse", "syntaxKind": "modifier" - }, - { - "tagName": "@suppress", - "syntaxKind": "modifier" } ], "supportForTags": { - "@alias": true, "@define": true, "@license": true, - "@nocollapse": true, - "@suppress": true + "@nocollapse": true } } From 2523093cc9b1bc5e44a82c08ab9b534e4e042081 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 12:15:55 -0800 Subject: [PATCH 074/102] refactor!: Remove the InsertionMarkerManager. (#8649) * refactor!: Remove the InsertionMarkerManager. * chore: Remove unused imports. * chore: Remove import of insertion marker manager test. --- core/blockly.ts | 2 - core/insertion_marker_manager.ts | 742 ------------------- core/renderers/common/renderer.ts | 49 -- core/renderers/zelos/renderer.ts | 34 - tests/mocha/index.html | 1 - tests/mocha/insertion_marker_manager_test.js | 443 ----------- 6 files changed, 1271 deletions(-) delete mode 100644 core/insertion_marker_manager.ts delete mode 100644 tests/mocha/insertion_marker_manager_test.js diff --git a/core/blockly.ts b/core/blockly.ts index 7163d10b0..aab29b544 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -113,7 +113,6 @@ import * as icons from './icons.js'; import {inject} from './inject.js'; import {Input} from './inputs/input.js'; import * as inputs from './inputs.js'; -import {InsertionMarkerManager} from './insertion_marker_manager.js'; import {InsertionMarkerPreviewer} from './insertion_marker_previewer.js'; import {IASTNodeLocation} from './interfaces/i_ast_node_location.js'; import {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js'; @@ -555,7 +554,6 @@ export {IMetricsManager}; export {IMovable}; export {Input}; export {inputs}; -export {InsertionMarkerManager}; export {InsertionMarkerPreviewer}; export {IObservable, isObservable}; export {IPaster, isPaster}; diff --git a/core/insertion_marker_manager.ts b/core/insertion_marker_manager.ts deleted file mode 100644 index 376297f10..000000000 --- a/core/insertion_marker_manager.ts +++ /dev/null @@ -1,742 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Class that controls updates to connections during drags. - * - * @class - */ -// Former goog.module ID: Blockly.InsertionMarkerManager - -import {finishQueuedRenders} from './render_management.js'; -import * as blockAnimations from './block_animations.js'; -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 * as blocks from './serialization/blocks.js'; -import * as eventUtils from './events/utils.js'; -import type {IDeleteArea} from './interfaces/i_delete_area.js'; -import type {IDragTarget} from './interfaces/i_drag_target.js'; -import type {RenderedConnection} from './rendered_connection.js'; -import type {Coordinate} from './utils/coordinate.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; -import * as renderManagement from './render_management.js'; - -/** Represents a nearby valid connection. */ -interface CandidateConnection { - /** - * A nearby valid connection that is compatible with local. - * This is not on any of the blocks that are being dragged. - */ - closest: RenderedConnection; - /** - * A connection on the dragging stack that is compatible with closest. This is - * on the top block that is being dragged or the last block in the dragging - * stack. - */ - local: RenderedConnection; - radius: number; -} - -/** - * 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. - * - * @deprecated v10 - Use an IConnectionPreviewer instead. - */ -export class InsertionMarkerManager { - /** - * The top block in the stack being dragged. - * Does not change during a drag. - */ - private readonly topBlock: BlockSvg; - - /** - * The workspace on which these connections are being dragged. - * Does not change during a drag. - */ - private readonly workspace: WorkspaceSvg; - - /** - * The last connection on the stack, if it's not the last connection on the - * first block. - * Set in initAvailableConnections, if at all. - */ - private lastOnStack: RenderedConnection | null = null; - - /** - * The insertion marker corresponding to the last block in the stack, if - * that's not the same as the first block in the stack. - * Set in initAvailableConnections, if at all - */ - private lastMarker: BlockSvg | null = null; - - /** - * The insertion marker that shows up between blocks to show where a block - * would go if dropped immediately. - */ - private firstMarker: BlockSvg; - - /** - * Information about the connection that would be made if the dragging block - * were released immediately. Updated on every mouse move. - */ - private activeCandidate: CandidateConnection | null = null; - - /** - * Whether the block would be deleted if it were dropped immediately. - * Updated on every mouse move. - * - * @internal - */ - public wouldDeleteBlock = false; - - /** - * Connection on the insertion marker block that corresponds to - * the active candidate's local connection on the currently dragged block. - */ - private markerConnection: RenderedConnection | null = null; - - /** The block that currently has an input being highlighted, or null. */ - private highlightedBlock: BlockSvg | null = null; - - /** The block being faded to indicate replacement, or null. */ - private fadedBlock: BlockSvg | null = null; - - /** - * The connections on the dragging blocks that are available to connect to - * other blocks. This includes all open connections on the top block, as - * well as the last connection on the block stack. - */ - private availableConnections: RenderedConnection[]; - - /** @param block The top block in the stack being dragged. */ - constructor(block: BlockSvg) { - common.setSelected(block); - this.topBlock = block; - - this.workspace = block.workspace; - - this.firstMarker = this.createMarkerBlock(this.topBlock); - - this.availableConnections = this.initAvailableConnections(); - - if (this.lastOnStack) { - this.lastMarker = this.createMarkerBlock( - this.lastOnStack.getSourceBlock(), - ); - } - } - - /** - * Sever all links from this object. - * - * @internal - */ - dispose() { - this.availableConnections.length = 0; - this.disposeInsertionMarker(this.firstMarker); - this.disposeInsertionMarker(this.lastMarker); - } - - /** - * Update the available connections for the top block. These connections can - * change if a block is unplugged and the stack is healed. - * - * @internal - */ - updateAvailableConnections() { - this.availableConnections = this.initAvailableConnections(); - } - - /** - * Return whether the block would be connected if dropped immediately, based - * on information from the most recent move event. - * - * @returns True if the block would be connected if dropped immediately. - * @internal - */ - wouldConnectBlock(): boolean { - return !!this.activeCandidate; - } - - /** - * Connect to the closest connection and render the results. - * This should be called at the end of a drag. - * - * @internal - */ - applyConnections() { - if (!this.activeCandidate) return; - eventUtils.disable(); - this.hidePreview(); - eventUtils.enable(); - const {local, closest} = this.activeCandidate; - local.connect(closest); - const inferiorConnection = local.isSuperior() ? closest : local; - const rootBlock = this.topBlock.getRootBlock(); - - finishQueuedRenders().then(() => { - blockAnimations.connectionUiEffect(inferiorConnection.getSourceBlock()); - // bringToFront is incredibly expensive. Delay until the next frame. - setTimeout(() => { - rootBlock.bringToFront(); - }, 0); - }); - } - - /** - * Update connections based on the most recent move location. - * - * @param dxy Position relative to drag start, in workspace units. - * @param dragTarget The drag target that the block is currently over. - * @internal - */ - update(dxy: Coordinate, dragTarget: IDragTarget | null) { - const newCandidate = this.getCandidate(dxy); - - this.wouldDeleteBlock = this.shouldDelete(!!newCandidate, dragTarget); - - const shouldUpdate = - this.wouldDeleteBlock || this.shouldUpdatePreviews(newCandidate, dxy); - - if (shouldUpdate) { - // Don't fire events for insertion marker creation or movement. - eventUtils.disable(); - this.maybeHidePreview(newCandidate); - this.maybeShowPreview(newCandidate); - eventUtils.enable(); - } - } - - /** - * Create an insertion marker that represents the given block. - * - * @param sourceBlock The block that the insertion marker will represent. - * @returns The insertion marker that represents the given block. - */ - private createMarkerBlock(sourceBlock: BlockSvg): BlockSvg { - eventUtils.disable(); - let result: BlockSvg; - try { - const blockJson = blocks.save(sourceBlock, { - addCoordinates: false, - addInputBlocks: false, - addNextBlocks: false, - doFullSerialization: false, - }); - - if (!blockJson) { - throw new Error( - `Failed to serialize source block. ${sourceBlock.toDevString()}`, - ); - } - - result = blocks.append(blockJson, this.workspace) as BlockSvg; - - // Turn shadow blocks that are created programmatically during - // initalization to insertion markers too. - for (const block of result.getDescendants(false)) { - block.setInsertionMarker(true); - } - - result.initSvg(); - result.getSvgRoot().setAttribute('visibility', 'hidden'); - } finally { - eventUtils.enable(); - } - - return result; - } - - /** - * 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. - */ - private initAvailableConnections(): RenderedConnection[] { - const available = this.topBlock.getConnections_(false); - // Also check the last connection on this stack - const lastOnStack = this.topBlock.lastConnectionInStack(true); - if (lastOnStack && lastOnStack !== this.topBlock.nextConnection) { - available.push(lastOnStack); - this.lastOnStack = lastOnStack; - } - return available; - } - - /** - * Whether the previews (insertion marker and replacement marker) should be - * updated based on the closest candidate and the current drag distance. - * - * @param newCandidate A new candidate connection that may replace the current - * best candidate. - * @param dxy Position relative to drag start, in workspace units. - * @returns Whether the preview should be updated. - */ - private shouldUpdatePreviews( - newCandidate: CandidateConnection | null, - dxy: Coordinate, - ): boolean { - // Only need to update if we were showing a preview before. - if (!newCandidate) return !!this.activeCandidate; - - // We weren't showing a preview before, but we should now. - if (!this.activeCandidate) return true; - - // We're already showing an insertion marker. - // Decide whether the new connection has higher priority. - const {local: activeLocal, closest: activeClosest} = this.activeCandidate; - if ( - activeClosest === newCandidate.closest && - activeLocal === newCandidate.local - ) { - // The connection was the same as the current connection. - return false; - } - - const xDiff = activeLocal.x + dxy.x - activeClosest.x; - const yDiff = activeLocal.y + dxy.y - activeClosest.y; - const curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff); - // Slightly prefer the existing preview over a new preview. - return ( - newCandidate.radius < curDistance - config.currentConnectionPreference - ); - } - - /** - * Find the nearest valid connection, which may be the same as the current - * closest connection. - * - * @param dxy Position relative to drag start, in workspace units. - * @returns An object containing a local connection, a closest connection, and - * a radius. - */ - private getCandidate(dxy: Coordinate): CandidateConnection | null { - // It's possible that a block has added or removed connections during a - // drag, (e.g. in a drag/move event handler), so let's update the available - // connections. Note that this will be called on every move while dragging, - // so it might cause slowness, especially if the block stack is large. If - // so, maybe it could be made more efficient. Also note that we won't update - // the connections if we've already connected the insertion marker to a - // block. - if (!this.markerConnection || !this.markerConnection.isConnected()) { - this.updateAvailableConnections(); - } - - let radius = this.getStartRadius(); - let candidate = null; - for (let i = 0; i < this.availableConnections.length; i++) { - const myConnection = this.availableConnections[i]; - const neighbour = myConnection.closest(radius, dxy); - if (neighbour.connection) { - candidate = { - closest: neighbour.connection, - local: myConnection, - radius: neighbour.radius, - }; - radius = neighbour.radius; - } - } - return candidate; - } - - /** - * Decide the radius at which to start searching for the closest connection. - * - * @returns The radius at which to start the search for the closest - * connection. - */ - private getStartRadius(): number { - // If there is already a connection highlighted, - // increase the radius we check for making new connections. - // When a connection is highlighted, blocks move around when the - // insertion marker is created, which could cause the connection became out - // of range. By increasing radiusConnection when a connection already - // exists, we never "lose" the connection from the offset. - return this.activeCandidate - ? config.connectingSnapRadius - : config.snapRadius; - } - - /** - * Whether ending the drag would delete the block. - * - * @param newCandidate Whether there is a candidate connection that the - * block could connect to if the drag ended immediately. - * @param dragTarget The drag target that the block is currently over. - * @returns Whether dropping the block immediately would delete the block. - */ - private shouldDelete( - newCandidate: boolean, - dragTarget: IDragTarget | null, - ): boolean { - if (dragTarget) { - const componentManager = this.workspace.getComponentManager(); - const isDeleteArea = componentManager.hasCapability( - dragTarget.id, - ComponentManager.Capability.DELETE_AREA, - ); - if (isDeleteArea) { - return (dragTarget as IDeleteArea).wouldDelete(this.topBlock); - } - } - return false; - } - - /** - * Show an insertion marker or replacement highlighting during a drag, if - * needed. - * At the beginning of this function, this.activeConnection should be null. - * - * @param newCandidate A new candidate connection that may replace the current - * best candidate. - */ - private maybeShowPreview(newCandidate: CandidateConnection | null) { - if (this.wouldDeleteBlock) return; // Nope, don't add a marker. - if (!newCandidate) return; // Nothing to connect to. - - const closest = newCandidate.closest; - - // Something went wrong and we're trying to connect to an invalid - // connection. - if ( - closest === this.activeCandidate?.closest || - closest.getSourceBlock().isInsertionMarker() - ) { - console.log('Trying to connect to an insertion marker'); - return; - } - this.activeCandidate = newCandidate; - // Add an insertion marker or replacement marker. - this.showPreview(this.activeCandidate); - } - - /** - * A preview should be shown. This function figures out if it should be a - * block highlight or an insertion marker, and shows the appropriate one. - * - * @param activeCandidate The connection that will be made if the drag ends - * immediately. - */ - private showPreview(activeCandidate: CandidateConnection) { - const renderer = this.workspace.getRenderer(); - const method = renderer.getConnectionPreviewMethod( - activeCandidate.closest, - activeCandidate.local, - this.topBlock, - ); - - switch (method) { - case InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE: - this.showInsertionInputOutline(activeCandidate); - break; - case InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER: - this.showInsertionMarker(activeCandidate); - break; - case InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE: - this.showReplacementFade(activeCandidate); - break; - } - - // Optionally highlight the actual connection, as a nod to previous - // behaviour. - if (renderer.shouldHighlightConnection(activeCandidate.closest)) { - activeCandidate.closest.highlight(); - } - } - - /** - * Hide an insertion marker or replacement highlighting during a drag, if - * needed. - * At the end of this function, this.activeCandidate will be null. - * - * @param newCandidate A new candidate connection that may replace the current - * best candidate. - */ - private maybeHidePreview(newCandidate: CandidateConnection | null) { - // If there's no new preview, remove the old one but don't bother deleting - // it. We might need it later, and this saves disposing of it and recreating - // it. - if (!newCandidate) { - this.hidePreview(); - } else { - if (this.activeCandidate) { - const closestChanged = - this.activeCandidate.closest !== newCandidate.closest; - const localChanged = this.activeCandidate.local !== newCandidate.local; - - // If there's a new preview and there was a preview before, and either - // connection has changed, remove the old preview. - // Also hide if we had a preview before but now we're going to delete - // instead. - if (closestChanged || localChanged || this.wouldDeleteBlock) { - this.hidePreview(); - } - } - } - - // Either way, clear out old state. - this.markerConnection = null; - this.activeCandidate = null; - } - - /** - * A preview should be hidden. Loop through all possible preview modes - * and hide everything. - */ - private hidePreview() { - const closest = this.activeCandidate?.closest; - if ( - closest && - closest.targetBlock() && - this.workspace.getRenderer().shouldHighlightConnection(closest) - ) { - closest.unhighlight(); - } - this.hideReplacementFade(); - this.hideInsertionInputOutline(); - this.hideInsertionMarker(); - } - - /** - * Shows an insertion marker connected to the appropriate blocks (based on - * manager state). - * - * @param activeCandidate The connection that will be made if the drag ends - * immediately. - */ - private showInsertionMarker(activeCandidate: CandidateConnection) { - const {local, closest} = activeCandidate; - - const isLastInStack = this.lastOnStack && local === this.lastOnStack; - let insertionMarker = isLastInStack ? this.lastMarker : this.firstMarker; - if (!insertionMarker) { - throw new Error( - 'Cannot show the insertion marker because there is no insertion ' + - 'marker block', - ); - } - let imConn; - try { - imConn = insertionMarker.getMatchingConnection( - local.getSourceBlock(), - local, - ); - } catch (e) { - // It's possible that the number of connections on the local block has - // changed since the insertion marker was originally created. Let's - // recreate the insertion marker and try again. In theory we could - // 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. - 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 ' + - 'marker block', - ); - } - imConn = insertionMarker.getMatchingConnection( - local.getSourceBlock(), - local, - ); - } - - if (!imConn) { - throw new Error( - 'Cannot show the insertion marker because there is no ' + - 'associated connection', - ); - } - - if (imConn === this.markerConnection) { - throw new Error( - "Made it to showInsertionMarker_ even though the marker isn't " + - 'changing', - ); - } - - // Render disconnected from everything else so that we have a valid - // connection location. - insertionMarker.queueRender(); - renderManagement.triggerQueuedRenders(); - - // Connect() also renders the insertion marker. - imConn.connect(closest); - - const originalOffsetToTarget = { - x: closest.x - imConn.x, - y: closest.y - imConn.y, - }; - const originalOffsetInBlock = imConn.getOffsetInBlock().clone(); - const imConnConst = imConn; - renderManagement.finishQueuedRenders().then(() => { - // Position so that the existing block doesn't move. - insertionMarker?.positionNearConnection( - imConnConst, - originalOffsetToTarget, - originalOffsetInBlock, - ); - insertionMarker?.getSvgRoot().setAttribute('visibility', 'visible'); - }); - - this.markerConnection = imConn; - } - - /** - * Disconnects and hides the current insertion marker. Should return the - * blocks to their original state. - */ - private hideInsertionMarker() { - if (!this.markerConnection) return; - - const markerConn = this.markerConnection; - const imBlock = markerConn.getSourceBlock(); - const markerPrev = imBlock.previousConnection; - const markerOutput = imBlock.outputConnection; - - 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(true); - } - - if (markerConn.targetConnection) { - throw Error( - 'markerConnection still connected at the end of ' + - 'disconnectInsertionMarker', - ); - } - - this.markerConnection = null; - const svg = imBlock.getSvgRoot(); - if (svg) { - svg.setAttribute('visibility', 'hidden'); - } - } - - /** - * Shows an outline around the input the closest connection belongs to. - * - * @param activeCandidate The connection that will be made if the drag ends - * immediately. - */ - private showInsertionInputOutline(activeCandidate: CandidateConnection) { - const closest = activeCandidate.closest; - this.highlightedBlock = closest.getSourceBlock(); - this.highlightedBlock.highlightShapeForInput(closest, true); - } - - /** Hides any visible input outlines. */ - private hideInsertionInputOutline() { - if (!this.highlightedBlock) return; - - if (!this.activeCandidate) { - throw new Error( - 'Cannot hide the insertion marker outline because ' + - 'there is no active candidate', - ); - } - this.highlightedBlock.highlightShapeForInput( - this.activeCandidate.closest, - false, - ); - this.highlightedBlock = null; - } - - /** - * Shows a replacement fade affect on the closest connection's target block - * (the block that is currently connected to it). - * - * @param activeCandidate The connection that will be made if the drag ends - * immediately. - */ - private showReplacementFade(activeCandidate: CandidateConnection) { - this.fadedBlock = activeCandidate.closest.targetBlock(); - if (!this.fadedBlock) { - throw new Error( - 'Cannot show the replacement fade because the ' + - 'closest connection does not have a target block', - ); - } - this.fadedBlock.fadeForReplacement(true); - } - - /** - * Hides/Removes any visible fade affects. - */ - private hideReplacementFade() { - if (!this.fadedBlock) return; - - this.fadedBlock.fadeForReplacement(false); - this.fadedBlock = null; - } - - /** - * Get a list of the insertion markers that currently exist. Drags have 0, 1, - * or 2 insertion markers. - * - * @returns A possibly empty list of insertion marker blocks. - * @internal - */ - getInsertionMarkers(): BlockSvg[] { - const result = []; - if (this.firstMarker) { - result.push(this.firstMarker); - } - if (this.lastMarker) { - result.push(this.lastMarker); - } - 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 { - /** - * An enum describing different kinds of previews the InsertionMarkerManager - * could display. - */ - export enum PREVIEW_TYPE { - INSERTION_MARKER = 0, - INPUT_OUTLINE = 1, - REPLACEMENT_FADE = 2, - } -} - -export type PreviewType = InsertionMarkerManager.PREVIEW_TYPE; -export const PreviewType = InsertionMarkerManager.PREVIEW_TYPE; diff --git a/core/renderers/common/renderer.ts b/core/renderers/common/renderer.ts index 15a958db4..255bc81ff 100644 --- a/core/renderers/common/renderer.ts +++ b/core/renderers/common/renderer.ts @@ -10,13 +10,8 @@ import type {Block} from '../../block.js'; import type {BlockSvg} from '../../block_svg.js'; import {Connection} from '../../connection.js'; import {ConnectionType} from '../../connection_type.js'; -import { - InsertionMarkerManager, - PreviewType, -} from '../../insertion_marker_manager.js'; import type {IRegistrable} from '../../interfaces/i_registrable.js'; import type {Marker} from '../../keyboard_nav/marker.js'; -import type {RenderedConnection} from '../../rendered_connection.js'; import type {BlockStyle, Theme} from '../../theme.js'; import type {WorkspaceSvg} from '../../workspace_svg.js'; @@ -26,7 +21,6 @@ import type {IPathObject} from './i_path_object.js'; import {RenderInfo} from './info.js'; import {MarkerSvg} from './marker_svg.js'; import {PathObject} from './path_object.js'; -import * as deprecation from '../../utils/deprecation.js'; /** * The base class for a block renderer. @@ -224,49 +218,6 @@ export class Renderer implements IRegistrable { ); } - /** - * Chooses a connection preview method based on the available connection, the - * current dragged connection, and the block being dragged. - * - * @param closest The available connection. - * @param local The connection currently being dragged. - * @param topBlock The block currently being dragged. - * @returns The preview type to display. - * - * @deprecated v10 - This function is no longer respected. A custom - * IConnectionPreviewer may be able to fulfill the functionality. - */ - getConnectionPreviewMethod( - closest: RenderedConnection, - local: RenderedConnection, - topBlock: BlockSvg, - ): PreviewType { - deprecation.warn( - 'getConnectionPreviewMethod', - 'v10', - 'v12', - 'an IConnectionPreviewer, if it fulfills your use case.', - ); - if ( - local.type === ConnectionType.OUTPUT_VALUE || - local.type === ConnectionType.PREVIOUS_STATEMENT - ) { - if ( - !closest.isConnected() || - this.orphanCanConnectAtEnd( - topBlock, - closest.targetBlock() as BlockSvg, - local.type, - ) - ) { - return InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; - } - return InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE; - } - - return InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER; - } - /** * Render the block. * diff --git a/core/renderers/zelos/renderer.ts b/core/renderers/zelos/renderer.ts index 354a3f35a..44fddacb2 100644 --- a/core/renderers/zelos/renderer.ts +++ b/core/renderers/zelos/renderer.ts @@ -7,10 +7,7 @@ // Former goog.module ID: Blockly.zelos.Renderer import type {BlockSvg} from '../../block_svg.js'; -import {ConnectionType} from '../../connection_type.js'; -import {InsertionMarkerManager} from '../../insertion_marker_manager.js'; import type {Marker} from '../../keyboard_nav/marker.js'; -import type {RenderedConnection} from '../../rendered_connection.js'; import type {BlockStyle} from '../../theme.js'; import type {WorkspaceSvg} from '../../workspace_svg.js'; import * as blockRendering from '../common/block_rendering.js'; @@ -22,7 +19,6 @@ import {Drawer} from './drawer.js'; import {RenderInfo} from './info.js'; import {MarkerSvg} from './marker_svg.js'; import {PathObject} from './path_object.js'; -import * as deprecation from '../../utils/deprecation.js'; /** * The zelos renderer. This renderer emulates Scratch-style and MakeCode-style @@ -108,36 +104,6 @@ export class Renderer extends BaseRenderer { override getConstants(): ConstantProvider { return this.constants_; } - - /** - * @deprecated v10 - This function is no longer respected. A custom - * IConnectionPreviewer may be able to fulfill the functionality. - */ - override getConnectionPreviewMethod( - closest: RenderedConnection, - local: RenderedConnection, - topBlock: BlockSvg, - ) { - deprecation.warn( - 'getConnectionPreviewMethod', - 'v10', - 'v12', - 'an IConnectionPreviewer, if it fulfills your use case.', - ); - if (local.type === ConnectionType.OUTPUT_VALUE) { - if (!closest.isConnected()) { - return InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE; - } - // TODO: Returning this is a total hack, because we don't want to show - // a replacement fade, we want to show an outline affect. - // Sadly zelos does not support showing an outline around filled - // inputs, so we have to pretend like the connected block is getting - // replaced. - return InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE; - } - - return super.getConnectionPreviewMethod(closest, local, topBlock); - } } blockRendering.register('zelos', Renderer); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 58a71e0ac..ce9948a21 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -95,7 +95,6 @@ import './icon_test.js'; import './input_test.js'; import './insertion_marker_test.js'; - import './insertion_marker_manager_test.js'; import './jso_deserialization_test.js'; import './jso_serialization_test.js'; import './json_test.js'; diff --git a/tests/mocha/insertion_marker_manager_test.js b/tests/mocha/insertion_marker_manager_test.js deleted file mode 100644 index e6992109f..000000000 --- a/tests/mocha/insertion_marker_manager_test.js +++ /dev/null @@ -1,443 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {assert} from '../../node_modules/chai/chai.js'; -import { - sharedTestSetup, - sharedTestTeardown, -} from './test_helpers/setup_teardown.js'; -import { - defineRowBlock, - defineRowToStackBlock, - defineStackBlock, -} from './test_helpers/block_definitions.js'; - -suite('Insertion marker manager', function () { - setup(function () { - sharedTestSetup.call(this); - defineRowBlock(); - defineStackBlock(); - defineRowToStackBlock(); - this.workspace = Blockly.inject('blocklyDiv'); - }); - teardown(function () { - sharedTestTeardown.call(this); - }); - - suite('Creating markers', function () { - function createBlocksAndManager(workspace, state) { - Blockly.serialization.workspaces.load(state, workspace); - const block = workspace.getBlockById('first'); - const manager = new Blockly.InsertionMarkerManager(block); - return manager; - } - - test('One stack block creates one marker', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'stack_block', - 'id': 'first', - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - }); - - test('Two stack blocks create two markers', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'stack_block', - 'id': 'first', - 'next': { - 'block': { - 'type': 'stack_block', - 'id': 'second', - }, - }, - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 2); - }); - - test('Three stack blocks create two markers', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'stack_block', - 'id': 'first', - 'next': { - 'block': { - 'type': 'stack_block', - 'id': 'second', - 'next': { - 'block': { - 'type': 'stack_block', - 'id': 'third', - }, - }, - }, - }, - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 2); - }); - - test('One value block creates one marker', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'row_block', - 'id': 'first', - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - }); - - test('Two value blocks create one marker', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'row_block', - 'id': 'first', - 'inputs': { - 'INPUT': { - 'block': { - 'type': 'row_block', - 'id': 'second', - }, - }, - }, - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - }); - - test('One row to stack block creates one marker', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'row_to_stack_block', - 'id': 'first', - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - }); - - test('Row to stack block with child creates two markers', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'row_to_stack_block', - 'id': 'first', - 'next': { - 'block': { - 'type': 'stack_block', - 'id': 'second', - }, - }, - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.equal(markers.length, 2); - }); - - suite('children being set as insertion markers', function () { - setup(function () { - Blockly.Blocks['shadows_in_init'] = { - init: function () { - this.appendValueInput('test').connection.setShadowState({ - 'type': 'math_number', - }); - this.setPreviousStatement(true); - }, - }; - - Blockly.Blocks['shadows_in_load'] = { - init: function () { - this.appendValueInput('test'); - this.setPreviousStatement(true); - }, - - loadExtraState: function () { - this.getInput('test').connection.setShadowState({ - 'type': 'math_number', - }); - }, - - saveExtraState: function () { - return true; - }, - }; - }); - - teardown(function () { - delete Blockly.Blocks['shadows_in_init']; - delete Blockly.Blocks['shadows_in_load']; - }); - - test('Shadows added in init are set as insertion markers', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'id': 'first', - 'type': 'shadows_in_init', - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.isTrue( - markers[0].getChildren()[0].isInsertionMarker(), - 'Expected the shadow block to be an insertion maker', - ); - }); - - test('Shadows added in `loadExtraState` are set as insertion markers', function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'id': 'first', - 'type': 'shadows_in_load', - }, - ], - }, - }; - const manager = createBlocksAndManager(this.workspace, state); - const markers = manager.getInsertionMarkers(); - assert.isTrue( - markers[0].getChildren()[0].isInsertionMarker(), - 'Expected the shadow block to be an insertion maker', - ); - }); - }); - }); - - suite('Would delete block', function () { - setup(function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'stack_block', - 'id': 'first', - }, - ], - }, - }; - Blockly.serialization.workspaces.load(state, this.workspace); - this.block = this.workspace.getBlockById('first'); - this.manager = new Blockly.InsertionMarkerManager(this.block); - - const componentManager = this.workspace.getComponentManager(); - this.stub = sinon.stub(componentManager, 'hasCapability'); - this.dxy = new Blockly.utils.Coordinate(0, 0); - }); - - test('Over delete area and accepted would delete', function () { - this.stub - .withArgs( - 'fakeDragTarget', - Blockly.ComponentManager.Capability.DELETE_AREA, - ) - .returns(true); - const fakeDragTarget = { - wouldDelete: sinon.fake.returns(true), - id: 'fakeDragTarget', - }; - this.manager.update(this.dxy, fakeDragTarget); - assert.isTrue(this.manager.wouldDeleteBlock); - }); - - test('Over delete area and rejected would not delete', function () { - this.stub - .withArgs( - 'fakeDragTarget', - Blockly.ComponentManager.Capability.DELETE_AREA, - ) - .returns(true); - const fakeDragTarget = { - wouldDelete: sinon.fake.returns(false), - id: 'fakeDragTarget', - }; - this.manager.update(this.dxy, fakeDragTarget); - assert.isFalse(this.manager.wouldDeleteBlock); - }); - - test('Drag target is not a delete area would not delete', function () { - this.stub - .withArgs( - 'fakeDragTarget', - Blockly.ComponentManager.Capability.DELETE_AREA, - ) - .returns(false); - const fakeDragTarget = { - wouldDelete: sinon.fake.returns(false), - id: 'fakeDragTarget', - }; - this.manager.update(this.dxy, fakeDragTarget); - assert.isFalse(this.manager.wouldDeleteBlock); - }); - - test('Not over drag target would not delete', function () { - this.manager.update(this.dxy, null); - assert.isFalse(this.manager.wouldDeleteBlock); - }); - }); - - suite('Would connect stack blocks', function () { - setup(function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'stack_block', - 'id': 'first', - 'x': 0, - 'y': 0, - }, - { - 'type': 'stack_block', - 'id': 'other', - 'x': 200, - 'y': 200, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(state, this.workspace); - this.block = this.workspace.getBlockById('first'); - this.block.setDragging(true); - this.manager = new Blockly.InsertionMarkerManager(this.block); - }); - - test('No other blocks nearby would not connect', function () { - this.manager.update(new Blockly.utils.Coordinate(0, 0), null); - assert.isFalse(this.manager.wouldConnectBlock()); - }); - - test('Near other block and above would connect before', function () { - this.manager.update(new Blockly.utils.Coordinate(200, 190), null); - assert.isTrue(this.manager.wouldConnectBlock()); - const markers = this.manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - const marker = markers[0]; - assert.isTrue(marker.nextConnection.isConnected()); - }); - - test('Near other block and below would connect after', function () { - this.manager.update(new Blockly.utils.Coordinate(200, 210), null); - assert.isTrue(this.manager.wouldConnectBlock()); - const markers = this.manager.getInsertionMarkers(); - assert.equal(markers.length, 1); - const marker = markers[0]; - assert.isTrue(marker.previousConnection.isConnected()); - }); - - test('Near other block and left would connect', function () { - this.manager.update(new Blockly.utils.Coordinate(190, 200), null); - assert.isTrue(this.manager.wouldConnectBlock()); - }); - - test('Near other block and right would connect', function () { - this.manager.update(new Blockly.utils.Coordinate(210, 200), null); - assert.isTrue(this.manager.wouldConnectBlock()); - }); - }); - - suite('Would connect row blocks', function () { - setup(function () { - const state = { - 'blocks': { - 'blocks': [ - { - 'type': 'row_block', - 'id': 'first', - 'x': 0, - 'y': 0, - }, - { - 'type': 'row_block', - 'id': 'other', - 'x': 200, - 'y': 200, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(state, this.workspace); - this.block = this.workspace.getBlockById('first'); - this.block.setDragging(true); - this.manager = new Blockly.InsertionMarkerManager(this.block); - }); - - test('No other blocks nearby would not connect', function () { - this.manager.update(new Blockly.utils.Coordinate(0, 0), null); - assert.isFalse(this.manager.wouldConnectBlock()); - }); - - test('Near other block and above would connect', function () { - this.manager.update(new Blockly.utils.Coordinate(200, 190), null); - assert.isTrue(this.manager.wouldConnectBlock()); - }); - - test('Near other block and below would connect', function () { - this.manager.update(new Blockly.utils.Coordinate(200, 210), null); - assert.isTrue(this.manager.wouldConnectBlock()); - }); - - test('Near other block and left would connect before', function () { - this.manager.update(new Blockly.utils.Coordinate(190, 200), null); - assert.isTrue(this.manager.wouldConnectBlock()); - const markers = this.manager.getInsertionMarkers(); - assert.isTrue(markers[0].getInput('INPUT').connection.isConnected()); - }); - - test('Near other block and right would connect after', function () { - this.manager.update(new Blockly.utils.Coordinate(210, 200), null); - assert.isTrue(this.manager.wouldConnectBlock()); - const markers = this.manager.getInsertionMarkers(); - assert.isTrue(markers[0].outputConnection.isConnected()); - }); - }); -}); From d804c1a3c40c56bdcb342da069e04b4979f46d0f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 12:16:17 -0800 Subject: [PATCH 075/102] refactor!: Improve ability to use CSS to style Blockly. (#8647) * refactor!: Rename blocklyTreeIconClosed to blocklyToolboxCategoryIconClosed. * refactor!: Rename blocklyTreeLabel to blocklyToolboxCategoryLabel * refactor!: Rename blocklyToolboxDiv to blocklyToolbox. * refactor: remove unreferenced CSS classes. * refactor!: Remove the blocklyArrowTop and blocklyArrowBottom classes. * feat: Add a blocklyTextInputField class to text fields. --- core/css.ts | 14 -------------- core/dropdowndiv.ts | 17 +++++------------ core/field_textinput.ts | 8 ++++++++ core/toolbox/category.ts | 24 ++++++++++++------------ core/toolbox/separator.ts | 2 +- core/toolbox/toolbox.ts | 4 ++-- tests/mocha/toolbox_test.js | 2 +- 7 files changed, 29 insertions(+), 42 deletions(-) diff --git a/core/css.ts b/core/css.ts index d18d930a9..22abfa32a 100644 --- a/core/css.ts +++ b/core/css.ts @@ -132,22 +132,12 @@ let content = ` z-index: -1; background-color: inherit; border-color: inherit; -} - -.blocklyArrowTop { border-top: 1px solid; border-left: 1px solid; border-top-left-radius: 4px; border-color: inherit; } -.blocklyArrowBottom { - border-bottom: 1px solid; - border-right: 1px solid; - border-bottom-right-radius: 4px; - border-color: inherit; -} - .blocklyHighlightedConnectionPath { fill: none; stroke: #fc3; @@ -243,10 +233,6 @@ let content = ` cursor: inherit; } -.blocklyFieldDropdown:not(.blocklyHidden) { - display: block; -} - .blocklyIconGroup { cursor: default; } diff --git a/core/dropdowndiv.ts b/core/dropdowndiv.ts index a47e78c2a..5ae1b99cf 100644 --- a/core/dropdowndiv.ts +++ b/core/dropdowndiv.ts @@ -697,19 +697,12 @@ function positionInternal( // Update arrow CSS. if (metrics.arrowVisible) { + const x = metrics.arrowX; + const y = metrics.arrowY; + const rotation = metrics.arrowAtTop ? 45 : 225; arrow.style.display = ''; - arrow.style.transform = - 'translate(' + - metrics.arrowX + - 'px,' + - metrics.arrowY + - 'px) rotate(45deg)'; - arrow.setAttribute( - 'class', - metrics.arrowAtTop - ? 'blocklyDropDownArrow blocklyArrowTop' - : 'blocklyDropDownArrow blocklyArrowBottom', - ); + arrow.style.transform = `translate(${x}px, ${y}px) rotate(${rotation}deg)`; + arrow.setAttribute('class', 'blocklyDropDownArrow'); } else { arrow.style.display = 'none'; } diff --git a/core/field_textinput.ts b/core/field_textinput.ts index 39bdca970..5b754624a 100644 --- a/core/field_textinput.ts +++ b/core/field_textinput.ts @@ -22,6 +22,7 @@ import { } from './field_input.js'; import * as fieldRegistry from './field_registry.js'; import * as parsing from './utils/parsing.js'; +import * as dom from './utils/dom.js'; /** * Class for an editable text field. @@ -49,6 +50,13 @@ export class FieldTextInput extends FieldInput { super(value, validator, config); } + override initView() { + super.initView(); + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyTextInputField'); + } + } + /** * Ensure that the input value casts to a valid string. * diff --git a/core/toolbox/category.ts b/core/toolbox/category.ts index 06f219e5e..c173c33ca 100644 --- a/core/toolbox/category.ts +++ b/core/toolbox/category.ts @@ -135,11 +135,11 @@ export class ToolboxCategory 'row': 'blocklyToolboxCategory', 'rowcontentcontainer': 'blocklyTreeRowContentContainer', 'icon': 'blocklyToolboxCategoryIcon', - 'label': 'blocklyTreeLabel', + 'label': 'blocklyToolboxCategoryLabel', 'contents': 'blocklyToolboxCategoryGroup', 'selected': 'blocklyToolboxSelected', 'openicon': 'blocklyToolboxCategoryIconOpen', - 'closedicon': 'blocklyTreeIconClosed', + 'closedicon': 'blocklyToolboxCategoryIconClosed', }; } @@ -663,11 +663,11 @@ Css.register(` background-color: rgba(255, 255, 255, .2); } -.blocklyToolboxDiv[layout="h"] .blocklyToolboxCategoryContainer { +.blocklyToolbox[layout="h"] .blocklyToolboxCategoryContainer { margin: 1px 5px 1px 0; } -.blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategoryContainer { +.blocklyToolbox[dir="RTL"][layout="h"] .blocklyToolboxCategoryContainer { margin: 1px 0 1px 5px; } @@ -679,7 +679,7 @@ Css.register(` white-space: nowrap; } -.blocklyToolboxDiv[dir="RTL"] .blocklyToolboxCategory { +.blocklyToolbox[dir="RTL"] .blocklyToolboxCategory { margin-left: 8px; padding-right: 0; } @@ -692,19 +692,19 @@ Css.register(` width: 16px; } -.blocklyTreeIconClosed { +.blocklyToolboxCategoryIconClosed { background-position: -32px -1px; } -.blocklyToolboxDiv[dir="RTL"] .blocklyTreeIconClosed { +.blocklyToolbox[dir="RTL"] .blocklyToolboxCategoryIconClosed { background-position: 0 -1px; } -.blocklyToolboxSelected>.blocklyTreeIconClosed { +.blocklyToolboxSelected>.blocklyToolboxCategoryIconClosed { background-position: -32px -17px; } -.blocklyToolboxDiv[dir="RTL"] .blocklyToolboxSelected>.blocklyTreeIconClosed { +.blocklyToolbox[dir="RTL"] .blocklyToolboxSelected>.blocklyToolboxCategoryIconClosed { background-position: 0 -17px; } @@ -716,18 +716,18 @@ Css.register(` background-position: -16px -17px; } -.blocklyTreeLabel { +.blocklyToolboxCategoryLabel { cursor: default; font: 16px sans-serif; padding: 0 3px; vertical-align: middle; } -.blocklyToolboxDelete .blocklyTreeLabel { +.blocklyToolboxDelete .blocklyToolboxCategoryLabel { cursor: url("<<>>/handdelete.cur"), auto; } -.blocklyToolboxSelected .blocklyTreeLabel { +.blocklyToolboxSelected .blocklyToolboxCategoryLabel { color: #fff; } `); diff --git a/core/toolbox/separator.ts b/core/toolbox/separator.ts index ec003daf6..5824b4393 100644 --- a/core/toolbox/separator.ts +++ b/core/toolbox/separator.ts @@ -88,7 +88,7 @@ Css.register(` margin: 5px 0; } -.blocklyToolboxDiv[layout="h"] .blocklyTreeSeparator { +.blocklyToolbox[layout="h"] .blocklyTreeSeparator { border-right: solid #e5e5e5 1px; border-bottom: none; height: auto; diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index 0c5a8e2a4..efd5381b4 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -198,7 +198,7 @@ export class Toolbox protected createContainer_(): HTMLDivElement { const toolboxContainer = document.createElement('div'); toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v'); - dom.addClass(toolboxContainer, 'blocklyToolboxDiv'); + dom.addClass(toolboxContainer, 'blocklyToolbox'); toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); return toolboxContainer; } @@ -1107,7 +1107,7 @@ Css.register(` } /* Category tree in Toolbox. */ -.blocklyToolboxDiv { +.blocklyToolbox { user-select: none; -ms-user-select: none; -webkit-user-select: none; diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index 755f08cf8..1cb8df979 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -47,7 +47,7 @@ suite('Toolbox', function () { test('Init called -> HtmlDiv is inserted before parent node', function () { const toolboxDiv = Blockly.common.getMainWorkspace().getInjectionDiv() .childNodes[0]; - assert.equal(toolboxDiv.className, 'blocklyToolboxDiv'); + assert.equal(toolboxDiv.className, 'blocklyToolbox'); }); test('Init called -> Toolbox is subscribed to background and foreground colour', function () { const themeManager = this.toolbox.workspace_.getThemeManager(); From 8f2228658e9beaa67db6f4bd78638767ae47a2d3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 7 Nov 2024 12:16:55 -0800 Subject: [PATCH 076/102] feat: Allow customizing GRID_UNIT for the Zelos renderer. (#8636) --- core/renderers/zelos/constants.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index ddb2bdeef..213d8a259 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -151,9 +151,19 @@ export class ConstantProvider extends BaseConstantProvider { */ SQUARED: Shape | null = null; - constructor() { + /** + * Creates a new ConstantProvider. + * + * @param gridUnit If set, defines the base unit used to calculate other + * constants. + */ + constructor(gridUnit?: number) { super(); + if (gridUnit) { + this.GRID_UNIT = gridUnit; + } + this.SMALL_PADDING = this.GRID_UNIT; this.MEDIUM_PADDING = 2 * this.GRID_UNIT; From 7bbbb959f05e8d51b5c0b5dcc17bce48e21d8ca6 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 11 Nov 2024 07:54:17 -0800 Subject: [PATCH 077/102] feat!: Use CSS to specify field cursors. (#8648) --- core/css.ts | 13 +++++++++++++ core/field.ts | 5 ----- core/field_checkbox.ts | 5 ----- core/field_dropdown.ts | 8 +++++--- core/field_input.ts | 7 ++++--- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/core/css.ts b/core/css.ts index 22abfa32a..0c547ca0a 100644 --- a/core/css.ts +++ b/core/css.ts @@ -464,4 +464,17 @@ input[type=number] { z-index: 80; pointer-events: none; } + +.blocklyField { + cursor: default; +} + +.blocklyInputField { + cursor: text; +} + +.blocklyDragging .blocklyField, +.blocklyDragging .blocklyIconGroup { + cursor: grabbing; +} `; diff --git a/core/field.ts b/core/field.ts index 2d50c04eb..fbaf1cf62 100644 --- a/core/field.ts +++ b/core/field.ts @@ -193,9 +193,6 @@ export abstract class Field */ SERIALIZABLE = false; - /** Mouse cursor style when over the hotspot that initiates the editor. */ - CURSOR = ''; - /** * @param value The initial value of the field. * Also accepts Field.SKIP_SETUP if you wish to skip setup (only used by @@ -536,11 +533,9 @@ export abstract class Field if (this.enabled_ && block.isEditable()) { dom.addClass(group, 'blocklyEditableField'); dom.removeClass(group, 'blocklyNonEditableField'); - group.style.cursor = this.CURSOR; } else { dom.addClass(group, 'blocklyNonEditableField'); dom.removeClass(group, 'blocklyEditableField'); - group.style.cursor = ''; } } diff --git a/core/field_checkbox.ts b/core/field_checkbox.ts index 0773a1f82..eb68be2e8 100644 --- a/core/field_checkbox.ts +++ b/core/field_checkbox.ts @@ -35,11 +35,6 @@ export class FieldCheckbox extends Field { */ override SERIALIZABLE = true; - /** - * Mouse cursor style when over the hotspot that initiates editability. - */ - override CURSOR = 'default'; - /** * NOTE: The default value is set in `Field`, so maintain that value instead * of overwriting it here or in the constructor. diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index 5f26ac3b4..a5f7830f6 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -70,9 +70,6 @@ export class FieldDropdown extends Field { */ override SERIALIZABLE = true; - /** Mouse cursor style when over the hotspot that initiates the editor. */ - override CURSOR = 'default'; - protected menuGenerator_?: MenuGenerator; /** A cache of the most recently generated options. */ @@ -204,6 +201,11 @@ export class FieldDropdown extends Field { if (this.borderRect_) { dom.addClass(this.borderRect_, 'blocklyDropdownRect'); } + + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyField'); + dom.addClass(this.fieldGroup_, 'blocklyDropdownField'); + } } /** diff --git a/core/field_input.ts b/core/field_input.ts index dcc2ac29e..5f845a6a2 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -99,9 +99,6 @@ export abstract class FieldInput extends Field< */ override SERIALIZABLE = true; - /** Mouse cursor style when over the hotspot that initiates the editor. */ - override CURSOR = 'text'; - /** * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts @@ -148,6 +145,10 @@ export abstract class FieldInput extends Field< if (this.isFullBlockField()) { this.clickTarget_ = (this.sourceBlock_ as BlockSvg).getSvgRoot(); } + + if (this.fieldGroup_) { + dom.addClass(this.fieldGroup_, 'blocklyInputField'); + } } protected override isFullBlockField(): boolean { From ae2a14014144aca4ee22f8e70a065e8242cf7c36 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 12 Nov 2024 09:52:23 -0800 Subject: [PATCH 078/102] refactor!: Use one map for toolbox contents. (#8654) --- core/toolbox/toolbox.ts | 66 ++++++++----------- .../mocha/test_helpers/toolbox_definitions.js | 10 ++- tests/mocha/toolbox_test.js | 40 ++++++----- 3 files changed, 53 insertions(+), 63 deletions(-) diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index efd5381b4..12465813c 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -70,9 +70,6 @@ export class Toolbox /** Whether the Toolbox is visible. */ protected isVisible_ = false; - /** The list of items in the toolbox. */ - protected contents_: IToolboxItem[] = []; - /** The width of the toolbox. */ protected width_ = 0; @@ -82,7 +79,10 @@ export class Toolbox /** The flyout for the toolbox. */ private flyout_: IFlyout | null = null; - protected contentMap_: {[key: string]: IToolboxItem}; + + /** Map from ID to the corresponding toolbox item. */ + protected contents = new Map(); + toolboxPosition: toolbox.Position; /** The currently selected item. */ @@ -118,9 +118,6 @@ export class Toolbox /** Is RTL vs LTR. */ this.RTL = workspace.options.RTL; - /** A map from toolbox item IDs to toolbox items. */ - this.contentMap_ = Object.create(null); - /** Position of the toolbox and flyout relative to the workspace. */ this.toolboxPosition = workspace.options.toolboxPosition; } @@ -367,14 +364,8 @@ export class Toolbox */ render(toolboxDef: toolbox.ToolboxInfo) { this.toolboxDef_ = toolboxDef; - for (let i = 0; i < this.contents_.length; i++) { - const toolboxItem = this.contents_[i]; - if (toolboxItem) { - toolboxItem.dispose(); - } - } - this.contents_ = []; - this.contentMap_ = Object.create(null); + this.contents.forEach((item) => item.dispose()); + this.contents.clear(); this.renderContents_(toolboxDef['contents']); this.position(); this.handleToolboxItemResize(); @@ -445,8 +436,7 @@ export class Toolbox * @param toolboxItem The item in the toolbox. */ protected addToolboxItem_(toolboxItem: IToolboxItem) { - this.contents_.push(toolboxItem); - this.contentMap_[toolboxItem.getId()] = toolboxItem; + this.contents.set(toolboxItem.getId(), toolboxItem); if (toolboxItem.isCollapsible()) { const collapsibleItem = toolboxItem as ICollapsibleToolboxItem; const childToolboxItems = collapsibleItem.getChildToolboxItems(); @@ -463,7 +453,7 @@ export class Toolbox * @returns The list of items in the toolbox. */ getToolboxItems(): IToolboxItem[] { - return this.contents_; + return [...this.contents.values()]; } /** @@ -618,7 +608,7 @@ export class Toolbox * @returns The toolbox item with the given ID, or null if no item exists. */ getToolboxItemById(id: string): IToolboxItem | null { - return this.contentMap_[id] || null; + return this.contents.get(id) || null; } /** @@ -765,14 +755,13 @@ export class Toolbox * @internal */ refreshTheme() { - for (let i = 0; i < this.contents_.length; i++) { - const child = this.contents_[i]; + this.contents.forEach((child) => { // TODO(#6097): Fix types or add refreshTheme to IToolboxItem. const childAsCategory = child as ToolboxCategory; if (childAsCategory.refreshTheme) { childAsCategory.refreshTheme(); } - } + }); } /** @@ -923,11 +912,9 @@ export class Toolbox * @param position The position of the item to select. */ selectItemByPosition(position: number) { - if (position > -1 && position < this.contents_.length) { - const item = this.contents_[position]; - if (item.isSelectable()) { - this.setSelectedItem(item); - } + const item = this.getToolboxItems()[position]; + if (item) { + this.setSelectedItem(item); } } @@ -1034,11 +1021,12 @@ export class Toolbox return false; } - let nextItemIdx = this.contents_.indexOf(this.selectedItem_) + 1; - if (nextItemIdx > -1 && nextItemIdx < this.contents_.length) { - let nextItem = this.contents_[nextItemIdx]; + const items = [...this.contents.values()]; + let nextItemIdx = items.indexOf(this.selectedItem_) + 1; + if (nextItemIdx > -1 && nextItemIdx < items.length) { + let nextItem = items[nextItemIdx]; while (nextItem && !nextItem.isSelectable()) { - nextItem = this.contents_[++nextItemIdx]; + nextItem = items[++nextItemIdx]; } if (nextItem && nextItem.isSelectable()) { this.setSelectedItem(nextItem); @@ -1058,11 +1046,12 @@ export class Toolbox return false; } - let prevItemIdx = this.contents_.indexOf(this.selectedItem_) - 1; - if (prevItemIdx > -1 && prevItemIdx < this.contents_.length) { - let prevItem = this.contents_[prevItemIdx]; + const items = [...this.contents.values()]; + let prevItemIdx = items.indexOf(this.selectedItem_) - 1; + if (prevItemIdx > -1 && prevItemIdx < items.length) { + let prevItem = items[prevItemIdx]; while (prevItem && !prevItem.isSelectable()) { - prevItem = this.contents_[--prevItemIdx]; + prevItem = items[--prevItemIdx]; } if (prevItem && prevItem.isSelectable()) { this.setSelectedItem(prevItem); @@ -1076,16 +1065,13 @@ export class Toolbox dispose() { this.workspace_.getComponentManager().removeComponent('toolbox'); this.flyout_!.dispose(); - for (let i = 0; i < this.contents_.length; i++) { - const toolboxItem = this.contents_[i]; - toolboxItem.dispose(); - } + this.contents.forEach((item) => item.dispose()); for (let j = 0; j < this.boundEvents_.length; j++) { browserEvents.unbind(this.boundEvents_[j]); } this.boundEvents_ = []; - this.contents_ = []; + this.contents.clear(); if (this.HtmlDiv) { this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv); diff --git a/tests/mocha/test_helpers/toolbox_definitions.js b/tests/mocha/test_helpers/toolbox_definitions.js index 2f767ed60..f05c29620 100644 --- a/tests/mocha/test_helpers/toolbox_definitions.js +++ b/tests/mocha/test_helpers/toolbox_definitions.js @@ -243,9 +243,8 @@ export function getBasicToolbox() { } export function getCollapsibleItem(toolbox) { - const contents = toolbox.contents_; - for (let i = 0; i < contents.length; i++) { - const item = contents[i]; + const contents = toolbox.contents.values(); + for (const item of contents) { if (item.isCollapsible()) { return item; } @@ -253,9 +252,8 @@ export function getCollapsibleItem(toolbox) { } export function getNonCollapsibleItem(toolbox) { - const contents = toolbox.contents_; - for (let i = 0; i < contents.length; i++) { - const item = contents[i]; + const contents = toolbox.contents.values(); + for (const item of contents) { if (!item.isCollapsible()) { return item; } diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index 1cb8df979..c6a1c726d 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -98,7 +98,7 @@ suite('Toolbox', function () { {'kind': 'category', 'contents': []}, ], }); - assert.lengthOf(this.toolbox.contents_, 2); + assert.equal(this.toolbox.contents.size, 2); sinon.assert.called(positionStub); }); // TODO: Uncomment once implemented. @@ -153,7 +153,7 @@ suite('Toolbox', function () { ], }; this.toolbox.render(jsonDef); - assert.lengthOf(this.toolbox.contents_, 1); + assert.equal(this.toolbox.contents.size, 1); }); test('multiple icon classes can be applied', function () { const jsonDef = { @@ -176,7 +176,7 @@ suite('Toolbox', function () { assert.doesNotThrow(() => { this.toolbox.render(jsonDef); }); - assert.lengthOf(this.toolbox.contents_, 1); + assert.equal(this.toolbox.contents.size, 1); }); }); @@ -204,7 +204,7 @@ suite('Toolbox', function () { const evt = { 'target': categoryXml, }; - const item = this.toolbox.contentMap_[categoryXml.getAttribute('id')]; + const item = this.toolbox.contents.get(categoryXml.getAttribute('id')); const setSelectedSpy = sinon.spy(this.toolbox, 'setSelectedItem'); const onClickSpy = sinon.spy(item, 'onClick'); this.toolbox.onClick_(evt); @@ -356,14 +356,16 @@ suite('Toolbox', function () { assert.isFalse(handled); }); test('Next item is selectable -> Should select next item', function () { - const item = this.toolbox.contents_[0]; + const items = [...this.toolbox.contents.values()]; + const item = items[0]; this.toolbox.selectedItem_ = item; const handled = this.toolbox.selectNext_(); assert.isTrue(handled); - assert.equal(this.toolbox.selectedItem_, this.toolbox.contents_[1]); + assert.equal(this.toolbox.selectedItem_, items[1]); }); test('Selected item is last item -> Should not handle event', function () { - const item = this.toolbox.contents_[this.toolbox.contents_.length - 1]; + const items = [...this.toolbox.contents.values()]; + const item = items.at(-1); this.toolbox.selectedItem_ = item; const handled = this.toolbox.selectNext_(); assert.isFalse(handled); @@ -387,15 +389,16 @@ suite('Toolbox', function () { assert.isFalse(handled); }); test('Selected item is first item -> Should not handle event', function () { - const item = this.toolbox.contents_[0]; + const item = [...this.toolbox.contents.values()][0]; this.toolbox.selectedItem_ = item; const handled = this.toolbox.selectPrevious_(); assert.isFalse(handled); assert.equal(this.toolbox.selectedItem_, item); }); test('Previous item is selectable -> Should select previous item', function () { - const item = this.toolbox.contents_[1]; - const prevItem = this.toolbox.contents_[0]; + const items = [...this.toolbox.contents.values()]; + const item = items[1]; + const prevItem = items[0]; this.toolbox.selectedItem_ = item; const handled = this.toolbox.selectPrevious_(); assert.isTrue(handled); @@ -404,9 +407,10 @@ suite('Toolbox', function () { test('Previous item is collapsed -> Should skip over children of the previous item', function () { const childItem = getChildItem(this.toolbox); const parentItem = childItem.getParent(); - const parentIdx = this.toolbox.contents_.indexOf(parentItem); + const items = [...this.toolbox.contents.values()]; + const parentIdx = items.indexOf(parentItem); // Gets the item after the parent. - const item = this.toolbox.contents_[parentIdx + 1]; + const item = items[parentIdx + 1]; this.toolbox.selectedItem_ = item; const handled = this.toolbox.selectPrevious_(); assert.isTrue(handled); @@ -728,9 +732,10 @@ suite('Toolbox', function () { }); test('Child categories visible if all ancestors expanded', function () { this.toolbox.render(getDeeplyNestedJSON()); - const outerCategory = this.toolbox.contents_[0]; - const middleCategory = this.toolbox.contents_[1]; - const innerCategory = this.toolbox.contents_[2]; + const items = [...this.toolbox.contents.values()]; + const outerCategory = items[0]; + const middleCategory = items[1]; + const innerCategory = items[2]; outerCategory.toggleExpanded(); middleCategory.toggleExpanded(); @@ -743,8 +748,9 @@ suite('Toolbox', function () { }); test('Child categories not visible if any ancestor not expanded', function () { this.toolbox.render(getDeeplyNestedJSON()); - const middleCategory = this.toolbox.contents_[1]; - const innerCategory = this.toolbox.contents_[2]; + const items = [...this.toolbox.contents.values()]; + const middleCategory = items[1]; + const innerCategory = items[2]; // Don't expand the outermost category // Even though the direct parent of inner is expanded, it shouldn't be visible From af5905a3e6571d0e9a6973cc4104ba7972299ff8 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 12 Nov 2024 11:45:20 -0800 Subject: [PATCH 079/102] refactor!: Add setSelectedItem() to IToolbox. (#8650) --- core/interfaces/i_toolbox.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/interfaces/i_toolbox.ts b/core/interfaces/i_toolbox.ts index a236d4442..e45bc6c04 100644 --- a/core/interfaces/i_toolbox.ts +++ b/core/interfaces/i_toolbox.ts @@ -94,7 +94,7 @@ export interface IToolbox extends IRegistrable { setVisible(isVisible: boolean): void; /** - * Selects the toolbox item by it's position in the list of toolbox items. + * Selects the toolbox item by its position in the list of toolbox items. * * @param position The position of the item to select. */ @@ -107,6 +107,14 @@ export interface IToolbox extends IRegistrable { */ getSelectedItem(): IToolboxItem | null; + /** + * Sets the selected item. + * + * @param item The toolbox item to select, or null to remove the current + * selection. + */ + setSelectedItem(item: IToolboxItem | null): void; + /** Disposes of this toolbox. */ dispose(): void; } From 4230956244aa0c61c7d1feedcebeea5294dedaba Mon Sep 17 00:00:00 2001 From: John Nesky Date: Mon, 2 Dec 2024 13:34:05 -0800 Subject: [PATCH 080/102] fix: Create CSS vars for SVG patterns. (#8671) --- core/bubbles/bubble.ts | 6 +--- core/css.ts | 9 ++++++ core/grid.ts | 15 ++++++++++ core/inject.ts | 11 ++++++-- core/renderers/common/constants.ts | 30 +++++++++++++++++++- core/renderers/common/path_object.ts | 11 -------- core/renderers/common/renderer.ts | 25 +++++++++++++++-- core/renderers/geras/renderer.ts | 8 ++++-- core/renderers/zelos/constants.ts | 34 +++++++++++++++++++++-- core/renderers/zelos/path_object.ts | 14 +--------- core/workspace_svg.ts | 41 ++++++++++++++++++---------- 11 files changed, 149 insertions(+), 55 deletions(-) diff --git a/core/bubbles/bubble.ts b/core/bubbles/bubble.ts index 35b9e7dde..cac1c6485 100644 --- a/core/bubbles/bubble.ts +++ b/core/bubbles/bubble.ts @@ -106,11 +106,7 @@ export abstract class Bubble implements IBubble, ISelectable { ); const embossGroup = dom.createSvgElement( Svg.G, - { - 'filter': `url(#${ - this.workspace.getRenderer().getConstants().embossFilterId - })`, - }, + {'class': 'blocklyEmboss'}, this.svgRoot, ); this.tail = dom.createSvgElement( diff --git a/core/css.ts b/core/css.ts index 0c547ca0a..fe5071411 100644 --- a/core/css.ts +++ b/core/css.ts @@ -85,6 +85,10 @@ let content = ` transition: transform .5s; } +.blocklyEmboss { + filter: var(--blocklyEmbossFilter); +} + .blocklyTooltipDiv { background-color: #ffffc7; border: 1px solid #ddc; @@ -138,6 +142,10 @@ let content = ` border-color: inherit; } +.blocklyHighlighted>.blocklyPath { + filter: var(--blocklyEmbossFilter); +} + .blocklyHighlightedConnectionPath { fill: none; stroke: #fc3; @@ -189,6 +197,7 @@ let content = ` } .blocklyDisabled>.blocklyPath { + fill: var(--blocklyDisabledPattern); fill-opacity: .5; stroke-opacity: .5; } diff --git a/core/grid.ts b/core/grid.ts index 1a5de250e..45c1674f9 100644 --- a/core/grid.ts +++ b/core/grid.ts @@ -210,6 +210,9 @@ export class Grid { * @param rnd A random ID to append to the pattern's ID. * @param gridOptions The object containing grid configuration. * @param defs The root SVG element for this workspace's defs. + * @param injectionDiv The div containing the parent workspace and all related + * workspaces and block containers. CSS variables representing SVG patterns + * will be scoped to this container. * @returns The SVG element for the grid pattern. * @internal */ @@ -217,6 +220,7 @@ export class Grid { rnd: string, gridOptions: GridOptions, defs: SVGElement, + injectionDiv?: HTMLElement, ): SVGElement { /* @@ -247,6 +251,17 @@ export class Grid { // Edge 16 doesn't handle empty patterns dom.createSvgElement(Svg.LINE, {}, gridPattern); } + + if (injectionDiv) { + // Add CSS variables scoped to the injection div referencing the created + // patterns so that CSS can apply the patterns to any element in the + // injection div. + injectionDiv.style.setProperty( + '--blocklyGridPattern', + `url(#${gridPattern.id})`, + ); + } + return gridPattern; } } diff --git a/core/inject.ts b/core/inject.ts index 55409b7f3..d04b23ed7 100644 --- a/core/inject.ts +++ b/core/inject.ts @@ -89,7 +89,7 @@ export function inject( * @param options Dictionary of options. * @returns Newly created SVG image. */ -function createDom(container: Element, options: Options): SVGElement { +function createDom(container: HTMLElement, 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. @@ -132,7 +132,12 @@ function createDom(container: Element, options: Options): SVGElement { // https://neil.fraser.name/news/2015/11/01/ const rnd = String(Math.random()).substring(2); - options.gridPattern = Grid.createDom(rnd, options.gridOptions, defs); + options.gridPattern = Grid.createDom( + rnd, + options.gridOptions, + defs, + container, + ); return svg; } @@ -144,7 +149,7 @@ function createDom(container: Element, options: Options): SVGElement { * @returns Newly created main workspace. */ function createMainWorkspace( - injectionDiv: Element, + injectionDiv: HTMLElement, svg: SVGElement, options: Options, ): WorkspaceSvg { diff --git a/core/renderers/common/constants.ts b/core/renderers/common/constants.ts index 01217edb7..c5a7a759c 100644 --- a/core/renderers/common/constants.ts +++ b/core/renderers/common/constants.ts @@ -926,8 +926,18 @@ export class ConstantProvider { * @param svg The root of the workspace's SVG. * @param tagName The name to use for the CSS style tag. * @param selector The CSS selector to use. + * @param injectionDivIfIsParent The div containing the parent workspace and + * all related workspaces and block containers, if this renderer is for the + * parent workspace. CSS variables representing SVG patterns will be scoped + * to this container. Child workspaces should not override the CSS variables + * created by the parent and thus do not need access to the injection div. */ - createDom(svg: SVGElement, tagName: string, selector: string) { + createDom( + svg: SVGElement, + tagName: string, + selector: string, + injectionDivIfIsParent?: HTMLElement, + ) { this.injectCSS_(tagName, selector); /* @@ -1034,6 +1044,24 @@ export class ConstantProvider { this.disabledPattern = disabledPattern; this.createDebugFilter(); + + if (injectionDivIfIsParent) { + // If this renderer is for the parent workspace, add CSS variables scoped + // to the injection div referencing the created patterns so that CSS can + // apply the patterns to any element in the injection div. + injectionDivIfIsParent.style.setProperty( + '--blocklyEmbossFilter', + `url(#${this.embossFilterId})`, + ); + injectionDivIfIsParent.style.setProperty( + '--blocklyDisabledPattern', + `url(#${this.disabledPatternId})`, + ); + injectionDivIfIsParent.style.setProperty( + '--blocklyDebugFilter', + `url(#${this.debugFilterId})`, + ); + } } /** diff --git a/core/renderers/common/path_object.ts b/core/renderers/common/path_object.ts index 12e23b6c4..823ab6785 100644 --- a/core/renderers/common/path_object.ts +++ b/core/renderers/common/path_object.ts @@ -173,13 +173,8 @@ export class PathObject implements IPathObject { updateHighlighted(enable: boolean) { if (enable) { - this.svgPath.setAttribute( - 'filter', - 'url(#' + this.constants.embossFilterId + ')', - ); this.setClass_('blocklyHighlighted', true); } else { - this.svgPath.setAttribute('filter', 'none'); this.setClass_('blocklyHighlighted', false); } } @@ -206,12 +201,6 @@ export class PathObject implements IPathObject { */ protected updateDisabled_(disabled: boolean) { this.setClass_('blocklyDisabled', disabled); - if (disabled) { - this.svgPath.setAttribute( - 'fill', - 'url(#' + this.constants.disabledPatternId + ')', - ); - } } /** diff --git a/core/renderers/common/renderer.ts b/core/renderers/common/renderer.ts index 255bc81ff..62d392a8b 100644 --- a/core/renderers/common/renderer.ts +++ b/core/renderers/common/renderer.ts @@ -78,13 +78,23 @@ export class Renderer implements IRegistrable { * * @param svg The root of the workspace's SVG. * @param theme The workspace theme object. + * @param injectionDivIfIsParent The div containing the parent workspace and + * all related workspaces and block containers, if this renderer is for the + * parent workspace. CSS variables representing SVG patterns will be scoped + * to this container. Child workspaces should not override the CSS variables + * created by the parent and thus do not need access to the injection div. * @internal */ - createDom(svg: SVGElement, theme: Theme) { + createDom( + svg: SVGElement, + theme: Theme, + injectionDivIfIsParent?: HTMLElement, + ) { this.constants_.createDom( svg, this.name + '-' + theme.name, '.' + this.getClassName() + '.' + theme.getClassName(), + injectionDivIfIsParent, ); } @@ -93,8 +103,17 @@ export class Renderer implements IRegistrable { * * @param svg The root of the workspace's SVG. * @param theme The workspace theme object. + * @param injectionDivIfIsParent The div containing the parent workspace and + * all related workspaces and block containers, if this renderer is for the + * parent workspace. CSS variables representing SVG patterns will be scoped + * to this container. Child workspaces should not override the CSS variables + * created by the parent and thus do not need access to the injection div. */ - refreshDom(svg: SVGElement, theme: Theme) { + refreshDom( + svg: SVGElement, + theme: Theme, + injectionDivIfIsParent?: HTMLElement, + ) { const previousConstants = this.getConstants(); previousConstants.dispose(); this.constants_ = this.makeConstants_(); @@ -105,7 +124,7 @@ export class Renderer implements IRegistrable { this.constants_.randomIdentifier = previousConstants.randomIdentifier; this.constants_.setTheme(theme); this.constants_.init(); - this.createDom(svg, theme); + this.createDom(svg, theme, injectionDivIfIsParent); } /** diff --git a/core/renderers/geras/renderer.ts b/core/renderers/geras/renderer.ts index 06062e9bc..635391c81 100644 --- a/core/renderers/geras/renderer.ts +++ b/core/renderers/geras/renderer.ts @@ -50,8 +50,12 @@ export class Renderer extends BaseRenderer { this.highlightConstants.init(); } - override refreshDom(svg: SVGElement, theme: Theme) { - super.refreshDom(svg, theme); + override refreshDom( + svg: SVGElement, + theme: Theme, + injectionDiv: HTMLElement, + ) { + super.refreshDom(svg, theme, injectionDiv); this.getHighlightConstants().init(); } diff --git a/core/renderers/zelos/constants.ts b/core/renderers/zelos/constants.ts index 213d8a259..3677d3477 100644 --- a/core/renderers/zelos/constants.ts +++ b/core/renderers/zelos/constants.ts @@ -675,8 +675,13 @@ export class ConstantProvider extends BaseConstantProvider { return utilsColour.blend('#000', colour, 0.25) || colour; } - override createDom(svg: SVGElement, tagName: string, selector: string) { - super.createDom(svg, tagName, selector); + override createDom( + svg: SVGElement, + tagName: string, + selector: string, + injectionDivIfIsParent?: HTMLElement, + ) { + super.createDom(svg, tagName, selector, injectionDivIfIsParent); /* ... filters go here ... @@ -795,6 +800,20 @@ export class ConstantProvider extends BaseConstantProvider { ); this.replacementGlowFilterId = replacementGlowFilter.id; this.replacementGlowFilter = replacementGlowFilter; + + if (injectionDivIfIsParent) { + // If this renderer is for the parent workspace, add CSS variables scoped + // to the injection div referencing the created patterns so that CSS can + // apply the patterns to any element in the injection div. + injectionDivIfIsParent.style.setProperty( + '--blocklySelectedGlowFilter', + `url(#${this.selectedGlowFilterId})`, + ); + injectionDivIfIsParent.style.setProperty( + '--blocklyReplacementGlowFilter', + `url(#${this.replacementGlowFilterId})`, + ); + } } override getCSS_(selector: string) { @@ -873,7 +892,7 @@ export class ConstantProvider extends BaseConstantProvider { // Disabled outline paths. `${selector} .blocklyDisabled > .blocklyOutlinePath {`, - `fill: url(#blocklyDisabledPattern${this.randomIdentifier})`, + `fill: var(--blocklyDisabledPattern)`, `}`, // Insertion marker. @@ -881,6 +900,15 @@ export class ConstantProvider extends BaseConstantProvider { `fill-opacity: ${this.INSERTION_MARKER_OPACITY};`, `stroke: none;`, `}`, + + `${selector} .blocklySelected>.blocklyPath.blocklyPathSelected {`, + `fill: none;`, + `filter: var(--blocklySelectedGlowFilter);`, + `}`, + + `${selector} .blocklyReplaceable>.blocklyPath {`, + `filter: var(--blocklyReplacementGlowFilter);`, + `}`, ]; } } diff --git a/core/renderers/zelos/path_object.ts b/core/renderers/zelos/path_object.ts index fdc6ab8a6..6cb3a0506 100644 --- a/core/renderers/zelos/path_object.ts +++ b/core/renderers/zelos/path_object.ts @@ -91,11 +91,7 @@ export class PathObject extends BasePathObject { if (enable) { if (!this.svgPathSelected) { this.svgPathSelected = this.svgPath.cloneNode(true) as SVGElement; - this.svgPathSelected.setAttribute('fill', 'none'); - this.svgPathSelected.setAttribute( - 'filter', - 'url(#' + this.constants.selectedGlowFilterId + ')', - ); + this.svgPathSelected.classList.add('blocklyPathSelected'); this.svgRoot.appendChild(this.svgPathSelected); } } else { @@ -108,14 +104,6 @@ export class PathObject extends BasePathObject { override updateReplacementFade(enable: boolean) { this.setClass_('blocklyReplaceable', enable); - if (enable) { - this.svgPath.setAttribute( - 'filter', - 'url(#' + this.constants.replacementGlowFilterId + ')', - ); - } else { - this.svgPath.removeAttribute('filter'); - } } override updateShapeForInputHighlight(conn: Connection, enable: boolean) { diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 5447bdf51..30dcaaeb9 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -225,7 +225,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * The first parent div with 'injectionDiv' in the name, or null if not set. * Access this with getInjectionDiv. */ - private injectionDiv: Element | null = null; + private injectionDiv: HTMLElement | null = null; /** * Last known position of the page scroll. @@ -539,7 +539,12 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { */ refreshTheme() { if (this.svgGroup_) { - this.renderer.refreshDom(this.svgGroup_, this.getTheme()); + const isParentWorkspace = this.options.parentWorkspace === null; + this.renderer.refreshDom( + this.svgGroup_, + this.getTheme(), + isParentWorkspace ? this.getInjectionDiv() : undefined, + ); } // Update all blocks in workspace that have a style name. @@ -636,20 +641,24 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { // Before the SVG canvas, scale the coordinates. scale = this.scale; } + let ancestor: Element = element; do { // Loop through this block and every parent. - const xy = svgMath.getRelativeXY(element); - if (element === this.getCanvas() || element === this.getBubbleCanvas()) { + const xy = svgMath.getRelativeXY(ancestor); + if ( + ancestor === this.getCanvas() || + ancestor === this.getBubbleCanvas() + ) { // After the SVG canvas, don't scale the coordinates. scale = 1; } x += xy.x * scale; y += xy.y * scale; - element = element.parentNode as SVGElement; + ancestor = ancestor.parentNode as Element; } while ( - element && - element !== this.getParentSvg() && - element !== this.getInjectionDiv() + ancestor && + ancestor !== this.getParentSvg() && + ancestor !== this.getInjectionDiv() ); return new Coordinate(x, y); } @@ -687,7 +696,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @returns The first parent div with 'injectionDiv' in the name. * @internal */ - getInjectionDiv(): Element { + getInjectionDiv(): HTMLElement { // NB: it would be better to pass this in at createDom, but is more likely // to break existing uses of Blockly. if (!this.injectionDiv) { @@ -695,7 +704,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { while (element) { const classes = element.getAttribute('class') || ''; if ((' ' + classes + ' ').includes(' injectionDiv ')) { - this.injectionDiv = element; + this.injectionDiv = element as HTMLElement; break; } element = element.parentNode as Element; @@ -739,7 +748,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * 'blocklyMutatorBackground'. * @returns The workspace's SVG group. */ - createDom(opt_backgroundClass?: string, injectionDiv?: Element): Element { + createDom(opt_backgroundClass?: string, injectionDiv?: HTMLElement): Element { if (!this.injectionDiv) { this.injectionDiv = injectionDiv ?? null; } @@ -765,8 +774,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { ); if (opt_backgroundClass === 'blocklyMainBackground' && this.grid) { - this.svgBackground_.style.fill = - 'url(#' + this.grid.getPatternId() + ')'; + this.svgBackground_.style.fill = 'var(--blocklyGridPattern)'; } else { this.themeManager_.subscribe( this.svgBackground_, @@ -823,7 +831,12 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { CursorClass && this.markerManager.setCursor(new CursorClass()); - this.renderer.createDom(this.svgGroup_, this.getTheme()); + const isParentWorkspace = this.options.parentWorkspace === null; + this.renderer.createDom( + this.svgGroup_, + this.getTheme(), + isParentWorkspace ? this.getInjectionDiv() : undefined, + ); return this.svgGroup_; } From 389dd1a1cb8fc8c16c5ce0fdc1b1df0bf84b62fb Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 12:15:19 -0800 Subject: [PATCH 081/102] chore: Post-merge fixits. --- core/block.ts | 8 +++--- core/block_flyout_inflater.ts | 28 +++++++++---------- core/blockly.ts | 8 ------ core/button_flyout_inflater.ts | 12 ++++---- core/events/events_var_type_change.ts | 10 +++---- core/events/type.ts | 2 ++ core/field_textinput.ts | 2 +- core/field_variable.ts | 6 ++-- core/flyout_base.ts | 4 +-- core/icons/comment_icon.ts | 1 - core/interfaces/i_comment_icon.ts | 2 +- core/interfaces/i_flyout_inflater.ts | 6 ++-- .../i_variable_backed_parameter_model.ts | 2 +- core/label_flyout_inflater.ts | 12 ++++---- core/names.ts | 2 +- core/renderers/common/renderer.ts | 1 - core/renderers/zelos/renderer.ts | 1 - core/separator_flyout_inflater.ts | 12 ++++---- core/serialization/blocks.ts | 1 - core/serialization/variables.ts | 2 +- core/variable_model.ts | 3 +- core/variables.ts | 2 +- core/xml.ts | 8 +++--- 23 files changed, 63 insertions(+), 72 deletions(-) diff --git a/core/block.ts b/core/block.ts index c3dc037c5..9c68bc4cd 100644 --- a/core/block.ts +++ b/core/block.ts @@ -43,6 +43,10 @@ import {ValueInput} from './inputs/value_input.js'; import type {IASTNodeLocation} from './interfaces/i_ast_node_location.js'; import {isCommentIcon} from './interfaces/i_comment_icon.js'; import {type IIcon} from './interfaces/i_icon.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import * as registry from './registry.js'; import * as Tooltip from './tooltip.js'; import * as arrayUtils from './utils/array.js'; @@ -51,10 +55,6 @@ import * as deprecation from './utils/deprecation.js'; import * as idGenerator from './utils/idgenerator.js'; import * as parsing from './utils/parsing.js'; import {Size} from './utils/size.js'; -import type { - IVariableModel, - IVariableState, -} from './interfaces/i_variable_model.js'; import type {Workspace} from './workspace.js'; /** diff --git a/core/block_flyout_inflater.ts b/core/block_flyout_inflater.ts index b22d2a821..b888e5f3a 100644 --- a/core/block_flyout_inflater.ts +++ b/core/block_flyout_inflater.ts @@ -4,21 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {IFlyout} from './interfaces/i_flyout.js'; -import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; import {BlockSvg} from './block_svg.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; -import * as utilsXml from './utils/xml.js'; -import * as eventUtils from './events/utils.js'; -import * as Xml from './xml.js'; -import * as blocks from './serialization/blocks.js'; +import * as browserEvents from './browser_events.js'; import * as common from './common.js'; -import * as registry from './registry.js'; import {MANUALLY_DISABLED} from './constants.js'; import type {Abstract as AbstractEvent} from './events/events_abstract.js'; +import {EventType} from './events/type.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {IFlyout} from './interfaces/i_flyout.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; +import * as registry from './registry.js'; +import * as blocks from './serialization/blocks.js'; import type {BlockInfo} from './utils/toolbox.js'; -import * as browserEvents from './browser_events.js'; +import * as utilsXml from './utils/xml.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; +import * as Xml from './xml.js'; /** * The language-neutral ID for when the reason why a block is disabled is @@ -51,7 +51,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the block on. * @returns A newly created block. */ - load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { this.setFlyoutWorkspace(flyoutWorkspace); this.flyout = flyoutWorkspace.targetWorkspace?.getFlyout() ?? undefined; const block = this.createBlock(state as BlockInfo, flyoutWorkspace); @@ -114,7 +114,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this block. */ - gapForElement(state: Object, defaultGap: number): number { + gapForElement(state: object, defaultGap: number): number { const blockState = state as BlockInfo; let gap; if (blockState['gap']) { @@ -245,8 +245,8 @@ export class BlockFlyoutInflater implements IFlyoutInflater { !this.flyoutWorkspace || (event && !( - event.type === eventUtils.BLOCK_CREATE || - event.type === eventUtils.BLOCK_DELETE + event.type === EventType.BLOCK_CREATE || + event.type === EventType.BLOCK_DELETE )) ) return; diff --git a/core/blockly.ts b/core/blockly.ts index 5d0a9ae15..d0543abbe 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -483,7 +483,6 @@ export { BlockFlyoutInflater, ButtonFlyoutInflater, CodeGenerator, - CodeGenerator, Field, FieldCheckbox, FieldCheckboxConfig, @@ -495,18 +494,11 @@ export { FieldDropdownFromJsonConfig, FieldDropdownValidator, FieldImage, - FieldImage, - FieldImageConfig, FieldImageConfig, FieldImageFromJsonConfig, - FieldImageFromJsonConfig, - FieldLabel, FieldLabel, FieldLabelConfig, - FieldLabelConfig, FieldLabelFromJsonConfig, - FieldLabelFromJsonConfig, - FieldLabelSerializable, FieldLabelSerializable, FieldNumber, FieldNumberConfig, diff --git a/core/button_flyout_inflater.ts b/core/button_flyout_inflater.ts index 703dc6069..fc788ea5b 100644 --- a/core/button_flyout_inflater.ts +++ b/core/button_flyout_inflater.ts @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; import {FlyoutButton} from './flyout_button.js'; -import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; +import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class responsible for creating buttons for flyouts. @@ -22,7 +22,7 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the button on. * @returns A newly created FlyoutButton. */ - load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { const button = new FlyoutButton( flyoutWorkspace, flyoutWorkspace.targetWorkspace!, @@ -40,7 +40,7 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this button. */ - gapForElement(state: Object, defaultGap: number): number { + gapForElement(state: object, defaultGap: number): number { return defaultGap; } diff --git a/core/events/events_var_type_change.ts b/core/events/events_var_type_change.ts index ab8686620..c02a7e454 100644 --- a/core/events/events_var_type_change.ts +++ b/core/events/events_var_type_change.ts @@ -10,21 +10,21 @@ * @class */ -import * as registry from '../registry.js'; import type { IVariableModel, IVariableState, } from '../interfaces/i_variable_model.js'; +import * as registry from '../registry.js'; -import {VarBase, VarBaseJson} from './events_var_base.js'; -import * as eventUtils from './utils.js'; import type {Workspace} from '../workspace.js'; +import {VarBase, VarBaseJson} from './events_var_base.js'; +import {EventType} from './type.js'; /** * Notifies listeners that a variable's type has changed. */ export class VarTypeChange extends VarBase { - override type = eventUtils.VAR_TYPE_CHANGE; + override type = EventType.VAR_TYPE_CHANGE; /** * @param variable The variable whose type changed. Undefined for a blank event. @@ -117,6 +117,6 @@ export interface VarTypeChangeJson extends VarBaseJson { registry.register( registry.Type.EVENT, - eventUtils.VAR_TYPE_CHANGE, + EventType.VAR_TYPE_CHANGE, VarTypeChange, ); diff --git a/core/events/type.ts b/core/events/type.ts index db9ad6c96..0928b8ff0 100644 --- a/core/events/type.ts +++ b/core/events/type.ts @@ -28,6 +28,8 @@ export enum EventType { VAR_DELETE = 'var_delete', /** Type of event that renames a variable. */ VAR_RENAME = 'var_rename', + /** Type of event that changes the type of a variable. */ + VAR_TYPE_CHANGE = 'var_type_change', /** * Type of generic event that records a UI change. * diff --git a/core/field_textinput.ts b/core/field_textinput.ts index 5b754624a..2b896ad47 100644 --- a/core/field_textinput.ts +++ b/core/field_textinput.ts @@ -21,8 +21,8 @@ import { FieldInputValidator, } from './field_input.js'; import * as fieldRegistry from './field_registry.js'; -import * as parsing from './utils/parsing.js'; import * as dom from './utils/dom.js'; +import * as parsing from './utils/parsing.js'; /** * Class for an editable text field. diff --git a/core/field_variable.ts b/core/field_variable.ts index 0c890f4d7..ad9037e96 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -22,17 +22,17 @@ import { MenuGenerator, MenuOption, } from './field_dropdown.js'; -import * as dom from './utils/dom.js'; import * as fieldRegistry from './field_registry.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import * as internalConstants from './internal_constants.js'; import type {Menu} from './menu.js'; import type {MenuItem} from './menuitem.js'; -import {WorkspaceSvg} from './workspace_svg.js'; import {Msg} from './msg.js'; +import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; import {Size} from './utils/size.js'; -import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; +import {WorkspaceSvg} from './workspace_svg.js'; import * as Xml from './xml.js'; /** diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 5b41a8004..54248edfd 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -642,8 +642,8 @@ export abstract class Flyout // user typing long strings into fields on the blocks in the flyout. this.reflowWrapper = (event) => { if ( - event.type === eventUtils.BLOCK_CHANGE || - event.type === eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE + event.type === EventType.BLOCK_CHANGE || + event.type === EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE ) { this.reflow(); } diff --git a/core/icons/comment_icon.ts b/core/icons/comment_icon.ts index f252c4f59..78bf601f7 100644 --- a/core/icons/comment_icon.ts +++ b/core/icons/comment_icon.ts @@ -199,7 +199,6 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable { setBubbleLocation(location: Coordinate) { this.bubbleLocation = location; this.textInputBubble?.moveDuringDrag(location); - this.textBubble?.moveDuringDrag(location); } /** diff --git a/core/interfaces/i_comment_icon.ts b/core/interfaces/i_comment_icon.ts index 52e550290..05f86f40f 100644 --- a/core/interfaces/i_comment_icon.ts +++ b/core/interfaces/i_comment_icon.ts @@ -6,8 +6,8 @@ import {CommentState} from '../icons/comment_icon.js'; import {IconType} from '../icons/icon_types.js'; -import {Size} from '../utils/size.js'; import {Coordinate} from '../utils/coordinate.js'; +import {Size} from '../utils/size.js'; import {IHasBubble, hasBubble} from './i_has_bubble.js'; import {IIcon, isIcon} from './i_icon.js'; import {ISerializable, isSerializable} from './i_serializable.js'; diff --git a/core/interfaces/i_flyout_inflater.ts b/core/interfaces/i_flyout_inflater.ts index f4a3b6ee9..31f4c23fc 100644 --- a/core/interfaces/i_flyout_inflater.ts +++ b/core/interfaces/i_flyout_inflater.ts @@ -1,5 +1,5 @@ -import type {IBoundedElement} from './i_bounded_element.js'; import type {WorkspaceSvg} from '../workspace_svg.js'; +import type {IBoundedElement} from './i_bounded_element.js'; export interface IFlyoutInflater { /** @@ -16,7 +16,7 @@ export interface IFlyoutInflater { * element, however. * @returns The newly inflated flyout element. */ - load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement; + load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement; /** * Returns the amount of spacing that should follow the element corresponding @@ -26,7 +26,7 @@ export interface IFlyoutInflater { * @param defaultGap The default gap for elements in this flyout. * @returns The gap that should follow the given element. */ - gapForElement(state: Object, defaultGap: number): number; + gapForElement(state: object, defaultGap: number): number; /** * Disposes of the given element. diff --git a/core/interfaces/i_variable_backed_parameter_model.ts b/core/interfaces/i_variable_backed_parameter_model.ts index 4fda2df46..444deb601 100644 --- a/core/interfaces/i_variable_backed_parameter_model.ts +++ b/core/interfaces/i_variable_backed_parameter_model.ts @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {IVariableModel, IVariableState} from './i_variable_model.js'; import {IParameterModel} from './i_parameter_model.js'; +import type {IVariableModel, IVariableState} from './i_variable_model.js'; /** Interface for a parameter model that holds a variable model. */ export interface IVariableBackedParameterModel extends IParameterModel { diff --git a/core/label_flyout_inflater.ts b/core/label_flyout_inflater.ts index 67b02857a..ad304a9a6 100644 --- a/core/label_flyout_inflater.ts +++ b/core/label_flyout_inflater.ts @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; import {FlyoutButton} from './flyout_button.js'; -import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; +import {ButtonOrLabelInfo} from './utils/toolbox.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class responsible for creating labels for flyouts. @@ -22,7 +22,7 @@ export class LabelFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the label on. * @returns A FlyoutButton configured as a label. */ - load(state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { const label = new FlyoutButton( flyoutWorkspace, flyoutWorkspace.targetWorkspace!, @@ -40,7 +40,7 @@ export class LabelFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this label. */ - gapForElement(state: Object, defaultGap: number): number { + gapForElement(state: object, defaultGap: number): number { return defaultGap; } diff --git a/core/names.ts b/core/names.ts index 9976da224..db7486f71 100644 --- a/core/names.ts +++ b/core/names.ts @@ -11,12 +11,12 @@ */ // Former goog.module ID: Blockly.Names -import {Msg} from './msg.js'; import type {IVariableMap} from './interfaces/i_variable_map.js'; import type { IVariableModel, IVariableState, } from './interfaces/i_variable_model.js'; +import {Msg} from './msg.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; diff --git a/core/renderers/common/renderer.ts b/core/renderers/common/renderer.ts index f223cffa0..01de1f877 100644 --- a/core/renderers/common/renderer.ts +++ b/core/renderers/common/renderer.ts @@ -13,7 +13,6 @@ import {ConnectionType} from '../../connection_type.js'; import type {IRegistrable} from '../../interfaces/i_registrable.js'; import type {Marker} from '../../keyboard_nav/marker.js'; import type {BlockStyle, Theme} from '../../theme.js'; -import * as deprecation from '../../utils/deprecation.js'; import type {WorkspaceSvg} from '../../workspace_svg.js'; import {ConstantProvider} from './constants.js'; import {Drawer} from './drawer.js'; diff --git a/core/renderers/zelos/renderer.ts b/core/renderers/zelos/renderer.ts index fb46921d6..c880ce9f8 100644 --- a/core/renderers/zelos/renderer.ts +++ b/core/renderers/zelos/renderer.ts @@ -9,7 +9,6 @@ import type {BlockSvg} from '../../block_svg.js'; import type {Marker} from '../../keyboard_nav/marker.js'; import type {BlockStyle} from '../../theme.js'; -import * as deprecation from '../../utils/deprecation.js'; import type {WorkspaceSvg} from '../../workspace_svg.js'; import * as blockRendering from '../common/block_rendering.js'; import type {RenderInfo as BaseRenderInfo} from '../common/info.js'; diff --git a/core/separator_flyout_inflater.ts b/core/separator_flyout_inflater.ts index 5ed02aeb9..8c0acf2f5 100644 --- a/core/separator_flyout_inflater.ts +++ b/core/separator_flyout_inflater.ts @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; -import type {SeparatorInfo} from './utils/toolbox.js'; +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; +import type {SeparatorInfo} from './utils/toolbox.js'; +import type {WorkspaceSvg} from './workspace_svg.js'; /** * Class responsible for creating separators for flyouts. @@ -33,7 +33,7 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace the separator belongs to. * @returns A newly created FlyoutSeparator. */ - load(_state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(_state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { const flyoutAxis = flyoutWorkspace.targetWorkspace?.getFlyout() ?.horizontalLayout ? SeparatorAxis.X @@ -48,7 +48,7 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The desired size of the separator. */ - gapForElement(state: Object, defaultGap: number): number { + gapForElement(state: object, defaultGap: number): number { const separatorState = state as SeparatorInfo; const newGap = parseInt(String(separatorState['gap'])); return newGap ?? defaultGap; diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index e729f6826..0c4f06c59 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -36,7 +36,6 @@ import * as priorities from './priorities.js'; import * as serializationRegistry from './registry.js'; // TODO(#5160): Remove this once lint is fixed. -/* eslint-disable no-use-before-define */ /** * Represents the state of a connection. diff --git a/core/serialization/variables.ts b/core/serialization/variables.ts index 31c5eb1de..d9c266fb8 100644 --- a/core/serialization/variables.ts +++ b/core/serialization/variables.ts @@ -8,9 +8,9 @@ import type {ISerializer} from '../interfaces/i_serializer.js'; import type {IVariableState} from '../interfaces/i_variable_model.js'; +import * as registry from '../registry.js'; import type {Workspace} from '../workspace.js'; import * as priorities from './priorities.js'; -import * as registry from '../registry.js'; import * as serializationRegistry from './registry.js'; /** diff --git a/core/variable_model.ts b/core/variable_model.ts index 9c959f4f3..4cd16a9c3 100644 --- a/core/variable_model.ts +++ b/core/variable_model.ts @@ -14,6 +14,7 @@ // Unused import preserved for side-effects. Remove if unneeded. import './events/events_var_create.js'; +import {EventType} from './events/type.js'; import * as eventUtils from './events/utils.js'; import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import * as registry from './registry.js'; @@ -138,7 +139,7 @@ export class VariableModel implements IVariableModel { state['id'], ); workspace.getVariableMap().addVariable(variable); - eventUtils.fire(new (eventUtils.get(eventUtils.VAR_CREATE))(variable)); + eventUtils.fire(new (eventUtils.get(EventType.VAR_CREATE))(variable)); } } diff --git a/core/variables.ts b/core/variables.ts index a7f571fa4..75f0c3cf8 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -11,9 +11,9 @@ import {Blocks} from './blocks.js'; import * as dialog from './dialog.js'; import {isLegacyProcedureDefBlock} from './interfaces/i_legacy_procedure_blocks.js'; import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; +import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import {Msg} from './msg.js'; import * as utilsXml from './utils/xml.js'; -import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; diff --git a/core/xml.ts b/core/xml.ts index dad3116c9..a1aaa8114 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -17,15 +17,15 @@ import * as eventUtils from './events/utils.js'; import type {Field} from './field.js'; import {IconType} from './icons/icon_types.js'; import {inputTypes} from './inputs/input_types.js'; +import type { + IVariableModel, + IVariableState, +} from './interfaces/i_variable_model.js'; import * as renderManagement from './render_management.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; import {Size} from './utils/size.js'; import * as utilsXml from './utils/xml.js'; -import type { - IVariableModel, - IVariableState, -} from './interfaces/i_variable_model.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; import {WorkspaceSvg} from './workspace_svg.js'; From aad5339c01291823d463f36dec1f98e151c2f3bb Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 12:18:08 -0800 Subject: [PATCH 082/102] fix: Fix variable type change test. --- core/events/events.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/events/events.ts b/core/events/events.ts index ab2603938..ae3b9e6b2 100644 --- a/core/events/events.ts +++ b/core/events/events.ts @@ -48,6 +48,7 @@ export {VarBase, VarBaseJson} from './events_var_base.js'; export {VarCreate, VarCreateJson} from './events_var_create.js'; export {VarDelete, VarDeleteJson} from './events_var_delete.js'; export {VarRename, VarRenameJson} from './events_var_rename.js'; +export {VarTypeChange, VarTypeChangeJson} from './events_var_type_change.js'; export {ViewportChange, ViewportChangeJson} from './events_viewport.js'; export {FinishedLoading} from './workspace_events.js'; From d2c2d6b554adb6f72cf70fe6b7a4112944e9040a Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 4 Dec 2024 12:44:26 -0800 Subject: [PATCH 083/102] release: Update version number to 12.0.0-beta.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb43adcf7..b1288c49a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockly", - "version": "12.0.0", + "version": "12.0.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockly", - "version": "12.0.0", + "version": "12.0.0-beta.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 9469fc5d3..8e10e2163 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "12.0.0", + "version": "12.0.0-beta.0", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From 54ebfb7a0e00c870b1a96ef57d1e0e705c28968c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 6 Jan 2025 10:52:02 -0800 Subject: [PATCH 084/102] fix: Fix unsafe cast in Input.setVisible(). (#8695) --- core/inputs/input.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/inputs/input.ts b/core/inputs/input.ts index 0907bf449..f8783aea3 100644 --- a/core/inputs/input.ts +++ b/core/inputs/input.ts @@ -20,7 +20,7 @@ import type {Connection} from '../connection.js'; import type {ConnectionType} from '../connection_type.js'; import type {Field} from '../field.js'; import * as fieldRegistry from '../field_registry.js'; -import type {RenderedConnection} from '../rendered_connection.js'; +import {RenderedConnection} from '../rendered_connection.js'; import {Align} from './align.js'; import {inputTypes} from './input_types.js'; @@ -181,15 +181,14 @@ export class Input { for (let y = 0, field; (field = this.fieldRow[y]); y++) { field.setVisible(visible); } - if (this.connection) { - const renderedConnection = this.connection as RenderedConnection; + if (this.connection && this.connection instanceof RenderedConnection) { // Has a connection. if (visible) { - renderList = renderedConnection.startTrackingAll(); + renderList = this.connection.startTrackingAll(); } else { - renderedConnection.stopTrackingAll(); + this.connection.stopTrackingAll(); } - const child = renderedConnection.targetBlock(); + const child = this.connection.targetBlock(); if (child) { child.getSvgRoot().style.display = visible ? 'block' : 'none'; } From eeef2edf34d488752e0988e17cb72e35d1b3d56e Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 6 Jan 2025 10:53:45 -0800 Subject: [PATCH 085/102] chore!: Fix warnings when generating docs. (#8660) --- api-extractor.json | 5 +++++ core/block.ts | 5 ++--- core/connection.ts | 2 +- core/events/events_var_delete.ts | 2 -- core/events/events_var_rename.ts | 2 -- core/interfaces/i_metrics_manager.ts | 2 +- core/interfaces/i_rendered_element.ts | 5 +---- core/menu.ts | 4 +--- core/metrics_manager.ts | 2 +- core/renderers/common/renderer.ts | 2 +- core/workspace_svg.ts | 1 + 11 files changed, 14 insertions(+), 18 deletions(-) diff --git a/api-extractor.json b/api-extractor.json index 6c599d255..66414503a 100644 --- a/api-extractor.json +++ b/api-extractor.json @@ -352,6 +352,11 @@ // Needs investigation. "ae-forgotten-export": { "logLevel": "none" + }, + + // We don't prefix our internal APIs with underscores. + "ae-internal-missing-underscore": { + "logLevel": "none" } }, diff --git a/core/block.ts b/core/block.ts index 9c68bc4cd..b5eff8311 100644 --- a/core/block.ts +++ b/core/block.ts @@ -1411,7 +1411,7 @@ export class Block implements IASTNodeLocation { return this.disabledReasons.size === 0; } - /** @deprecated v11 - Get whether the block is manually disabled. */ + /** @deprecated v11 - Get or sets whether the block is manually disabled. */ private get disabled(): boolean { deprecation.warn( 'disabled', @@ -1422,7 +1422,6 @@ export class Block implements IASTNodeLocation { return this.hasDisabledReason(constants.MANUALLY_DISABLED); } - /** @deprecated v11 - Set whether the block is manually disabled. */ private set disabled(value: boolean) { deprecation.warn( 'disabled', @@ -2519,7 +2518,7 @@ export class Block implements IASTNodeLocation { * * Intended to on be used in console logs and errors. If you need a string * that uses the user's native language (including block text, field values, - * and child blocks), use [toString()]{@link Block#toString}. + * and child blocks), use {@link (Block:class).toString | toString()}. * * @returns The description. */ diff --git a/core/connection.ts b/core/connection.ts index 9cc2c28a9..039d8822c 100644 --- a/core/connection.ts +++ b/core/connection.ts @@ -485,7 +485,7 @@ export class Connection implements IASTNodeLocationWithBlock { * * Headless configurations (the default) do not have neighboring connection, * and always return an empty list (the default). - * {@link RenderedConnection#neighbours} overrides this behavior with a list + * {@link (RenderedConnection:class).neighbours} overrides this behavior with a list * computed from the rendered positioning. * * @param _maxLimit The maximum radius to another connection. diff --git a/core/events/events_var_delete.ts b/core/events/events_var_delete.ts index 8663eb398..225459c44 100644 --- a/core/events/events_var_delete.ts +++ b/core/events/events_var_delete.ts @@ -18,8 +18,6 @@ import {EventType} from './type.js'; /** * Notifies listeners that a variable model has been deleted. - * - * @class */ export class VarDelete extends VarBase { override type = EventType.VAR_DELETE; diff --git a/core/events/events_var_rename.ts b/core/events/events_var_rename.ts index 26c272c7b..23a0a17cd 100644 --- a/core/events/events_var_rename.ts +++ b/core/events/events_var_rename.ts @@ -18,8 +18,6 @@ import {EventType} from './type.js'; /** * Notifies listeners that a variable model was renamed. - * - * @class */ export class VarRename extends VarBase { override type = EventType.VAR_RENAME; diff --git a/core/interfaces/i_metrics_manager.ts b/core/interfaces/i_metrics_manager.ts index bb4d54da4..6fc0d080c 100644 --- a/core/interfaces/i_metrics_manager.ts +++ b/core/interfaces/i_metrics_manager.ts @@ -63,7 +63,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_rendered_element.ts b/core/interfaces/i_rendered_element.ts index 7e6981ca6..fe9460c7f 100644 --- a/core/interfaces/i_rendered_element.ts +++ b/core/interfaces/i_rendered_element.ts @@ -4,18 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @internal */ export interface IRenderedElement { /** - * @returns The root SVG element of htis rendered element. + * @returns The root SVG element of this rendered element. */ getSvgRoot(): SVGElement; } /** * @returns True if the given object is an IRenderedElement. - * - * @internal */ export function isRenderedElement(obj: any): obj is IRenderedElement { return obj['getSvgRoot'] !== undefined; diff --git a/core/menu.ts b/core/menu.ts index f01c1edfb..ec9aae571 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -389,9 +389,7 @@ export class Menu { // Keyboard events. /** - * Attempts to handle a keyboard event, if the menu item is enabled, by - * calling - * {@link Menu#handleKeyEventInternal_}. + * Attempts to handle a keyboard event. * * @param e Key event to handle. */ diff --git a/core/metrics_manager.ts b/core/metrics_manager.ts index 62a2614b6..a8470462c 100644 --- a/core/metrics_manager.ts +++ b/core/metrics_manager.ts @@ -76,7 +76,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:class).getFlyoutMetrics}. * * @returns The object with the width, height and position of the toolbox. */ diff --git a/core/renderers/common/renderer.ts b/core/renderers/common/renderer.ts index 01de1f877..812ddd976 100644 --- a/core/renderers/common/renderer.ts +++ b/core/renderers/common/renderer.ts @@ -73,7 +73,7 @@ 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. + * {@link blockRendering#ConstantProvider.createDom} method instead. * * @param svg The root of the workspace's SVG. * @param theme The workspace theme object. diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 68f956b4d..60288573c 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -1102,6 +1102,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { /** * @returns The layer manager for this workspace. + * @internal */ getLayerManager(): LayerManager | null { return this.layerManager; From 071814e9de6a5c49e32a50917b48f0a92e2a6910 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 6 Jan 2025 10:55:10 -0800 Subject: [PATCH 086/102] feat: Warn if a variable category is loaded without variable blocks. (#8704) --- core/variables.ts | 5 +++++ core/variables_dynamic.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/core/variables.ts b/core/variables.ts index 75f0c3cf8..5d60b475b 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -92,6 +92,11 @@ export function allDeveloperVariables(workspace: Workspace): string[] { * @returns Array of XML elements. */ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { + if (!Blocks['variables_set'] && !Blocks['variables_get']) { + console.warn( + 'There are no variable blocks, but there is a variable category.', + ); + } let xmlList = new Array(); const button = document.createElement('button'); button.setAttribute('text', '%{BKY_NEW_VARIABLE}'); diff --git a/core/variables_dynamic.ts b/core/variables_dynamic.ts index 8dc691d3a..6722f8b49 100644 --- a/core/variables_dynamic.ts +++ b/core/variables_dynamic.ts @@ -76,6 +76,11 @@ export const onCreateVariableButtonClick_Colour = colourButtonClickHandler; * @returns Array of XML elements. */ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { + if (!Blocks['variables_set_dynamic'] && !Blocks['variables_get_dynamic']) { + console.warn( + 'There are no dynamic variable blocks, but there is a dynamic variable category.', + ); + } let xmlList = new Array(); let button = document.createElement('button'); button.setAttribute('text', Msg['NEW_STRING_VARIABLE']); From 503cd0073f42193f16bbffbb472564993a1bd1c9 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 6 Jan 2025 11:08:17 -0800 Subject: [PATCH 087/102] refactor: Reenable workspace resizing after reflowing flyouts. (#8683) --- core/flyout_base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 54248edfd..87aba0119 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -634,8 +634,8 @@ export abstract class Flyout } else { this.width_ = 0; } - this.workspace_.setResizesEnabled(true); this.reflow(); + this.workspace_.setResizesEnabled(true); // Listen for block change events, and reflow the flyout in response. This // accommodates e.g. resizing a non-autoclosing flyout in response to the From 956f272da0f4af071e3c9dfe5b5b2cd3bc3f3164 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 6 Jan 2025 11:30:22 -0800 Subject: [PATCH 088/102] feat: Add a generator for all fields on a block. (#8667) * feat: Add a generator for all fields on a block. * chore: Add docstring. --- core/block.ts | 78 ++++++++++++++++++------------------ core/block_svg.ts | 6 +-- core/serialization/blocks.ts | 10 ++--- core/xml.ts | 12 ++---- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/core/block.ts b/core/block.ts index b5eff8311..f5683fcca 100644 --- a/core/block.ts +++ b/core/block.ts @@ -937,10 +937,8 @@ export class Block implements IASTNodeLocation { */ setEditable(editable: boolean) { this.editable = editable; - for (let i = 0, input; (input = this.inputList[i]); i++) { - for (let j = 0, field; (field = input.fieldRow[j]); j++) { - field.updateEditable(); - } + for (const field of this.getFields()) { + field.updateEditable(); } } @@ -1107,16 +1105,27 @@ export class Block implements IASTNodeLocation { ' instead', ); } - for (let i = 0, input; (input = this.inputList[i]); i++) { - for (let j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.name === name) { - return field; - } + for (const field of this.getFields()) { + if (field.name === name) { + return field; } } return null; } + /** + * Returns a generator that provides every field on the block. + * + * @yields A generator that can be used to iterate the fields on the block. + */ + *getFields(): Generator { + for (const input of this.inputList) { + for (const field of input.fieldRow) { + yield field; + } + } + } + /** * Return all variables referenced by this block. * @@ -1124,12 +1133,9 @@ export class Block implements IASTNodeLocation { */ getVars(): string[] { 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()) { - // NOTE: This only applies to `FieldVariable`, a `Field` - vars.push(field.getValue() as string); - } + for (const field of this.getFields()) { + if (field.referencesVariables()) { + vars.push(field.getValue()); } } return vars; @@ -1143,17 +1149,15 @@ export class Block implements IASTNodeLocation { */ getVarModels(): IVariableModel[] { const vars = []; - for (let i = 0, input; (input = this.inputList[i]); i++) { - for (let j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.referencesVariables()) { - const model = this.workspace.getVariableById( - field.getValue() as string, - ); - // Check if the variable actually exists (and isn't just a potential - // variable). - if (model) { - vars.push(model); - } + for (const field of this.getFields()) { + if (field.referencesVariables()) { + const model = this.workspace.getVariableById( + field.getValue() as string, + ); + // Check if the variable actually exists (and isn't just a potential + // variable). + if (model) { + vars.push(model); } } } @@ -1168,14 +1172,12 @@ export class Block implements IASTNodeLocation { * @internal */ updateVarName(variable: IVariableModel) { - for (let i = 0, input; (input = this.inputList[i]); i++) { - for (let j = 0, field; (field = input.fieldRow[j]); j++) { - if ( - field.referencesVariables() && - variable.getId() === field.getValue() - ) { - field.refreshVariableName(); - } + for (const field of this.getFields()) { + if ( + field.referencesVariables() && + variable.getId() === field.getValue() + ) { + field.refreshVariableName(); } } } @@ -1189,11 +1191,9 @@ export class Block implements IASTNodeLocation { * updated name. */ renameVarById(oldId: string, newId: string) { - for (let i = 0, input; (input = this.inputList[i]); i++) { - for (let j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.referencesVariables() && oldId === field.getValue()) { - field.setValue(newId); - } + for (const field of this.getFields()) { + if (field.referencesVariables() && oldId === field.getValue()) { + field.setValue(newId); } } } diff --git a/core/block_svg.ts b/core/block_svg.ts index aabe51f7a..f04da034a 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -911,10 +911,8 @@ export class BlockSvg icons[i].applyColour(); } - for (let x = 0, input; (input = this.inputList[x]); x++) { - for (let y = 0, field; (field = input.fieldRow[y]); y++) { - field.applyColour(); - } + for (const field of this.getFields()) { + field.applyColour(); } } diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index 0c4f06c59..3696ab2f2 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -261,13 +261,9 @@ function saveIcons(block: Block, state: State, doFullSerialization: boolean) { */ function saveFields(block: Block, state: State, doFullSerialization: boolean) { const fields = Object.create(null); - for (let i = 0; i < block.inputList.length; i++) { - const input = block.inputList[i]; - for (let j = 0; j < input.fieldRow.length; j++) { - const field = input.fieldRow[j]; - if (field.isSerializable()) { - fields[field.name!] = field.saveState(doFullSerialization); - } + for (const field of block.getFields()) { + if (field.isSerializable()) { + fields[field.name!] = field.saveState(doFullSerialization); } } if (Object.keys(fields).length) { diff --git a/core/xml.ts b/core/xml.ts index a1aaa8114..f4b5f66dd 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -168,14 +168,10 @@ function fieldToDom(field: Field): Element | null { * @param element The XML element to which the field DOM should be attached. */ function allFieldsToDom(block: Block, element: Element) { - for (let i = 0; i < block.inputList.length; i++) { - const input = block.inputList[i]; - for (let j = 0; j < input.fieldRow.length; j++) { - const field = input.fieldRow[j]; - const fieldDom = fieldToDom(field); - if (fieldDom) { - element.appendChild(fieldDom); - } + for (const field of block.getFields()) { + const fieldDom = fieldToDom(field); + if (fieldDom) { + element.appendChild(fieldDom); } } } From 151d21e50e930b11a08e36a0de2b85542da50cf2 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 7 Jan 2025 14:04:21 -0800 Subject: [PATCH 089/102] refactor: Convert renderer typecheck methods to typeguards. (#8656) * refactor: Convert renderer typecheck methods to typeguards. * chore: Revert unintended change. * chore: Format types.ts. --- core/renderers/common/drawer.ts | 20 +-- core/renderers/common/info.ts | 9 +- core/renderers/geras/drawer.ts | 2 +- core/renderers/geras/info.ts | 25 ++-- core/renderers/measurables/in_row_spacer.ts | 8 ++ core/renderers/measurables/input_row.ts | 8 +- core/renderers/measurables/jagged_edge.ts | 8 ++ core/renderers/measurables/next_connection.ts | 8 ++ .../measurables/previous_connection.ts | 8 ++ core/renderers/measurables/round_corner.ts | 8 ++ core/renderers/measurables/row.ts | 10 +- core/renderers/measurables/square_corner.ts | 8 ++ core/renderers/measurables/statement_input.ts | 8 ++ core/renderers/measurables/top_row.ts | 3 +- core/renderers/measurables/types.ts | 136 +++++++++++------- core/renderers/thrasos/info.ts | 22 ++- core/renderers/zelos/drawer.ts | 10 +- core/renderers/zelos/info.ts | 16 +-- 18 files changed, 189 insertions(+), 128 deletions(-) diff --git a/core/renderers/common/drawer.ts b/core/renderers/common/drawer.ts index 59a856011..09320710c 100644 --- a/core/renderers/common/drawer.ts +++ b/core/renderers/common/drawer.ts @@ -15,7 +15,6 @@ import type {ExternalValueInput} from '../measurables/external_value_input.js'; import type {Field} from '../measurables/field.js'; import type {Icon} from '../measurables/icon.js'; import type {InlineInput} from '../measurables/inline_input.js'; -import type {PreviousConnection} from '../measurables/previous_connection.js'; import type {Row} from '../measurables/row.js'; import {Types} from '../measurables/types.js'; import type {ConstantProvider, Notch, PuzzleTab} from './constants.js'; @@ -116,13 +115,8 @@ export class Drawer { this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft; } else if (Types.isRightRoundedCorner(elem)) { this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight; - } else if ( - Types.isPreviousConnection(elem) && - elem instanceof Connection - ) { - this.outlinePath_ += ( - (elem as PreviousConnection).shape as Notch - ).pathLeft; + } else if (Types.isPreviousConnection(elem)) { + this.outlinePath_ += (elem.shape as Notch).pathLeft; } else if (Types.isHat(elem)) { this.outlinePath_ += this.constants_.START_HAT.path; } else if (Types.isSpacer(elem)) { @@ -217,7 +211,7 @@ export class Drawer { let rightCornerYOffset = 0; let outlinePath = ''; for (let i = elems.length - 1, elem; (elem = elems[i]); i--) { - if (Types.isNextConnection(elem) && elem instanceof Connection) { + if (Types.isNextConnection(elem)) { outlinePath += (elem.shape as Notch).pathRight; } else if (Types.isLeftSquareCorner(elem)) { outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos); @@ -269,9 +263,9 @@ export class Drawer { for (let i = 0, row; (row = this.info_.rows[i]); i++) { for (let j = 0, elem; (elem = row.elements[j]); j++) { if (Types.isInlineInput(elem)) { - this.drawInlineInput_(elem as InlineInput); + this.drawInlineInput_(elem); } else if (Types.isIcon(elem) || Types.isField(elem)) { - this.layoutField_(elem as Field | Icon); + this.layoutField_(elem); } } } @@ -295,13 +289,13 @@ export class Drawer { } if (Types.isIcon(fieldInfo)) { - const icon = (fieldInfo as Icon).icon; + const icon = fieldInfo.icon; icon.setOffsetInBlock(new Coordinate(xPos, yPos)); if (this.info_.isInsertionMarker) { icon.hideForInsertionMarker(); } } else { - const svgGroup = (fieldInfo as Field).field.getSvgRoot()!; + const svgGroup = fieldInfo.field.getSvgRoot()!; svgGroup.setAttribute( 'transform', 'translate(' + xPos + ',' + yPos + ')' + scale, diff --git a/core/renderers/common/info.ts b/core/renderers/common/info.ts index 680fa57f2..f826d17e4 100644 --- a/core/renderers/common/info.ts +++ b/core/renderers/common/info.ts @@ -671,20 +671,17 @@ export class RenderInfo { return row.yPos + elem.height / 2; } if (Types.isBottomRow(row)) { - const bottomRow = row as BottomRow; - const baseline = - bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight; + const baseline = row.yPos + row.height - row.descenderHeight; if (Types.isNextConnection(elem)) { return baseline + elem.height / 2; } return baseline - elem.height / 2; } if (Types.isTopRow(row)) { - const topRow = row as TopRow; if (Types.isHat(elem)) { - return topRow.capline - elem.height / 2; + return row.capline - elem.height / 2; } - return topRow.capline + elem.height / 2; + return row.capline + elem.height / 2; } return row.yPos + row.height / 2; } diff --git a/core/renderers/geras/drawer.ts b/core/renderers/geras/drawer.ts index 542b21ff9..9d0ed829b 100644 --- a/core/renderers/geras/drawer.ts +++ b/core/renderers/geras/drawer.ts @@ -100,7 +100,7 @@ export class Drawer extends BaseDrawer { } override drawInlineInput_(input: InlineInput) { - this.highlighter_.drawInlineInput(input as InlineInput); + this.highlighter_.drawInlineInput(input); super.drawInlineInput_(input); } diff --git a/core/renderers/geras/info.ts b/core/renderers/geras/info.ts index b9cc1c59c..3e1980aa0 100644 --- a/core/renderers/geras/info.ts +++ b/core/renderers/geras/info.ts @@ -14,13 +14,9 @@ import {StatementInput} from '../../inputs/statement_input.js'; import {ValueInput} from '../../inputs/value_input.js'; import {RenderInfo as BaseRenderInfo} from '../common/info.js'; import type {Measurable} from '../measurables/base.js'; -import type {BottomRow} from '../measurables/bottom_row.js'; import {ExternalValueInput} from '../measurables/external_value_input.js'; -import type {Field} from '../measurables/field.js'; import {InRowSpacer} from '../measurables/in_row_spacer.js'; -import type {InputRow} from '../measurables/input_row.js'; import type {Row} from '../measurables/row.js'; -import type {TopRow} from '../measurables/top_row.js'; import {Types} from '../measurables/types.js'; import type {ConstantProvider} from './constants.js'; import {InlineInput} from './measurables/inline_input.js'; @@ -150,7 +146,7 @@ export class RenderInfo extends BaseRenderInfo { override getInRowSpacing_(prev: Measurable | null, next: Measurable | null) { if (!prev) { // Between an editable field and the beginning of the row. - if (next && Types.isField(next) && (next as Field).isEditable) { + if (next && Types.isField(next) && next.isEditable) { return this.constants_.MEDIUM_PADDING; } // Inline input at the beginning of the row. @@ -167,7 +163,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between a non-input and the end of the row or a statement input. if (!Types.isInput(prev) && (!next || Types.isStatementInput(next))) { // Between an editable field and the end of the row. - if (Types.isField(prev) && (prev as Field).isEditable) { + if (Types.isField(prev) && prev.isEditable) { return this.constants_.MEDIUM_PADDING; } // Padding at the end of an icon-only row to make the block shape clearer. @@ -208,7 +204,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between a non-input and an input. if (!Types.isInput(prev) && next && Types.isInput(next)) { // Between an editable field and an input. - if (Types.isField(prev) && (prev as Field).isEditable) { + if (Types.isField(prev) && prev.isEditable) { if (Types.isInlineInput(next)) { return this.constants_.SMALL_PADDING; } else if (Types.isExternalInput(next)) { @@ -233,7 +229,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between an inline input and a field. if (Types.isInlineInput(prev) && next && Types.isField(next)) { // Editable field after inline input. - if ((next as Field).isEditable) { + if (next.isEditable) { return this.constants_.MEDIUM_PADDING; } else { // Noneditable field after inline input. @@ -278,7 +274,7 @@ export class RenderInfo extends BaseRenderInfo { Types.isField(prev) && next && Types.isField(next) && - (prev as Field).isEditable === (next as Field).isEditable + prev.isEditable === next.isEditable ) { return this.constants_.LARGE_PADDING; } @@ -323,20 +319,17 @@ export class RenderInfo extends BaseRenderInfo { return row.yPos + elem.height / 2; } if (Types.isBottomRow(row)) { - const bottomRow = row as BottomRow; - const baseline = - bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight; + const baseline = row.yPos + row.height - row.descenderHeight; if (Types.isNextConnection(elem)) { return baseline + elem.height / 2; } return baseline - elem.height / 2; } if (Types.isTopRow(row)) { - const topRow = row as TopRow; if (Types.isHat(elem)) { - return topRow.capline - elem.height / 2; + return row.capline - elem.height / 2; } - return topRow.capline + elem.height / 2; + return row.capline + elem.height / 2; } let result = row.yPos; @@ -370,7 +363,7 @@ export class RenderInfo extends BaseRenderInfo { rowNextRightEdges.set(row, nextRightEdge); if (Types.isInputRow(row)) { if (row.hasStatement) { - this.alignStatementRow_(row as InputRow); + this.alignStatementRow_(row); } if ( prevInput && diff --git a/core/renderers/measurables/in_row_spacer.ts b/core/renderers/measurables/in_row_spacer.ts index ec64e71a2..d9378620c 100644 --- a/core/renderers/measurables/in_row_spacer.ts +++ b/core/renderers/measurables/in_row_spacer.ts @@ -15,6 +15,14 @@ import {Types} from './types.js'; * row. */ export class InRowSpacer extends Measurable { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private inRowSpacer: undefined; + /** * @param constants The rendering constants provider. * @param width The width of the spacer. diff --git a/core/renderers/measurables/input_row.ts b/core/renderers/measurables/input_row.ts index a9924246f..869e6718f 100644 --- a/core/renderers/measurables/input_row.ts +++ b/core/renderers/measurables/input_row.ts @@ -7,10 +7,7 @@ // Former goog.module ID: Blockly.blockRendering.InputRow import type {ConstantProvider} from '../common/constants.js'; -import {ExternalValueInput} from './external_value_input.js'; -import {InputConnection} from './input_connection.js'; import {Row} from './row.js'; -import {StatementInput} from './statement_input.js'; import {Types} from './types.js'; /** @@ -40,12 +37,11 @@ export class InputRow extends Row { for (let i = 0; i < this.elements.length; i++) { const elem = this.elements[i]; this.width += elem.width; - if (Types.isInput(elem) && elem instanceof InputConnection) { - if (Types.isStatementInput(elem) && elem instanceof StatementInput) { + if (Types.isInput(elem)) { + if (Types.isStatementInput(elem)) { connectedBlockWidths += elem.connectedBlockWidth; } else if ( Types.isExternalInput(elem) && - elem instanceof ExternalValueInput && elem.connectedBlockWidth !== 0 ) { connectedBlockWidths += diff --git a/core/renderers/measurables/jagged_edge.ts b/core/renderers/measurables/jagged_edge.ts index daca25121..982e2b353 100644 --- a/core/renderers/measurables/jagged_edge.ts +++ b/core/renderers/measurables/jagged_edge.ts @@ -15,6 +15,14 @@ import {Types} from './types.js'; * collapsed block takes up during rendering. */ export class JaggedEdge extends Measurable { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private jaggedEdge: undefined; + /** * @param constants The rendering constants provider. */ diff --git a/core/renderers/measurables/next_connection.ts b/core/renderers/measurables/next_connection.ts index ea22001ed..c10a26904 100644 --- a/core/renderers/measurables/next_connection.ts +++ b/core/renderers/measurables/next_connection.ts @@ -16,6 +16,14 @@ import {Types} from './types.js'; * up during rendering. */ export class NextConnection extends Connection { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private nextConnection: undefined; + /** * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this diff --git a/core/renderers/measurables/previous_connection.ts b/core/renderers/measurables/previous_connection.ts index 1314eb6a4..30944766c 100644 --- a/core/renderers/measurables/previous_connection.ts +++ b/core/renderers/measurables/previous_connection.ts @@ -16,6 +16,14 @@ import {Types} from './types.js'; * up during rendering. */ export class PreviousConnection extends Connection { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private previousConnection: undefined; + /** * @param constants The rendering constants provider. * @param connectionModel The connection object on the block that this diff --git a/core/renderers/measurables/round_corner.ts b/core/renderers/measurables/round_corner.ts index 60bbed707..02c90546e 100644 --- a/core/renderers/measurables/round_corner.ts +++ b/core/renderers/measurables/round_corner.ts @@ -15,6 +15,14 @@ import {Types} from './types.js'; * during rendering. */ export class RoundCorner extends Measurable { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private roundCorner: undefined; + /** * @param constants The rendering constants provider. * @param opt_position The position of this corner. diff --git a/core/renderers/measurables/row.ts b/core/renderers/measurables/row.ts index 613ec6ace..bc4707e83 100644 --- a/core/renderers/measurables/row.ts +++ b/core/renderers/measurables/row.ts @@ -127,7 +127,7 @@ export class Row { for (let i = this.elements.length - 1; i >= 0; i--) { const elem = this.elements[i]; if (Types.isInput(elem)) { - return elem as InputConnection; + return elem; } } return null; @@ -166,8 +166,8 @@ export class Row { getFirstSpacer(): InRowSpacer | null { for (let i = 0; i < this.elements.length; i++) { const elem = this.elements[i]; - if (Types.isSpacer(elem)) { - return elem as InRowSpacer; + if (Types.isInRowSpacer(elem)) { + return elem; } } return null; @@ -181,8 +181,8 @@ export class Row { getLastSpacer(): InRowSpacer | null { for (let i = this.elements.length - 1; i >= 0; i--) { const elem = this.elements[i]; - if (Types.isSpacer(elem)) { - return elem as InRowSpacer; + if (Types.isInRowSpacer(elem)) { + return elem; } } return null; diff --git a/core/renderers/measurables/square_corner.ts b/core/renderers/measurables/square_corner.ts index 29749ac05..054e148be 100644 --- a/core/renderers/measurables/square_corner.ts +++ b/core/renderers/measurables/square_corner.ts @@ -15,6 +15,14 @@ import {Types} from './types.js'; * during rendering. */ export class SquareCorner extends Measurable { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private squareCorner: undefined; + /** * @param constants The rendering constants provider. * @param opt_position The position of this corner. diff --git a/core/renderers/measurables/statement_input.ts b/core/renderers/measurables/statement_input.ts index 91fe5b64a..b0b527d36 100644 --- a/core/renderers/measurables/statement_input.ts +++ b/core/renderers/measurables/statement_input.ts @@ -16,6 +16,14 @@ import {Types} from './types.js'; * during rendering */ export class StatementInput extends InputConnection { + // This field exists solely to structurally distinguish this type from other + // Measurable subclasses. Because this class otherwise has the same fields as + // Measurable, and Typescript doesn't support nominal typing, Typescript will + // consider it and other subclasses in the same situation as being of the same + // type, even if typeguards are used, which could result in Typescript typing + // objects of this class as `never`. + private statementInput: undefined; + /** * @param constants The rendering constants provider. * @param input The statement input to measure and store information for. diff --git a/core/renderers/measurables/top_row.ts b/core/renderers/measurables/top_row.ts index b87ce4ad7..f1e779480 100644 --- a/core/renderers/measurables/top_row.ts +++ b/core/renderers/measurables/top_row.ts @@ -8,7 +8,6 @@ import type {BlockSvg} from '../../block_svg.js'; import type {ConstantProvider} from '../common/constants.js'; -import {Hat} from './hat.js'; import type {PreviousConnection} from './previous_connection.js'; import {Row} from './row.js'; import {Types} from './types.js'; @@ -85,7 +84,7 @@ export class TopRow extends Row { const elem = this.elements[i]; width += elem.width; if (!Types.isSpacer(elem)) { - if (Types.isHat(elem) && elem instanceof Hat) { + if (Types.isHat(elem)) { ascenderHeight = Math.max(ascenderHeight, elem.ascenderHeight); } else { height = Math.max(height, elem.height); diff --git a/core/renderers/measurables/types.ts b/core/renderers/measurables/types.ts index a145b1563..99de339f1 100644 --- a/core/renderers/measurables/types.ts +++ b/core/renderers/measurables/types.ts @@ -7,7 +7,24 @@ // Former goog.module ID: Blockly.blockRendering.Types import type {Measurable} from './base.js'; +import type {BottomRow} from './bottom_row.js'; +import type {ExternalValueInput} from './external_value_input.js'; +import type {Field} from './field.js'; +import type {Hat} from './hat.js'; +import type {Icon} from './icon.js'; +import type {InRowSpacer} from './in_row_spacer.js'; +import type {InlineInput} from './inline_input.js'; +import type {InputConnection} from './input_connection.js'; +import type {InputRow} from './input_row.js'; +import type {JaggedEdge} from './jagged_edge.js'; +import type {NextConnection} from './next_connection.js'; +import type {PreviousConnection} from './previous_connection.js'; +import type {RoundCorner} from './round_corner.js'; import type {Row} from './row.js'; +import type {SpacerRow} from './spacer_row.js'; +import type {SquareCorner} from './square_corner.js'; +import type {StatementInput} from './statement_input.js'; +import type {TopRow} from './top_row.js'; /** * Types of rendering elements. @@ -82,8 +99,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a field. */ - isField(elem: Measurable): number { - return elem.type & this.FIELD; + isField(elem: Measurable): elem is Field { + return (elem.type & this.FIELD) >= 1; } /** @@ -92,8 +109,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a hat. */ - isHat(elem: Measurable): number { - return elem.type & this.HAT; + isHat(elem: Measurable): elem is Hat { + return (elem.type & this.HAT) >= 1; } /** @@ -102,8 +119,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about an icon. */ - isIcon(elem: Measurable): number { - return elem.type & this.ICON; + isIcon(elem: Measurable): elem is Icon { + return (elem.type & this.ICON) >= 1; } /** @@ -112,8 +129,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a spacer. */ - isSpacer(elem: Measurable | Row): number { - return elem.type & this.SPACER; + isSpacer(elem: Measurable | Row): elem is SpacerRow | InRowSpacer { + return (elem.type & this.SPACER) >= 1; } /** @@ -122,8 +139,18 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about an in-row spacer. */ - isInRowSpacer(elem: Measurable): number { - return elem.type & this.IN_ROW_SPACER; + isInRowSpacer(elem: Measurable): elem is InRowSpacer { + return (elem.type & this.IN_ROW_SPACER) >= 1; + } + + /** + * Whether a row is a spacer row. + * + * @param row The row to check. + * @returns True if the row is a spacer row. + */ + isSpacerRow(row: Row): row is SpacerRow { + return (row.type & this.BETWEEN_ROW_SPACER) >= 1; } /** @@ -132,8 +159,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about an input. */ - isInput(elem: Measurable): number { - return elem.type & this.INPUT; + isInput(elem: Measurable): elem is InputConnection { + return (elem.type & this.INPUT) >= 1; } /** @@ -142,8 +169,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about an external input. */ - isExternalInput(elem: Measurable): number { - return elem.type & this.EXTERNAL_VALUE_INPUT; + isExternalInput(elem: Measurable): elem is ExternalValueInput { + return (elem.type & this.EXTERNAL_VALUE_INPUT) >= 1; } /** @@ -152,8 +179,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about an inline input. */ - isInlineInput(elem: Measurable): number { - return elem.type & this.INLINE_INPUT; + isInlineInput(elem: Measurable): elem is InlineInput { + return (elem.type & this.INLINE_INPUT) >= 1; } /** @@ -162,8 +189,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a statement input. */ - isStatementInput(elem: Measurable): number { - return elem.type & this.STATEMENT_INPUT; + isStatementInput(elem: Measurable): elem is StatementInput { + return (elem.type & this.STATEMENT_INPUT) >= 1; } /** @@ -172,8 +199,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a previous connection. */ - isPreviousConnection(elem: Measurable): number { - return elem.type & this.PREVIOUS_CONNECTION; + isPreviousConnection(elem: Measurable): elem is PreviousConnection { + return (elem.type & this.PREVIOUS_CONNECTION) >= 1; } /** @@ -182,8 +209,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a next connection. */ - isNextConnection(elem: Measurable): number { - return elem.type & this.NEXT_CONNECTION; + isNextConnection(elem: Measurable): elem is NextConnection { + return (elem.type & this.NEXT_CONNECTION) >= 1; } /** @@ -194,8 +221,17 @@ class TypesContainer { * @returns 1 if the object stores information about a previous or next * connection. */ - isPreviousOrNextConnection(elem: Measurable): number { - return elem.type & (this.PREVIOUS_CONNECTION | this.NEXT_CONNECTION); + isPreviousOrNextConnection( + elem: Measurable, + ): elem is PreviousConnection | NextConnection { + return this.isPreviousConnection(elem) || this.isNextConnection(elem); + } + + isRoundCorner(elem: Measurable): elem is RoundCorner { + return ( + (elem.type & this.LEFT_ROUND_CORNER) >= 1 || + (elem.type & this.RIGHT_ROUND_CORNER) >= 1 + ); } /** @@ -204,8 +240,10 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a left round corner. */ - isLeftRoundedCorner(elem: Measurable): number { - return elem.type & this.LEFT_ROUND_CORNER; + isLeftRoundedCorner(elem: Measurable): boolean { + return ( + this.isRoundCorner(elem) && (elem.type & this.LEFT_ROUND_CORNER) >= 1 + ); } /** @@ -214,8 +252,10 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a right round corner. */ - isRightRoundedCorner(elem: Measurable): number { - return elem.type & this.RIGHT_ROUND_CORNER; + isRightRoundedCorner(elem: Measurable): boolean { + return ( + this.isRoundCorner(elem) && (elem.type & this.RIGHT_ROUND_CORNER) >= 1 + ); } /** @@ -224,8 +264,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a left square corner. */ - isLeftSquareCorner(elem: Measurable): number { - return elem.type & this.LEFT_SQUARE_CORNER; + isLeftSquareCorner(elem: Measurable): boolean { + return (elem.type & this.LEFT_SQUARE_CORNER) >= 1; } /** @@ -234,8 +274,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a right square corner. */ - isRightSquareCorner(elem: Measurable): number { - return elem.type & this.RIGHT_SQUARE_CORNER; + isRightSquareCorner(elem: Measurable): boolean { + return (elem.type & this.RIGHT_SQUARE_CORNER) >= 1; } /** @@ -244,8 +284,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a corner. */ - isCorner(elem: Measurable): number { - return elem.type & this.CORNER; + isCorner(elem: Measurable): elem is SquareCorner | RoundCorner { + return (elem.type & this.CORNER) >= 1; } /** @@ -254,8 +294,8 @@ class TypesContainer { * @param elem The element to check. * @returns 1 if the object stores information about a jagged edge. */ - isJaggedEdge(elem: Measurable): number { - return elem.type & this.JAGGED_EDGE; + isJaggedEdge(elem: Measurable): elem is JaggedEdge { + return (elem.type & this.JAGGED_EDGE) >= 1; } /** @@ -264,8 +304,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about a row. */ - isRow(row: Row): number { - return row.type & this.ROW; + isRow(row: Row): row is Row { + return (row.type & this.ROW) >= 1; } /** @@ -274,8 +314,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about a between-row spacer. */ - isBetweenRowSpacer(row: Row): number { - return row.type & this.BETWEEN_ROW_SPACER; + isBetweenRowSpacer(row: Row): row is SpacerRow { + return (row.type & this.BETWEEN_ROW_SPACER) >= 1; } /** @@ -284,8 +324,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about a top row. */ - isTopRow(row: Row): number { - return row.type & this.TOP_ROW; + isTopRow(row: Row): row is TopRow { + return (row.type & this.TOP_ROW) >= 1; } /** @@ -294,8 +334,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about a bottom row. */ - isBottomRow(row: Row): number { - return row.type & this.BOTTOM_ROW; + isBottomRow(row: Row): row is BottomRow { + return (row.type & this.BOTTOM_ROW) >= 1; } /** @@ -304,8 +344,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about a top or bottom row. */ - isTopOrBottomRow(row: Row): number { - return row.type & (this.TOP_ROW | this.BOTTOM_ROW); + isTopOrBottomRow(row: Row): row is TopRow | BottomRow { + return this.isTopRow(row) || this.isBottomRow(row); } /** @@ -314,8 +354,8 @@ class TypesContainer { * @param row The row to check. * @returns 1 if the object stores information about an input row. */ - isInputRow(row: Row): number { - return row.type & this.INPUT_ROW; + isInputRow(row: Row): row is InputRow { + return (row.type & this.INPUT_ROW) >= 1; } } diff --git a/core/renderers/thrasos/info.ts b/core/renderers/thrasos/info.ts index 23772a9af..3c8c19f94 100644 --- a/core/renderers/thrasos/info.ts +++ b/core/renderers/thrasos/info.ts @@ -9,11 +9,8 @@ import type {BlockSvg} from '../../block_svg.js'; import {RenderInfo as BaseRenderInfo} from '../common/info.js'; import type {Measurable} from '../measurables/base.js'; -import type {BottomRow} from '../measurables/bottom_row.js'; -import type {Field} from '../measurables/field.js'; import {InRowSpacer} from '../measurables/in_row_spacer.js'; import type {Row} from '../measurables/row.js'; -import type {TopRow} from '../measurables/top_row.js'; import {Types} from '../measurables/types.js'; import type {Renderer} from './renderer.js'; @@ -94,7 +91,7 @@ export class RenderInfo extends BaseRenderInfo { override getInRowSpacing_(prev: Measurable | null, next: Measurable | null) { if (!prev) { // Between an editable field and the beginning of the row. - if (next && Types.isField(next) && (next as Field).isEditable) { + if (next && Types.isField(next) && next.isEditable) { return this.constants_.MEDIUM_PADDING; } // Inline input at the beginning of the row. @@ -111,7 +108,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between a non-input and the end of the row. if (!Types.isInput(prev) && !next) { // Between an editable field and the end of the row. - if (Types.isField(prev) && (prev as Field).isEditable) { + if (Types.isField(prev) && prev.isEditable) { return this.constants_.MEDIUM_PADDING; } // Padding at the end of an icon-only row to make the block shape clearer. @@ -151,7 +148,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between a non-input and an input. if (!Types.isInput(prev) && next && Types.isInput(next)) { // Between an editable field and an input. - if (Types.isField(prev) && (prev as Field).isEditable) { + if (Types.isField(prev) && prev.isEditable) { if (Types.isInlineInput(next)) { return this.constants_.SMALL_PADDING; } else if (Types.isExternalInput(next)) { @@ -177,7 +174,7 @@ export class RenderInfo extends BaseRenderInfo { // Spacing between an inline input and a field. if (Types.isInlineInput(prev) && next && Types.isField(next)) { // Editable field after inline input. - if ((next as Field).isEditable) { + if (next.isEditable) { return this.constants_.MEDIUM_PADDING; } else { // Noneditable field after inline input. @@ -205,7 +202,7 @@ export class RenderInfo extends BaseRenderInfo { Types.isField(prev) && next && Types.isField(next) && - (prev as Field).isEditable === (next as Field).isEditable + prev.isEditable === next.isEditable ) { return this.constants_.LARGE_PADDING; } @@ -247,20 +244,17 @@ export class RenderInfo extends BaseRenderInfo { return row.yPos + elem.height / 2; } if (Types.isBottomRow(row)) { - const bottomRow = row as BottomRow; - const baseline = - bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight; + const baseline = row.yPos + row.height - row.descenderHeight; if (Types.isNextConnection(elem)) { return baseline + elem.height / 2; } return baseline - elem.height / 2; } if (Types.isTopRow(row)) { - const topRow = row as TopRow; if (Types.isHat(elem)) { - return topRow.capline - elem.height / 2; + return row.capline - elem.height / 2; } - return topRow.capline + elem.height / 2; + return row.capline + elem.height / 2; } let result = row.yPos; diff --git a/core/renderers/zelos/drawer.ts b/core/renderers/zelos/drawer.ts index e5b91c1e6..5cc52c0cb 100644 --- a/core/renderers/zelos/drawer.ts +++ b/core/renderers/zelos/drawer.ts @@ -15,7 +15,6 @@ import {Connection} from '../measurables/connection.js'; import type {InlineInput} from '../measurables/inline_input.js'; import {OutputConnection} from '../measurables/output_connection.js'; import type {Row} from '../measurables/row.js'; -import type {SpacerRow} from '../measurables/spacer_row.js'; import {Types} from '../measurables/types.js'; import type {InsideCorners} from './constants.js'; import type {RenderInfo} from './info.js'; @@ -96,20 +95,19 @@ export class Drawer extends BaseDrawer { return; } if (Types.isSpacer(row)) { - const spacerRow = row as SpacerRow; - const precedesStatement = spacerRow.precedesStatement; - const followsStatement = spacerRow.followsStatement; + const precedesStatement = row.precedesStatement; + const followsStatement = row.followsStatement; if (precedesStatement || followsStatement) { const insideCorners = this.constants_.INSIDE_CORNERS as InsideCorners; const cornerHeight = insideCorners.rightHeight; const remainingHeight = - spacerRow.height - (precedesStatement ? cornerHeight : 0); + row.height - (precedesStatement ? cornerHeight : 0); const bottomRightPath = followsStatement ? insideCorners.pathBottomRight : ''; const verticalPath = remainingHeight > 0 - ? svgPaths.lineOnAxis('V', spacerRow.yPos + remainingHeight) + ? svgPaths.lineOnAxis('V', row.yPos + remainingHeight) : ''; const topRightPath = precedesStatement ? insideCorners.pathTopRight diff --git a/core/renderers/zelos/info.ts b/core/renderers/zelos/info.ts index dd3702fe5..5c507c33a 100644 --- a/core/renderers/zelos/info.ts +++ b/core/renderers/zelos/info.ts @@ -20,7 +20,6 @@ import {RenderInfo as BaseRenderInfo} from '../common/info.js'; import type {Measurable} from '../measurables/base.js'; import {Field} from '../measurables/field.js'; import {InRowSpacer} from '../measurables/in_row_spacer.js'; -import {InputConnection} from '../measurables/input_connection.js'; import type {Row} from '../measurables/row.js'; import type {SpacerRow} from '../measurables/spacer_row.js'; import {Types} from '../measurables/types.js'; @@ -207,9 +206,8 @@ export class RenderInfo extends BaseRenderInfo { } // Top and bottom rows act as a spacer so we don't need any extra padding. if (Types.isTopRow(prev)) { - const topRow = prev as TopRow; if ( - !topRow.hasPreviousConnection && + !prev.hasPreviousConnection && (!this.outputConnection || this.hasStatementInput) ) { return Math.abs( @@ -219,7 +217,6 @@ export class RenderInfo extends BaseRenderInfo { return this.constants_.NO_PADDING; } if (Types.isBottomRow(next)) { - const bottomRow = next as BottomRow; if (!this.outputConnection) { const topHeight = Math.max( @@ -230,7 +227,7 @@ export class RenderInfo extends BaseRenderInfo { ), ) - this.constants_.CORNER_RADIUS; return topHeight; - } else if (!bottomRow.hasNextConnection && this.hasStatementInput) { + } else if (!next.hasNextConnection && this.hasStatementInput) { return Math.abs( this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS, ); @@ -259,7 +256,7 @@ export class RenderInfo extends BaseRenderInfo { ) { return row.yPos + this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT / 2; } - if (Types.isInlineInput(elem) && elem instanceof InputConnection) { + if (Types.isInlineInput(elem)) { const connectedBlock = elem.connectedBlock; if ( connectedBlock && @@ -308,7 +305,6 @@ export class RenderInfo extends BaseRenderInfo { } if ( Types.isField(elem) && - elem instanceof Field && elem.parentInput === this.rightAlignedDummyInputs.get(row) ) { break; @@ -371,7 +367,6 @@ export class RenderInfo extends BaseRenderInfo { xCursor < minXPos && !( Types.isField(elem) && - elem instanceof Field && (elem.field instanceof FieldLabel || elem.field instanceof FieldImage) ) @@ -525,7 +520,7 @@ export class RenderInfo extends BaseRenderInfo { return 0; } } - if (Types.isInlineInput(elem) && elem instanceof InputConnection) { + if (Types.isInlineInput(elem)) { const connectedBlock = elem.connectedBlock; const innerShape = connectedBlock ? (connectedBlock.pathObject as PathObject).outputShapeType @@ -552,7 +547,7 @@ export class RenderInfo extends BaseRenderInfo { connectionWidth - this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][innerShape] ); - } else if (Types.isField(elem) && elem instanceof Field) { + } else if (Types.isField(elem)) { // Special case for text inputs. if ( outerShape === constants.SHAPES.ROUND && @@ -616,7 +611,6 @@ export class RenderInfo extends BaseRenderInfo { for (let j = 0; j < row.elements.length; j++) { const elem = row.elements[j]; if ( - elem instanceof InputConnection && Types.isInlineInput(elem) && elem.connectedBlock && !elem.connectedBlock.isShadow() && From 4dcffa0914f3a4ce4a5c9ac164381262214497a6 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 8 Jan 2025 09:37:28 -0800 Subject: [PATCH 090/102] fix: Don't create intermediate variables when renaming a procedure argument. (#8723) --- blocks/procedures.ts | 104 ++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 56 deletions(-) diff --git a/blocks/procedures.ts b/blocks/procedures.ts index bac430c22..7284973d9 100644 --- a/blocks/procedures.ts +++ b/blocks/procedures.ts @@ -629,30 +629,49 @@ type ArgumentBlock = Block & ArgumentMixin; interface ArgumentMixin extends ArgumentMixinType {} type ArgumentMixinType = typeof PROCEDURES_MUTATORARGUMENT; -// TODO(#6920): This is kludgy. -type FieldTextInputForArgument = FieldTextInput & { - oldShowEditorFn_(_e?: Event, quietInput?: boolean): void; - createdVariables_: IVariableModel[]; -}; +/** + * Field responsible for editing procedure argument names. + */ +class ProcedureArgumentField extends FieldTextInput { + /** + * Whether or not this field is currently being edited interactively. + */ + editingInteractively = false; + + /** + * The procedure argument variable whose name is being interactively edited. + */ + editingVariable?: IVariableModel; + + /** + * Displays the field editor. + * + * @param e The event that triggered display of the field editor. + */ + protected override showEditor_(e?: Event) { + super.showEditor_(e); + this.editingInteractively = true; + this.editingVariable = undefined; + } + + /** + * Handles cleanup when the field editor is dismissed. + */ + override onFinishEditing_(value: string) { + super.onFinishEditing_(value); + this.editingInteractively = false; + } +} const PROCEDURES_MUTATORARGUMENT = { /** * Mutator block for procedure argument. */ init: function (this: ArgumentBlock) { - const field = fieldRegistry.fromJson({ - type: 'field_input', - text: Procedures.DEFAULT_ARG, - }) as FieldTextInputForArgument; - 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 as AnyDuringMigration).showEditor_; - const newShowEditorFn = function (this: typeof field) { - this.createdVariables_ = []; - this.oldShowEditorFn_(); - }; - (field as AnyDuringMigration).showEditor_ = newShowEditorFn; + const field = new ProcedureArgumentField( + Procedures.DEFAULT_ARG, + this.validator_, + ); this.appendDummyInput() .appendField(Msg['PROCEDURES_MUTATORARG_TITLE']) @@ -662,14 +681,6 @@ const PROCEDURES_MUTATORARGUMENT = { this.setStyle('procedure_blocks'); this.setTooltip(Msg['PROCEDURES_MUTATORARG_TOOLTIP']); this.contextMenu = false; - - // Create the default variable when we drag the block in from the flyout. - // Have to do this after installing the field on the block. - field.onFinishEditing_ = this.deleteIntermediateVars_; - // Create an empty list so onFinishEditing_ has something to look at, even - // though the editor was never opened. - field.createdVariables_ = []; - field.onFinishEditing_('x'); }, /** @@ -683,11 +694,11 @@ const PROCEDURES_MUTATORARGUMENT = { * @returns Valid name, or null if a name was not specified. */ validator_: function ( - this: FieldTextInputForArgument, + this: ProcedureArgumentField, varName: string, ): string | null { const sourceBlock = this.getSourceBlock()!; - const outerWs = sourceBlock!.workspace.getRootWorkspace()!; + const outerWs = sourceBlock.workspace.getRootWorkspace()!; varName = varName.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); if (!varName) { return null; @@ -716,43 +727,24 @@ const PROCEDURES_MUTATORARGUMENT = { return varName; } - let model = outerWs.getVariable(varName, ''); + const model = outerWs.getVariable(varName, ''); if (model && model.getName() !== varName) { // Rename the variable (case change) outerWs.renameVariableById(model.getId(), varName); } if (!model) { - model = outerWs.createVariable(varName, ''); - if (model && this.createdVariables_) { - this.createdVariables_.push(model); + if (this.editingInteractively) { + if (!this.editingVariable) { + this.editingVariable = outerWs.createVariable(varName, ''); + } else { + outerWs.renameVariableById(this.editingVariable.getId(), varName); + } + } else { + outerWs.createVariable(varName, ''); } } return varName; }, - - /** - * Called when focusing away from the text field. - * Deletes all variables that were created as the user typed their intended - * variable name. - * - * @internal - * @param newText The new variable name. - */ - deleteIntermediateVars_: function ( - this: FieldTextInputForArgument, - newText: string, - ) { - const outerWs = this.getSourceBlock()!.workspace.getRootWorkspace(); - if (!outerWs) { - return; - } - for (let i = 0; i < this.createdVariables_.length; i++) { - const model = this.createdVariables_[i]; - if (model.getName() !== newText) { - outerWs.deleteVariableById(model.getId()); - } - } - }, }; blocks['procedures_mutatorarg'] = PROCEDURES_MUTATORARGUMENT; From 80a6d85c263ffc1912041315650a2a2ccd699163 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 8 Jan 2025 11:50:18 -0800 Subject: [PATCH 091/102] refactor!: Use JSON instead of XML for defining dynamic toolbox categories. (#8658) * refactor!: Use JSON instead of XML for defining dynamic toolbox categories. * chore: Fix tests. * chore: Remove unused import. * chore: Update docstrings. * chore: Revert removal of XML-based category functions. * chore: Add deprecation notices. --- core/procedures.ts | 107 ++++++++++++++++++++- core/variables.ts | 160 ++++++++++++++++++++++++++++++-- core/variables_dynamic.ts | 95 +++++++++++++++++-- core/workspace_svg.ts | 12 +-- tests/mocha/contextmenu_test.js | 11 ++- tests/mocha/xml_test.js | 60 ------------ 6 files changed, 362 insertions(+), 83 deletions(-) diff --git a/core/procedures.ts b/core/procedures.ts index a16b0fce4..73f06836c 100644 --- a/core/procedures.ts +++ b/core/procedures.ts @@ -42,6 +42,8 @@ import {IProcedureModel} from './interfaces/i_procedure_model.js'; import {Msg} from './msg.js'; import {Names} from './names.js'; import {ObservableProcedureMap} from './observable_procedure_map.js'; +import * as deprecation from './utils/deprecation.js'; +import type {FlyoutItemInfo} from './utils/toolbox.js'; import * as utilsXml from './utils/xml.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; @@ -238,7 +240,7 @@ export function rename(this: Field, name: string): string { * @param workspace The workspace containing procedures. * @returns Array of XML block elements. */ -export function flyoutCategory(workspace: WorkspaceSvg): Element[] { +function xmlFlyoutCategory(workspace: WorkspaceSvg): Element[] { const xmlList = []; if (Blocks['procedures_defnoreturn']) { // @@ -322,6 +324,109 @@ export function flyoutCategory(workspace: WorkspaceSvg): Element[] { return xmlList; } +/** + * Internal wrapper that returns the contents of the procedure category. + * + * @internal + * @param workspace The workspace to populate procedure blocks for. + */ +export function internalFlyoutCategory( + workspace: WorkspaceSvg, +): FlyoutItemInfo[] { + return flyoutCategory(workspace, false); +} + +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: true, +): Element[]; +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: false, +): FlyoutItemInfo[]; +/** + * Construct the blocks required by the flyout for the procedure category. + * + * @param workspace The workspace containing procedures. + * @param useXml True to return the contents as XML, false to use JSON. + * @returns List of flyout contents as either XML or JSON. + */ +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml = true, +): Element[] | FlyoutItemInfo[] { + if (useXml) { + deprecation.warn( + 'The XML return value of Blockly.Procedures.flyoutCategory()', + 'v12', + 'v13', + 'the same method, but handle a return type of FlyoutItemInfo[] (JSON) instead.', + ); + return xmlFlyoutCategory(workspace); + } + const blocks = []; + if (Blocks['procedures_defnoreturn']) { + blocks.push({ + 'kind': 'block', + 'type': 'procedures_defnoreturn', + 'gap': 16, + 'fields': { + 'NAME': Msg['PROCEDURES_DEFNORETURN_PROCEDURE'], + }, + }); + } + if (Blocks['procedures_defreturn']) { + blocks.push({ + 'kind': 'block', + 'type': 'procedures_defreturn', + 'gap': 16, + 'fields': { + 'NAME': Msg['PROCEDURES_DEFRETURN_PROCEDURE'], + }, + }); + } + if (Blocks['procedures_ifreturn']) { + blocks.push({ + 'kind': 'block', + 'type': 'procedures_ifreturn', + 'gap': 16, + }); + } + if (blocks.length) { + // Add slightly larger gap between system blocks and user calls. + blocks[blocks.length - 1]['gap'] = 24; + } + + /** + * Creates JSON block definitions for each of the given procedures. + * + * @param procedureList A list of procedures, each of which is defined by a + * three-element list of name, parameter list, and return value boolean. + * @param templateName The type of the block to generate. + */ + function populateProcedures( + procedureList: ProcedureTuple[], + templateName: string, + ) { + for (const [name, args] of procedureList) { + blocks.push({ + 'kind': 'block', + 'type': templateName, + 'gap': 16, + 'extraState': { + 'name': name, + 'params': args, + }, + }); + } + } + + const tuple = allProcedures(workspace); + populateProcedures(tuple[0], 'procedures_callnoreturn'); + populateProcedures(tuple[1], 'procedures_callreturn'); + return blocks; +} + /** * Updates the procedure mutator's flyout so that the arg block is not a * duplicate of another arg. diff --git a/core/variables.ts b/core/variables.ts index 5d60b475b..c896efd0f 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -13,6 +13,8 @@ import {isLegacyProcedureDefBlock} from './interfaces/i_legacy_procedure_blocks. import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; import {Msg} from './msg.js'; +import * as deprecation from './utils/deprecation.js'; +import type {BlockInfo, FlyoutItemInfo} from './utils/toolbox.js'; import * as utilsXml from './utils/xml.js'; import type {Workspace} from './workspace.js'; import type {WorkspaceSvg} from './workspace_svg.js'; @@ -84,6 +86,157 @@ export function allDeveloperVariables(workspace: Workspace): string[] { return Array.from(variables.values()); } +/** + * Internal wrapper that returns the contents of the variables category. + * + * @internal + * @param workspace The workspace to populate variable blocks for. + */ +export function internalFlyoutCategory( + workspace: WorkspaceSvg, +): FlyoutItemInfo[] { + return flyoutCategory(workspace, false); +} + +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: true, +): Element[]; +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: false, +): FlyoutItemInfo[]; +/** + * Construct the elements (blocks and button) required by the flyout for the + * variable category. + * + * @param workspace The workspace containing variables. + * @param useXml True to return the contents as XML, false to use JSON. + * @returns List of flyout contents as either XML or JSON. + */ +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml = true, +): Element[] | FlyoutItemInfo[] { + if (!Blocks['variables_set'] && !Blocks['variables_get']) { + console.warn( + 'There are no variable blocks, but there is a variable category.', + ); + } + + if (useXml) { + deprecation.warn( + 'The XML return value of Blockly.Variables.flyoutCategory()', + 'v12', + 'v13', + 'the same method, but handle a return type of FlyoutItemInfo[] (JSON) instead.', + ); + return xmlFlyoutCategory(workspace); + } + + workspace.registerButtonCallback('CREATE_VARIABLE', function (button) { + createVariableButtonHandler(button.getTargetWorkspace()); + }); + + return [ + { + 'kind': 'button', + 'text': '%{BKY_NEW_VARIABLE}', + 'callbackkey': 'CREATE_VARIABLE', + }, + ...jsonFlyoutCategoryBlocks( + workspace, + workspace.getVariablesOfType(''), + true, + ), + ]; +} + +/** + * Returns the JSON definition for a variable field. + * + * @param variable The variable the field should reference. + * @returns JSON for a variable field. + */ +function generateVariableFieldJson(variable: IVariableModel) { + return { + 'VAR': { + 'name': variable.getName(), + 'type': variable.getType(), + }, + }; +} + +/** + * Construct the blocks required by the flyout for the variable category. + * + * @internal + * @param workspace The workspace containing variables. + * @param variables List of variables to create blocks for. + * @param includeChangeBlocks True to include `change x by _` blocks. + * @param getterType The type of the variable getter block to generate. + * @param setterType The type of the variable setter block to generate. + * @returns JSON list of blocks. + */ +export function jsonFlyoutCategoryBlocks( + workspace: Workspace, + variables: IVariableModel[], + includeChangeBlocks: boolean, + getterType = 'variables_get', + setterType = 'variables_set', +): BlockInfo[] { + includeChangeBlocks &&= Blocks['math_change']; + + const blocks = []; + const mostRecentVariable = variables.slice(-1)[0]; + if (mostRecentVariable) { + // Show one setter block, with the name of the most recently created variable. + if (Blocks[setterType]) { + blocks.push({ + kind: 'block', + type: setterType, + gap: includeChangeBlocks ? 8 : 24, + fields: generateVariableFieldJson(mostRecentVariable), + }); + } + + if (includeChangeBlocks) { + blocks.push({ + 'kind': 'block', + 'type': 'math_change', + 'gap': Blocks[getterType] ? 20 : 8, + 'fields': generateVariableFieldJson(mostRecentVariable), + 'inputs': { + 'DELTA': { + 'shadow': { + 'type': 'math_number', + 'fields': { + 'NUM': 1, + }, + }, + }, + }, + }); + } + } + + if (Blocks[getterType]) { + // Show one getter block for each variable, sorted in alphabetical order. + blocks.push( + ...variables.sort(compareByName).map((variable) => { + return { + 'kind': 'block', + 'type': getterType, + 'gap': 8, + 'fields': generateVariableFieldJson(variable), + }; + }), + ); + } + + return blocks; +} + /** * Construct the elements (blocks and button) required by the flyout for the * variable category. @@ -91,12 +244,7 @@ export function allDeveloperVariables(workspace: Workspace): string[] { * @param workspace The workspace containing variables. * @returns Array of XML elements. */ -export function flyoutCategory(workspace: WorkspaceSvg): Element[] { - if (!Blocks['variables_set'] && !Blocks['variables_get']) { - console.warn( - 'There are no variable blocks, but there is a variable category.', - ); - } +function xmlFlyoutCategory(workspace: WorkspaceSvg): Element[] { let xmlList = new Array(); const button = document.createElement('button'); button.setAttribute('text', '%{BKY_NEW_VARIABLE}'); diff --git a/core/variables_dynamic.ts b/core/variables_dynamic.ts index 6722f8b49..4e2682ce8 100644 --- a/core/variables_dynamic.ts +++ b/core/variables_dynamic.ts @@ -9,6 +9,8 @@ import {Blocks} from './blocks.js'; import type {FlyoutButton} from './flyout_button.js'; import {Msg} from './msg.js'; +import * as deprecation from './utils/deprecation.js'; +import type {FlyoutItemInfo} from './utils/toolbox.js'; import * as xml from './utils/xml.js'; import * as Variables from './variables.js'; import type {Workspace} from './workspace.js'; @@ -68,6 +70,92 @@ function colourButtonClickHandler(button: FlyoutButton) { // eslint-disable-next-line camelcase export const onCreateVariableButtonClick_Colour = colourButtonClickHandler; +/** + * Internal wrapper that returns the contents of the dynamic variables category. + * + * @internal + * @param workspace The workspace to populate variable blocks for. + */ +export function internalFlyoutCategory( + workspace: WorkspaceSvg, +): FlyoutItemInfo[] { + return flyoutCategory(workspace, false); +} + +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: true, +): Element[]; +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml: false, +): FlyoutItemInfo[]; +/** + * Construct the elements (blocks and button) required by the flyout for the + * dynamic variables category. + * + * @param useXml True to return the contents as XML, false to use JSON. + * @returns List of flyout contents as either XML or JSON. + */ +export function flyoutCategory( + workspace: WorkspaceSvg, + useXml = true, +): Element[] | FlyoutItemInfo[] { + if (!Blocks['variables_set_dynamic'] && !Blocks['variables_get_dynamic']) { + console.warn( + 'There are no dynamic variable blocks, but there is a dynamic variable category.', + ); + } + + if (useXml) { + deprecation.warn( + 'The XML return value of Blockly.VariablesDynamic.flyoutCategory()', + 'v12', + 'v13', + 'the same method, but handle a return type of FlyoutItemInfo[] (JSON) instead.', + ); + return xmlFlyoutCategory(workspace); + } + + workspace.registerButtonCallback( + 'CREATE_VARIABLE_STRING', + stringButtonClickHandler, + ); + workspace.registerButtonCallback( + 'CREATE_VARIABLE_NUMBER', + numberButtonClickHandler, + ); + workspace.registerButtonCallback( + 'CREATE_VARIABLE_COLOUR', + colourButtonClickHandler, + ); + + return [ + { + 'kind': 'button', + 'text': Msg['NEW_STRING_VARIABLE'], + 'callbackkey': 'CREATE_VARIABLE_STRING', + }, + { + 'kind': 'button', + 'text': Msg['NEW_NUMBER_VARIABLE'], + 'callbackkey': 'CREATE_VARIABLE_NUMBER', + }, + { + 'kind': 'button', + 'text': Msg['NEW_COLOUR_VARIABLE'], + 'callbackkey': 'CREATE_VARIABLE_COLOUR', + }, + ...Variables.jsonFlyoutCategoryBlocks( + workspace, + workspace.getAllVariables(), + false, + 'variables_get_dynamic', + 'variables_set_dynamic', + ), + ]; +} + /** * Construct the elements (blocks and button) required by the flyout for the * variable category. @@ -75,12 +163,7 @@ export const onCreateVariableButtonClick_Colour = colourButtonClickHandler; * @param workspace The workspace containing variables. * @returns Array of XML elements. */ -export function flyoutCategory(workspace: WorkspaceSvg): Element[] { - if (!Blocks['variables_set_dynamic'] && !Blocks['variables_get_dynamic']) { - console.warn( - 'There are no dynamic variable blocks, but there is a dynamic variable category.', - ); - } +function xmlFlyoutCategory(workspace: WorkspaceSvg): Element[] { let xmlList = new Array(); let button = document.createElement('button'); button.setAttribute('text', Msg['NEW_STRING_VARIABLE']); diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 60288573c..e9aac5b9d 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -365,24 +365,24 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { /** Manager in charge of markers and cursors. */ this.markerManager = new MarkerManager(this); - if (Variables && Variables.flyoutCategory) { + if (Variables && Variables.internalFlyoutCategory) { this.registerToolboxCategoryCallback( Variables.CATEGORY_NAME, - Variables.flyoutCategory, + Variables.internalFlyoutCategory, ); } - if (VariablesDynamic && VariablesDynamic.flyoutCategory) { + if (VariablesDynamic && VariablesDynamic.internalFlyoutCategory) { this.registerToolboxCategoryCallback( VariablesDynamic.CATEGORY_NAME, - VariablesDynamic.flyoutCategory, + VariablesDynamic.internalFlyoutCategory, ); } - if (Procedures && Procedures.flyoutCategory) { + if (Procedures && Procedures.internalFlyoutCategory) { this.registerToolboxCategoryCallback( Procedures.CATEGORY_NAME, - Procedures.flyoutCategory, + Procedures.internalFlyoutCategory, ); this.addChangeListener(Procedures.mutatorOpenListener); } diff --git a/tests/mocha/contextmenu_test.js b/tests/mocha/contextmenu_test.js index fe6d4be99..65896112b 100644 --- a/tests/mocha/contextmenu_test.js +++ b/tests/mocha/contextmenu_test.js @@ -6,7 +6,6 @@ import {callbackFactory} from '../../build/src/core/contextmenu.js'; import * as xmlUtils from '../../build/src/core/utils/xml.js'; -import * as Variables from '../../build/src/core/variables.js'; import {assert} from '../../node_modules/chai/chai.js'; import { sharedTestSetup, @@ -32,9 +31,13 @@ suite('Context Menu', function () { }); test('callback with xml state creates block', function () { - const xmlField = Variables.generateVariableFieldDom( - this.forLoopBlock.getField('VAR').getVariable(), - ); + const variable = this.forLoopBlock.getField('VAR').getVariable(); + const xmlField = document.createElement('field'); + xmlField.setAttribute('name', 'VAR'); + xmlField.setAttribute('id', variable.getId()); + xmlField.setAttribute('variabletype', variable.getType()); + xmlField.textContent = variable.getName(); + const xmlBlock = xmlUtils.createElement('block'); xmlBlock.setAttribute('type', 'variables_get'); xmlBlock.appendChild(xmlField); diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index d30716edb..218324197 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -531,28 +531,6 @@ suite('XML', function () { teardown(function () { workspaceTeardown.call(this, this.workspace); }); - suite('Dynamic Category Blocks', function () { - test('Untyped Variables', function () { - this.workspace.createVariable('name1', '', 'id1'); - const blocksArray = Blockly.Variables.flyoutCategoryBlocks( - this.workspace, - ); - for (let i = 0, xml; (xml = blocksArray[i]); i++) { - Blockly.Xml.domToBlock(xml, this.workspace); - } - }); - test('Typed Variables', function () { - this.workspace.createVariable('name1', 'String', 'id1'); - this.workspace.createVariable('name2', 'Number', 'id2'); - this.workspace.createVariable('name3', 'Colour', 'id3'); - const blocksArray = Blockly.VariablesDynamic.flyoutCategoryBlocks( - this.workspace, - ); - for (let i = 0, xml; (xml = blocksArray[i]); i++) { - Blockly.Xml.domToBlock(xml, this.workspace); - } - }); - }); suite('Comments', function () { suite('Headless', function () { test('Text', function () { @@ -910,42 +888,4 @@ suite('XML', function () { }); }); }); - suite('generateVariableFieldDom', function () { - test('Case Sensitive', function () { - const varId = 'testId'; - const type = 'testType'; - const name = 'testName'; - - const mockVariableModel = { - type: type, - name: name, - getId: function () { - return varId; - }, - getName: function () { - return name; - }, - getType: function () { - return type; - }, - }; - - const generatedXml = Blockly.Xml.domToText( - Blockly.Variables.generateVariableFieldDom(mockVariableModel), - ); - const expectedXml = - '' + - name + - ''; - assert.equal(generatedXml, expectedXml); - }); - }); }); From 75efba92e3338d66c786d15523dfd02494a40ebf Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 9 Jan 2025 14:31:51 -0800 Subject: [PATCH 092/102] fix: Fix bug that prevented keyboard navigation in flyouts. (#8687) * fix: Fix bug that prevented keyboard navigation in flyouts. * refactor: Add an `isFocusable()` method to FlyoutItem. --- core/block_flyout_inflater.ts | 30 +++++++++++++---- core/blockly.ts | 3 +- core/button_flyout_inflater.ts | 27 +++++++++++---- core/flyout_base.ts | 49 +++++++++++++--------------- core/flyout_horizontal.ts | 11 ++++--- core/flyout_item.ts | 42 ++++++++++++++++++++++++ core/flyout_vertical.ts | 15 +++++---- core/interfaces/i_flyout.ts | 2 +- core/interfaces/i_flyout_inflater.ts | 18 +++++++--- core/keyboard_nav/ast_node.ts | 27 ++++++++++----- core/label_flyout_inflater.ts | 31 ++++++++++++++---- core/separator_flyout_inflater.ts | 29 ++++++++++++---- 12 files changed, 203 insertions(+), 81 deletions(-) create mode 100644 core/flyout_item.ts diff --git a/core/block_flyout_inflater.ts b/core/block_flyout_inflater.ts index b888e5f3a..0177ddf50 100644 --- a/core/block_flyout_inflater.ts +++ b/core/block_flyout_inflater.ts @@ -10,7 +10,7 @@ import * as common from './common.js'; import {MANUALLY_DISABLED} from './constants.js'; import type {Abstract as AbstractEvent} from './events/events_abstract.js'; import {EventType} from './events/type.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import {FlyoutItem} from './flyout_item.js'; import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; @@ -27,6 +27,8 @@ import * as Xml from './xml.js'; const WORKSPACE_AT_BLOCK_CAPACITY_DISABLED_REASON = 'WORKSPACE_AT_BLOCK_CAPACITY'; +const BLOCK_TYPE = 'block'; + /** * Class responsible for creating blocks for flyouts. */ @@ -51,7 +53,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the block on. * @returns A newly created block. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { this.setFlyoutWorkspace(flyoutWorkspace); this.flyout = flyoutWorkspace.targetWorkspace?.getFlyout() ?? undefined; const block = this.createBlock(state as BlockInfo, flyoutWorkspace); @@ -70,7 +72,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { block.getDescendants(false).forEach((b) => (b.isInFlyout = true)); this.addBlockListeners(block); - return block; + return new FlyoutItem(block, BLOCK_TYPE, true); } /** @@ -114,7 +116,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this block. */ - gapForElement(state: object, defaultGap: number): number { + gapForItem(state: object, defaultGap: number): number { const blockState = state as BlockInfo; let gap; if (blockState['gap']) { @@ -134,9 +136,10 @@ export class BlockFlyoutInflater implements IFlyoutInflater { /** * Disposes of the given block. * - * @param element The flyout block to dispose of. + * @param item The flyout block to dispose of. */ - disposeElement(element: IBoundedElement): void { + disposeItem(item: FlyoutItem): void { + const element = item.getElement(); if (!(element instanceof BlockSvg)) return; this.removeListeners(element.id); element.dispose(false, false); @@ -257,6 +260,19 @@ export class BlockFlyoutInflater implements IFlyoutInflater { } }); } + + /** + * Returns the type of items this inflater is responsible for creating. + * + * @returns An identifier for the type of items this inflater creates. + */ + getType() { + return BLOCK_TYPE; + } } -registry.register(registry.Type.FLYOUT_INFLATER, 'block', BlockFlyoutInflater); +registry.register( + registry.Type.FLYOUT_INFLATER, + BLOCK_TYPE, + BlockFlyoutInflater, +); diff --git a/core/blockly.ts b/core/blockly.ts index d0543abbe..a743ca5a7 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -99,9 +99,10 @@ import { FieldVariableFromJsonConfig, FieldVariableValidator, } from './field_variable.js'; -import {Flyout, FlyoutItem} from './flyout_base.js'; +import {Flyout} from './flyout_base.js'; import {FlyoutButton} from './flyout_button.js'; import {HorizontalFlyout} from './flyout_horizontal.js'; +import {FlyoutItem} from './flyout_item.js'; import {FlyoutMetricsManager} from './flyout_metrics_manager.js'; import {FlyoutSeparator} from './flyout_separator.js'; import {VerticalFlyout} from './flyout_vertical.js'; diff --git a/core/button_flyout_inflater.ts b/core/button_flyout_inflater.ts index fc788ea5b..2a9c3e289 100644 --- a/core/button_flyout_inflater.ts +++ b/core/button_flyout_inflater.ts @@ -5,12 +5,14 @@ */ import {FlyoutButton} from './flyout_button.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import {FlyoutItem} from './flyout_item.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import {ButtonOrLabelInfo} from './utils/toolbox.js'; import type {WorkspaceSvg} from './workspace_svg.js'; +const BUTTON_TYPE = 'button'; + /** * Class responsible for creating buttons for flyouts. */ @@ -22,7 +24,7 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the button on. * @returns A newly created FlyoutButton. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { const button = new FlyoutButton( flyoutWorkspace, flyoutWorkspace.targetWorkspace!, @@ -30,7 +32,8 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { false, ); button.show(); - return button; + + return new FlyoutItem(button, BUTTON_TYPE, true); } /** @@ -40,24 +43,34 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this button. */ - gapForElement(state: object, defaultGap: number): number { + gapForItem(state: object, defaultGap: number): number { return defaultGap; } /** * Disposes of the given button. * - * @param element The flyout button to dispose of. + * @param item The flyout button to dispose of. */ - disposeElement(element: IBoundedElement): void { + disposeItem(item: FlyoutItem): void { + const element = item.getElement(); if (element instanceof FlyoutButton) { element.dispose(); } } + + /** + * Returns the type of items this inflater is responsible for creating. + * + * @returns An identifier for the type of items this inflater creates. + */ + getType() { + return BUTTON_TYPE; + } } registry.register( registry.Type.FLYOUT_INFLATER, - 'button', + BUTTON_TYPE, ButtonFlyoutInflater, ); diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 87aba0119..817076b97 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -18,16 +18,17 @@ import {DeleteArea} from './delete_area.js'; import type {Abstract as AbstractEvent} from './events/events_abstract.js'; import {EventType} from './events/type.js'; import * as eventUtils from './events/utils.js'; +import {FlyoutItem} from './flyout_item.js'; import {FlyoutMetricsManager} from './flyout_metrics_manager.js'; import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; import {IAutoHideable} from './interfaces/i_autohideable.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import type {Options} from './options.js'; import * as registry from './registry.js'; import * as renderManagement from './render_management.js'; import {ScrollbarPair} from './scrollbar_pair.js'; +import {SEPARATOR_TYPE} from './separator_flyout_inflater.js'; import * as blocks from './serialization/blocks.js'; import {Coordinate} from './utils/coordinate.js'; import * as dom from './utils/dom.js'; @@ -677,20 +678,19 @@ export abstract class Flyout const type = info['kind'].toLowerCase(); const inflater = this.getInflaterForType(type); if (inflater) { - const element = inflater.load(info, this.getWorkspace()); - contents.push({ - type, - element, - }); - const gap = inflater.gapForElement(info, defaultGap); + contents.push(inflater.load(info, this.getWorkspace())); + const gap = inflater.gapForItem(info, defaultGap); if (gap) { - contents.push({ - type: 'sep', - element: new FlyoutSeparator( - gap, - this.horizontalLayout ? SeparatorAxis.X : SeparatorAxis.Y, + contents.push( + new FlyoutItem( + new FlyoutSeparator( + gap, + this.horizontalLayout ? SeparatorAxis.X : SeparatorAxis.Y, + ), + SEPARATOR_TYPE, + false, ), - }); + ); } } } @@ -711,9 +711,12 @@ export abstract class Flyout */ protected normalizeSeparators(contents: FlyoutItem[]): FlyoutItem[] { for (let i = contents.length - 1; i > 0; i--) { - const elementType = contents[i].type.toLowerCase(); - const previousElementType = contents[i - 1].type.toLowerCase(); - if (elementType === 'sep' && previousElementType === 'sep') { + const elementType = contents[i].getType().toLowerCase(); + const previousElementType = contents[i - 1].getType().toLowerCase(); + if ( + elementType === SEPARATOR_TYPE && + previousElementType === SEPARATOR_TYPE + ) { // Remove previousElement from the array, shifting the current element // forward as a result. This preserves the behavior where explicit // separator elements override the value of prior implicit (or explicit) @@ -752,9 +755,9 @@ export abstract class Flyout * Delete elements from a previous showing of the flyout. */ private clearOldBlocks() { - this.getContents().forEach((element) => { - const inflater = this.getInflaterForType(element.type); - inflater?.disposeElement(element.element); + this.getContents().forEach((item) => { + const inflater = this.getInflaterForType(item.getType()); + inflater?.disposeItem(item); }); // Clear potential variables from the previous showing. @@ -959,11 +962,3 @@ export abstract class Flyout return null; } } - -/** - * A flyout content item. - */ -export interface FlyoutItem { - type: string; - element: IBoundedElement; -} diff --git a/core/flyout_horizontal.ts b/core/flyout_horizontal.ts index d19320c82..47b7ab06a 100644 --- a/core/flyout_horizontal.ts +++ b/core/flyout_horizontal.ts @@ -13,7 +13,8 @@ import * as browserEvents from './browser_events.js'; import * as dropDownDiv from './dropdowndiv.js'; -import {Flyout, FlyoutItem} from './flyout_base.js'; +import {Flyout} from './flyout_base.js'; +import type {FlyoutItem} from './flyout_item.js'; import type {Options} from './options.js'; import * as registry from './registry.js'; import {Scrollbar} from './scrollbar.js'; @@ -263,10 +264,10 @@ export class HorizontalFlyout extends Flyout { } for (const item of contents) { - const rect = item.element.getBoundingRectangle(); + const rect = item.getElement().getBoundingRectangle(); const moveX = this.RTL ? cursorX + rect.getWidth() : cursorX; - item.element.moveBy(moveX, cursorY); - cursorX += item.element.getBoundingRectangle().getWidth(); + item.getElement().moveBy(moveX, cursorY); + cursorX += item.getElement().getBoundingRectangle().getWidth(); } } @@ -336,7 +337,7 @@ export class HorizontalFlyout extends Flyout { let flyoutHeight = this.getContents().reduce((maxHeightSoFar, item) => { return Math.max( maxHeightSoFar, - item.element.getBoundingRectangle().getHeight(), + item.getElement().getBoundingRectangle().getHeight(), ); }, 0); flyoutHeight += this.MARGIN * 1.5; diff --git a/core/flyout_item.ts b/core/flyout_item.ts new file mode 100644 index 000000000..d501ceedb --- /dev/null +++ b/core/flyout_item.ts @@ -0,0 +1,42 @@ +import type {IBoundedElement} from './interfaces/i_bounded_element.js'; + +/** + * Representation of an item displayed in a flyout. + */ +export class FlyoutItem { + /** + * Creates a new FlyoutItem. + * + * @param element The element that will be displayed in the flyout. + * @param type The type of element. Should correspond to the type of the + * flyout inflater that created this object. + * @param focusable True if the element should be allowed to be focused by + * e.g. keyboard navigation in the flyout. + */ + constructor( + private element: IBoundedElement, + private type: string, + private focusable: boolean, + ) {} + + /** + * Returns the element displayed in the flyout. + */ + getElement() { + return this.element; + } + + /** + * Returns the type of flyout element this item represents. + */ + getType() { + return this.type; + } + + /** + * Returns whether or not the flyout element can receive focus. + */ + isFocusable() { + return this.focusable; + } +} diff --git a/core/flyout_vertical.ts b/core/flyout_vertical.ts index 8e7c1691c..968b7c024 100644 --- a/core/flyout_vertical.ts +++ b/core/flyout_vertical.ts @@ -13,7 +13,8 @@ import * as browserEvents from './browser_events.js'; import * as dropDownDiv from './dropdowndiv.js'; -import {Flyout, FlyoutItem} from './flyout_base.js'; +import {Flyout} from './flyout_base.js'; +import type {FlyoutItem} from './flyout_item.js'; import type {Options} from './options.js'; import * as registry from './registry.js'; import {Scrollbar} from './scrollbar.js'; @@ -229,8 +230,8 @@ export class VerticalFlyout extends Flyout { let cursorY = margin; for (const item of contents) { - item.element.moveBy(cursorX, cursorY); - cursorY += item.element.getBoundingRectangle().getHeight(); + item.getElement().moveBy(cursorX, cursorY); + cursorY += item.getElement().getBoundingRectangle().getHeight(); } } @@ -301,7 +302,7 @@ export class VerticalFlyout extends Flyout { let flyoutWidth = this.getContents().reduce((maxWidthSoFar, item) => { return Math.max( maxWidthSoFar, - item.element.getBoundingRectangle().getWidth(), + item.getElement().getBoundingRectangle().getWidth(), ); }, 0); flyoutWidth += this.MARGIN * 1.5 + this.tabWidth_; @@ -312,13 +313,13 @@ export class VerticalFlyout extends Flyout { if (this.RTL) { // With the flyoutWidth known, right-align the flyout contents. for (const item of this.getContents()) { - const oldX = item.element.getBoundingRectangle().left; + const oldX = item.getElement().getBoundingRectangle().left; const newX = flyoutWidth / this.workspace_.scale - - item.element.getBoundingRectangle().getWidth() - + item.getElement().getBoundingRectangle().getWidth() - this.MARGIN - this.tabWidth_; - item.element.moveBy(newX - oldX, 0); + item.getElement().moveBy(newX - oldX, 0); } } diff --git a/core/interfaces/i_flyout.ts b/core/interfaces/i_flyout.ts index c79be344c..42204775e 100644 --- a/core/interfaces/i_flyout.ts +++ b/core/interfaces/i_flyout.ts @@ -7,7 +7,7 @@ // Former goog.module ID: Blockly.IFlyout import type {BlockSvg} from '../block_svg.js'; -import {FlyoutItem} from '../flyout_base.js'; +import type {FlyoutItem} from '../flyout_item.js'; import type {Coordinate} from '../utils/coordinate.js'; import type {Svg} from '../utils/svg.js'; import type {FlyoutDefinition} from '../utils/toolbox.js'; diff --git a/core/interfaces/i_flyout_inflater.ts b/core/interfaces/i_flyout_inflater.ts index 31f4c23fc..2deab770d 100644 --- a/core/interfaces/i_flyout_inflater.ts +++ b/core/interfaces/i_flyout_inflater.ts @@ -1,5 +1,5 @@ +import type {FlyoutItem} from '../flyout_item.js'; import type {WorkspaceSvg} from '../workspace_svg.js'; -import type {IBoundedElement} from './i_bounded_element.js'; export interface IFlyoutInflater { /** @@ -16,7 +16,7 @@ export interface IFlyoutInflater { * element, however. * @returns The newly inflated flyout element. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement; + load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem; /** * Returns the amount of spacing that should follow the element corresponding @@ -26,7 +26,7 @@ export interface IFlyoutInflater { * @param defaultGap The default gap for elements in this flyout. * @returns The gap that should follow the given element. */ - gapForElement(state: object, defaultGap: number): number; + gapForItem(state: object, defaultGap: number): number; /** * Disposes of the given element. @@ -37,5 +37,15 @@ export interface IFlyoutInflater { * * @param element The flyout element to dispose of. */ - disposeElement(element: IBoundedElement): void; + disposeItem(item: FlyoutItem): void; + + /** + * Returns the type of items that this inflater is responsible for inflating. + * This should be the same as the name under which this inflater registers + * itself, as well as the value returned by `getType()` on the `FlyoutItem` + * objects returned by `load()`. + * + * @returns The type of items this inflater creates. + */ + getType(): string; } diff --git a/core/keyboard_nav/ast_node.ts b/core/keyboard_nav/ast_node.ts index 1b3d72a01..ec46a4d3f 100644 --- a/core/keyboard_nav/ast_node.ts +++ b/core/keyboard_nav/ast_node.ts @@ -17,8 +17,8 @@ import {BlockSvg} from '../block_svg.js'; import type {Connection} from '../connection.js'; import {ConnectionType} from '../connection_type.js'; import type {Field} from '../field.js'; -import {FlyoutItem} from '../flyout_base.js'; import {FlyoutButton} from '../flyout_button.js'; +import type {FlyoutItem} from '../flyout_item.js'; import type {Input} from '../inputs/input.js'; import type {IASTNodeLocation} from '../interfaces/i_ast_node_location.js'; import type {IASTNodeLocationWithBlock} from '../interfaces/i_ast_node_location_with_block.js'; @@ -348,10 +348,11 @@ export class ASTNode { ); if (!nextItem) return null; - if (nextItem.element instanceof FlyoutButton) { - return ASTNode.createButtonNode(nextItem.element); - } else if (nextItem.element instanceof BlockSvg) { - return ASTNode.createStackNode(nextItem.element); + const element = nextItem.getElement(); + if (element instanceof FlyoutButton) { + return ASTNode.createButtonNode(element); + } else if (element instanceof BlockSvg) { + return ASTNode.createStackNode(element); } return null; @@ -373,13 +374,13 @@ export class ASTNode { const currentIndex = flyoutContents.findIndex((item: FlyoutItem) => { if ( currentLocation instanceof BlockSvg && - item.element === currentLocation + item.getElement() === currentLocation ) { return true; } if ( currentLocation instanceof FlyoutButton && - item.element === currentLocation + item.getElement() === currentLocation ) { return true; } @@ -388,7 +389,17 @@ export class ASTNode { if (currentIndex < 0) return null; - const resultIndex = forward ? currentIndex + 1 : currentIndex - 1; + let resultIndex = forward ? currentIndex + 1 : currentIndex - 1; + // The flyout may contain non-focusable elements like spacers or custom + // items. If the next/previous element is one of those, keep looking until a + // focusable element is encountered. + while ( + resultIndex >= 0 && + resultIndex < flyoutContents.length && + !flyoutContents[resultIndex].isFocusable() + ) { + resultIndex += forward ? 1 : -1; + } if (resultIndex === -1 || resultIndex === flyoutContents.length) { return null; } diff --git a/core/label_flyout_inflater.ts b/core/label_flyout_inflater.ts index ad304a9a6..51899ef23 100644 --- a/core/label_flyout_inflater.ts +++ b/core/label_flyout_inflater.ts @@ -5,12 +5,14 @@ */ import {FlyoutButton} from './flyout_button.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; +import {FlyoutItem} from './flyout_item.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import {ButtonOrLabelInfo} from './utils/toolbox.js'; import type {WorkspaceSvg} from './workspace_svg.js'; +const LABEL_TYPE = 'label'; + /** * Class responsible for creating labels for flyouts. */ @@ -22,7 +24,7 @@ export class LabelFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace to create the label on. * @returns A FlyoutButton configured as a label. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { const label = new FlyoutButton( flyoutWorkspace, flyoutWorkspace.targetWorkspace!, @@ -30,7 +32,8 @@ export class LabelFlyoutInflater implements IFlyoutInflater { true, ); label.show(); - return label; + + return new FlyoutItem(label, LABEL_TYPE, true); } /** @@ -40,20 +43,34 @@ export class LabelFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The amount of space that should follow this label. */ - gapForElement(state: object, defaultGap: number): number { + gapForItem(state: object, defaultGap: number): number { return defaultGap; } /** * Disposes of the given label. * - * @param element The flyout label to dispose of. + * @param item The flyout label to dispose of. */ - disposeElement(element: IBoundedElement): void { + disposeItem(item: FlyoutItem): void { + const element = item.getElement(); if (element instanceof FlyoutButton) { element.dispose(); } } + + /** + * Returns the type of items this inflater is responsible for creating. + * + * @returns An identifier for the type of items this inflater creates. + */ + getType() { + return LABEL_TYPE; + } } -registry.register(registry.Type.FLYOUT_INFLATER, 'label', LabelFlyoutInflater); +registry.register( + registry.Type.FLYOUT_INFLATER, + LABEL_TYPE, + LabelFlyoutInflater, +); diff --git a/core/separator_flyout_inflater.ts b/core/separator_flyout_inflater.ts index 8c0acf2f5..0b9aa6026 100644 --- a/core/separator_flyout_inflater.ts +++ b/core/separator_flyout_inflater.ts @@ -4,13 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +import {FlyoutItem} from './flyout_item.js'; import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; -import type {IBoundedElement} from './interfaces/i_bounded_element.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import type {SeparatorInfo} from './utils/toolbox.js'; import type {WorkspaceSvg} from './workspace_svg.js'; +/** + * @internal + */ +export const SEPARATOR_TYPE = 'sep'; + /** * Class responsible for creating separators for flyouts. */ @@ -33,12 +38,13 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { * @param flyoutWorkspace The workspace the separator belongs to. * @returns A newly created FlyoutSeparator. */ - load(_state: object, flyoutWorkspace: WorkspaceSvg): IBoundedElement { + load(_state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { const flyoutAxis = flyoutWorkspace.targetWorkspace?.getFlyout() ?.horizontalLayout ? SeparatorAxis.X : SeparatorAxis.Y; - return new FlyoutSeparator(0, flyoutAxis); + const separator = new FlyoutSeparator(0, flyoutAxis); + return new FlyoutItem(separator, SEPARATOR_TYPE, false); } /** @@ -48,7 +54,7 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { * @param defaultGap The default spacing for flyout items. * @returns The desired size of the separator. */ - gapForElement(state: object, defaultGap: number): number { + gapForItem(state: object, defaultGap: number): number { const separatorState = state as SeparatorInfo; const newGap = parseInt(String(separatorState['gap'])); return newGap ?? defaultGap; @@ -57,13 +63,22 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { /** * Disposes of the given separator. Intentional no-op. * - * @param _element The flyout separator to dispose of. + * @param _item The flyout separator to dispose of. */ - disposeElement(_element: IBoundedElement): void {} + disposeItem(_item: FlyoutItem): void {} + + /** + * Returns the type of items this inflater is responsible for creating. + * + * @returns An identifier for the type of items this inflater creates. + */ + getType() { + return SEPARATOR_TYPE; + } } registry.register( registry.Type.FLYOUT_INFLATER, - 'sep', + SEPARATOR_TYPE, SeparatorFlyoutInflater, ); From c68d6451b736827eb0f0efa425427a488cd576a8 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 10 Jan 2025 10:53:31 -0800 Subject: [PATCH 093/102] release: Update version number to 12.0.0-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 59102d982..bd1267161 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockly", - "version": "12.0.0-beta.0", + "version": "12.0.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockly", - "version": "12.0.0-beta.0", + "version": "12.0.0-beta.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 8e10e2163..936fef256 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "12.0.0-beta.0", + "version": "12.0.0-beta.1", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" From c88ebf1ede7ca188a08ef7a19d4190b41fe1e7f9 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 16 Jan 2025 15:23:55 -0800 Subject: [PATCH 094/102] fix: Don't add padding around zero-width fields. (#8738) --- core/field.ts | 20 -------------------- core/renderers/common/info.ts | 5 +++++ core/renderers/geras/info.ts | 6 ++++++ core/renderers/thrasos/info.ts | 6 ++++++ core/renderers/zelos/info.ts | 6 ++++++ 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/core/field.ts b/core/field.ts index 627cf4ef2..deae29af9 100644 --- a/core/field.ts +++ b/core/field.ts @@ -83,9 +83,6 @@ export abstract class Field */ DEFAULT_VALUE: T | null = null; - /** Non-breaking space. */ - static readonly NBSP = '\u00A0'; - /** * A value used to signal when a field's constructor should *not* set the * field's value or run configure_, and should allow a subclass to do that @@ -905,17 +902,6 @@ export abstract class Field if (this.isDirty_) { this.render_(); this.isDirty_ = false; - } else if (this.visible_ && this.size_.width === 0) { - // If the field is not visible the width will be 0 as well, one of the - // problems with the old system. - this.render_(); - // Don't issue a warning if the field is actually zero width. - if (this.size_.width !== 0) { - console.warn( - 'Deprecated use of setting size_.width to 0 to rerender a' + - ' field. Set field.isDirty_ to true instead.', - ); - } } return this.size_; } @@ -979,16 +965,10 @@ export abstract class Field */ protected getDisplayText_(): string { let text = this.getText(); - if (!text) { - // Prevent the field from disappearing if empty. - return Field.NBSP; - } if (text.length > this.maxDisplayLength) { // Truncate displayed string and add an ellipsis ('...'). text = text.substring(0, this.maxDisplayLength - 2) + '…'; } - // Replace whitespace with non-breaking spaces so the text doesn't collapse. - text = text.replace(/\s/g, Field.NBSP); if (this.sourceBlock_ && this.sourceBlock_.RTL) { // The SVG is LTR, force text to be RTL by adding an RLM. text += '\u200F'; diff --git a/core/renderers/common/info.ts b/core/renderers/common/info.ts index f826d17e4..0e4d3e946 100644 --- a/core/renderers/common/info.ts +++ b/core/renderers/common/info.ts @@ -457,6 +457,11 @@ export class RenderInfo { } } + // Don't add padding after zero-width fields. + if (prev && Types.isField(prev) && prev.width === 0) { + return this.constants_.NO_PADDING; + } + return this.constants_.MEDIUM_PADDING; } diff --git a/core/renderers/geras/info.ts b/core/renderers/geras/info.ts index 3e1980aa0..11f9e764a 100644 --- a/core/renderers/geras/info.ts +++ b/core/renderers/geras/info.ts @@ -164,6 +164,9 @@ export class RenderInfo extends BaseRenderInfo { if (!Types.isInput(prev) && (!next || Types.isStatementInput(next))) { // Between an editable field and the end of the row. if (Types.isField(prev) && prev.isEditable) { + if (prev.width === 0) { + return this.constants_.NO_PADDING; + } return this.constants_.MEDIUM_PADDING; } // Padding at the end of an icon-only row to make the block shape clearer. @@ -276,6 +279,9 @@ export class RenderInfo extends BaseRenderInfo { Types.isField(next) && prev.isEditable === next.isEditable ) { + if (prev.width === 0) { + return this.constants_.NO_PADDING; + } return this.constants_.LARGE_PADDING; } diff --git a/core/renderers/thrasos/info.ts b/core/renderers/thrasos/info.ts index 3c8c19f94..62c08fa42 100644 --- a/core/renderers/thrasos/info.ts +++ b/core/renderers/thrasos/info.ts @@ -109,6 +109,9 @@ export class RenderInfo extends BaseRenderInfo { if (!Types.isInput(prev) && !next) { // Between an editable field and the end of the row. if (Types.isField(prev) && prev.isEditable) { + if (prev.width === 0) { + return this.constants_.NO_PADDING; + } return this.constants_.MEDIUM_PADDING; } // Padding at the end of an icon-only row to make the block shape clearer. @@ -204,6 +207,9 @@ export class RenderInfo extends BaseRenderInfo { Types.isField(next) && prev.isEditable === next.isEditable ) { + if (prev.width === 0) { + return this.constants_.NO_PADDING; + } return this.constants_.LARGE_PADDING; } diff --git a/core/renderers/zelos/info.ts b/core/renderers/zelos/info.ts index 5c507c33a..e14c584f0 100644 --- a/core/renderers/zelos/info.ts +++ b/core/renderers/zelos/info.ts @@ -186,6 +186,12 @@ export class RenderInfo extends BaseRenderInfo { if (prev && Types.isLeftSquareCorner(prev) && next && Types.isHat(next)) { return this.constants_.NO_PADDING; } + + // No space after zero-width fields. + if (prev && Types.isField(prev) && prev.width === 0) { + return this.constants_.NO_PADDING; + } + return this.constants_.MEDIUM_PADDING; } From 343c2f51f3e34956f7e8efdc0fb220fe441e18d4 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 30 Jan 2025 13:47:36 -0800 Subject: [PATCH 095/102] feat: Add support for toggling readonly mode. (#8750) * feat: Add methods for toggling and inspecting the readonly state of a workspace. * refactor: Use the new readonly setters/getters in place of checking the injection options. * fix: Fix bug that allowed dragging blocks from a flyout onto a readonly workspace. * feat: Toggle a `blocklyReadOnly` class when readonly status is changed. * chore: Placate the linter. * chore: Placate the compiler. --- core/block.ts | 6 +++--- core/block_svg.ts | 6 ++++-- core/comments/workspace_comment.ts | 6 +++--- core/dragging/block_drag_strategy.ts | 2 +- core/dragging/comment_drag_strategy.ts | 2 +- core/flyout_base.ts | 2 +- core/gesture.ts | 2 +- core/shortcut_items.ts | 14 +++++++------- core/workspace.ts | 22 ++++++++++++++++++++++ core/workspace_svg.ts | 11 ++++++++++- tests/mocha/keydown_test.js | 2 +- 11 files changed, 54 insertions(+), 21 deletions(-) diff --git a/core/block.ts b/core/block.ts index f5683fcca..b95427bce 100644 --- a/core/block.ts +++ b/core/block.ts @@ -795,7 +795,7 @@ export class Block implements IASTNodeLocation { this.deletable && !this.shadow && !this.isDeadOrDying() && - !this.workspace.options.readOnly + !this.workspace.isReadOnly() ); } @@ -828,7 +828,7 @@ export class Block implements IASTNodeLocation { this.movable && !this.shadow && !this.isDeadOrDying() && - !this.workspace.options.readOnly + !this.workspace.isReadOnly() ); } @@ -917,7 +917,7 @@ export class Block implements IASTNodeLocation { */ isEditable(): boolean { return ( - this.editable && !this.isDeadOrDying() && !this.workspace.options.readOnly + this.editable && !this.isDeadOrDying() && !this.workspace.isReadOnly() ); } diff --git a/core/block_svg.ts b/core/block_svg.ts index 1f30852c5..a33a21a85 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -231,7 +231,7 @@ export class BlockSvg this.applyColour(); this.pathObject.updateMovable(this.isMovable() || this.isInFlyout); const svg = this.getSvgRoot(); - if (!this.workspace.options.readOnly && svg) { + if (svg) { browserEvents.conditionalBind(svg, 'pointerdown', this, this.onMouseDown); } @@ -585,6 +585,8 @@ export class BlockSvg * @param e Pointer down event. */ private onMouseDown(e: PointerEvent) { + if (this.workspace.isReadOnly()) return; + const gesture = this.workspace.getGesture(e); if (gesture) { gesture.handleBlockStart(e, this); @@ -612,7 +614,7 @@ export class BlockSvg protected generateContextMenu(): Array< ContextMenuOption | LegacyContextMenuOption > | null { - if (this.workspace.options.readOnly || !this.contextMenu) { + if (this.workspace.isReadOnly() || !this.contextMenu) { return null; } const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( diff --git a/core/comments/workspace_comment.ts b/core/comments/workspace_comment.ts index f21ece8a1..190efd64d 100644 --- a/core/comments/workspace_comment.ts +++ b/core/comments/workspace_comment.ts @@ -144,7 +144,7 @@ export class WorkspaceComment { * workspace is read-only. */ isEditable(): boolean { - return this.isOwnEditable() && !this.workspace.options.readOnly; + return this.isOwnEditable() && !this.workspace.isReadOnly(); } /** @@ -165,7 +165,7 @@ export class WorkspaceComment { * workspace is read-only. */ isMovable() { - return this.isOwnMovable() && !this.workspace.options.readOnly; + return this.isOwnMovable() && !this.workspace.isReadOnly(); } /** @@ -189,7 +189,7 @@ export class WorkspaceComment { return ( this.isOwnDeletable() && !this.isDeadOrDying() && - !this.workspace.options.readOnly + !this.workspace.isReadOnly() ); } diff --git a/core/dragging/block_drag_strategy.ts b/core/dragging/block_drag_strategy.ts index c9a1ea0ab..07b9bca5b 100644 --- a/core/dragging/block_drag_strategy.ts +++ b/core/dragging/block_drag_strategy.ts @@ -78,7 +78,7 @@ export class BlockDragStrategy implements IDragStrategy { return ( this.block.isOwnMovable() && !this.block.isDeadOrDying() && - !this.workspace.options.readOnly && + !this.workspace.isReadOnly() && // We never drag blocks in the flyout, only create new blocks that are // dragged. !this.block.isInFlyout diff --git a/core/dragging/comment_drag_strategy.ts b/core/dragging/comment_drag_strategy.ts index dd8b10fc2..9e051d5bc 100644 --- a/core/dragging/comment_drag_strategy.ts +++ b/core/dragging/comment_drag_strategy.ts @@ -29,7 +29,7 @@ export class CommentDragStrategy implements IDragStrategy { return ( this.comment.isOwnMovable() && !this.comment.isDeadOrDying() && - !this.workspace.options.readOnly + !this.workspace.isReadOnly() ); } diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 817076b97..5b2e91b7c 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -786,7 +786,7 @@ export abstract class Flyout * @internal */ isBlockCreatable(block: BlockSvg): boolean { - return block.isEnabled(); + return block.isEnabled() && !this.getTargetWorkspace().isReadOnly(); } /** diff --git a/core/gesture.ts b/core/gesture.ts index 0b65299e5..fc23ba7ca 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -894,7 +894,7 @@ export class Gesture { 'Cannot do a block click because the target block is ' + 'undefined', ); } - if (this.targetBlock.isEnabled()) { + if (this.flyout.isBlockCreatable(this.targetBlock)) { if (!eventUtils.getGroup()) { eventUtils.setGroup(true); } diff --git a/core/shortcut_items.ts b/core/shortcut_items.ts index 0db28a51a..0793e6213 100644 --- a/core/shortcut_items.ts +++ b/core/shortcut_items.ts @@ -40,7 +40,7 @@ export function registerEscape() { const escapeAction: KeyboardShortcut = { name: names.ESCAPE, preconditionFn(workspace) { - return !workspace.options.readOnly; + return !workspace.isReadOnly(); }, callback(workspace) { // AnyDuringMigration because: Property 'hideChaff' does not exist on @@ -62,7 +62,7 @@ export function registerDelete() { preconditionFn(workspace) { const selected = common.getSelected(); return ( - !workspace.options.readOnly && + !workspace.isReadOnly() && selected != null && isDeletable(selected) && selected.isDeletable() && @@ -113,7 +113,7 @@ export function registerCopy() { preconditionFn(workspace) { const selected = common.getSelected(); return ( - !workspace.options.readOnly && + !workspace.isReadOnly() && !Gesture.inProgress() && selected != null && isDeletable(selected) && @@ -164,7 +164,7 @@ export function registerCut() { preconditionFn(workspace) { const selected = common.getSelected(); return ( - !workspace.options.readOnly && + !workspace.isReadOnly() && !Gesture.inProgress() && selected != null && isDeletable(selected) && @@ -221,7 +221,7 @@ export function registerPaste() { const pasteShortcut: KeyboardShortcut = { name: names.PASTE, preconditionFn(workspace) { - return !workspace.options.readOnly && !Gesture.inProgress(); + return !workspace.isReadOnly() && !Gesture.inProgress(); }, callback() { if (!copyData || !copyWorkspace) return false; @@ -269,7 +269,7 @@ export function registerUndo() { const undoShortcut: KeyboardShortcut = { name: names.UNDO, preconditionFn(workspace) { - return !workspace.options.readOnly && !Gesture.inProgress(); + return !workspace.isReadOnly() && !Gesture.inProgress(); }, callback(workspace, e) { // 'z' for undo 'Z' is for redo. @@ -308,7 +308,7 @@ export function registerRedo() { const redoShortcut: KeyboardShortcut = { name: names.REDO, preconditionFn(workspace) { - return !Gesture.inProgress() && !workspace.options.readOnly; + return !Gesture.inProgress() && !workspace.isReadOnly(); }, callback(workspace, e) { // 'z' for undo 'Z' is for redo. diff --git a/core/workspace.ts b/core/workspace.ts index 265420ec0..30238b91e 100644 --- a/core/workspace.ts +++ b/core/workspace.ts @@ -114,6 +114,7 @@ export class Workspace implements IASTNodeLocation { private readonly typedBlocksDB = new Map(); private variableMap: IVariableMap>; private procedureMap: IProcedureMap = new ObservableProcedureMap(); + private readOnly = false; /** * Blocks in the flyout can refer to variables that don't exist in the main @@ -153,6 +154,8 @@ export class Workspace implements IASTNodeLocation { */ const VariableMap = this.getVariableMapClass(); this.variableMap = new VariableMap(this); + + this.setIsReadOnly(this.options.readOnly); } /** @@ -947,4 +950,23 @@ export class Workspace implements IASTNodeLocation { } return VariableMap; } + + /** + * Returns whether or not this workspace is in readonly mode. + * + * @returns True if the workspace is readonly, otherwise false. + */ + isReadOnly(): boolean { + return this.readOnly; + } + + /** + * Sets whether or not this workspace is in readonly mode. + * + * @param readOnly True to make the workspace readonly, otherwise false. + */ + setIsReadOnly(readOnly: boolean) { + this.readOnly = readOnly; + this.options.readOnly = readOnly; + } } diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index e9aac5b9d..78506115e 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -1703,7 +1703,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { * @internal */ showContextMenu(e: PointerEvent) { - if (this.options.readOnly || this.isFlyout) { + if (this.isReadOnly() || this.isFlyout) { return; } const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions( @@ -2532,6 +2532,15 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg { dom.removeClass(this.injectionDiv, className); } } + + override setIsReadOnly(readOnly: boolean) { + super.setIsReadOnly(readOnly); + if (readOnly) { + this.addClass('blocklyReadOnly'); + } else { + this.removeClass('blocklyReadOnly'); + } + } } /** diff --git a/tests/mocha/keydown_test.js b/tests/mocha/keydown_test.js index 0b72a7fee..82293f224 100644 --- a/tests/mocha/keydown_test.js +++ b/tests/mocha/keydown_test.js @@ -42,7 +42,7 @@ suite('Key Down', function () { function runReadOnlyTest(keyEvent, opt_name) { const name = opt_name ? opt_name : 'Not called when readOnly is true'; test(name, function () { - this.workspace.options.readOnly = true; + this.workspace.setIsReadOnly(true); this.injectionDiv.dispatchEvent(keyEvent); sinon.assert.notCalled(this.hideChaffSpy); }); From e6e57ddc01ae39f044a5aa7cc568be6d7206f523 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 4 Feb 2025 15:23:03 -0800 Subject: [PATCH 096/102] fix: Fix bug that caused blocks dragged from non-primary flyouts to be misplaced. (#8753) * fix: Fix bug that caused blocks dragged from non-primary flyouts to be misplaced. * chore: Fix docstring. --- core/block_flyout_inflater.ts | 58 +++++++++++++--------------- core/button_flyout_inflater.ts | 10 ++--- core/flyout_base.ts | 2 +- core/interfaces/i_flyout_inflater.ts | 6 +-- core/label_flyout_inflater.ts | 11 +++--- core/separator_flyout_inflater.ts | 9 ++--- 6 files changed, 45 insertions(+), 51 deletions(-) diff --git a/core/block_flyout_inflater.ts b/core/block_flyout_inflater.ts index 0177ddf50..6011b150e 100644 --- a/core/block_flyout_inflater.ts +++ b/core/block_flyout_inflater.ts @@ -35,7 +35,6 @@ const BLOCK_TYPE = 'block'; export class BlockFlyoutInflater implements IFlyoutInflater { protected permanentlyDisabledBlocks = new Set(); protected listeners = new Map(); - protected flyoutWorkspace?: WorkspaceSvg; protected flyout?: IFlyout; private capacityWrapper: (event: AbstractEvent) => void; @@ -50,13 +49,12 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * Inflates a flyout block from the given state and adds it to the flyout. * * @param state A JSON representation of a flyout block. - * @param flyoutWorkspace The workspace to create the block on. + * @param flyout The flyout to create the block on. * @returns A newly created block. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { - this.setFlyoutWorkspace(flyoutWorkspace); - this.flyout = flyoutWorkspace.targetWorkspace?.getFlyout() ?? undefined; - const block = this.createBlock(state as BlockInfo, flyoutWorkspace); + load(state: object, flyout: IFlyout): FlyoutItem { + this.setFlyout(flyout); + const block = this.createBlock(state as BlockInfo, flyout.getWorkspace()); if (!block.isEnabled()) { // Record blocks that were initially disabled. @@ -157,22 +155,18 @@ export class BlockFlyoutInflater implements IFlyoutInflater { } /** - * Updates this inflater's flyout workspace. + * Updates this inflater's flyout. * - * @param workspace The workspace of the flyout that owns this inflater. + * @param flyout The flyout that owns this inflater. */ - protected setFlyoutWorkspace(workspace: WorkspaceSvg) { - if (this.flyoutWorkspace === workspace) return; + protected setFlyout(flyout: IFlyout) { + if (this.flyout === flyout) return; - if (this.flyoutWorkspace) { - this.flyoutWorkspace.targetWorkspace?.removeChangeListener( - this.capacityWrapper, - ); + if (this.flyout) { + this.flyout.targetWorkspace?.removeChangeListener(this.capacityWrapper); } - this.flyoutWorkspace = workspace; - this.flyoutWorkspace.targetWorkspace?.addChangeListener( - this.capacityWrapper, - ); + this.flyout = flyout; + this.flyout.targetWorkspace?.addChangeListener(this.capacityWrapper); } /** @@ -182,7 +176,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { * @param block The block to update the enabled/disabled state of. */ private updateStateBasedOnCapacity(block: BlockSvg) { - const enable = this.flyoutWorkspace?.targetWorkspace?.isCapacityAvailable( + const enable = this.flyout?.targetWorkspace?.isCapacityAvailable( common.getBlockTypeCounts(block), ); let currentBlock: BlockSvg | null = block; @@ -209,11 +203,10 @@ export class BlockFlyoutInflater implements IFlyoutInflater { 'pointerdown', block, (e: PointerEvent) => { - const gesture = this.flyoutWorkspace?.targetWorkspace?.getGesture(e); - const flyout = this.flyoutWorkspace?.targetWorkspace?.getFlyout(); - if (gesture && flyout) { + const gesture = this.flyout?.targetWorkspace?.getGesture(e); + if (gesture && this.flyout) { gesture.setStartBlock(block); - gesture.handleFlyoutStart(e, flyout); + gesture.handleFlyoutStart(e, this.flyout); } }, ), @@ -221,14 +214,14 @@ export class BlockFlyoutInflater implements IFlyoutInflater { blockListeners.push( browserEvents.bind(block.getSvgRoot(), 'pointerenter', null, () => { - if (!this.flyoutWorkspace?.targetWorkspace?.isDragging()) { + if (!this.flyout?.targetWorkspace?.isDragging()) { block.addSelect(); } }), ); blockListeners.push( browserEvents.bind(block.getSvgRoot(), 'pointerleave', null, () => { - if (!this.flyoutWorkspace?.targetWorkspace?.isDragging()) { + if (!this.flyout?.targetWorkspace?.isDragging()) { block.removeSelect(); } }), @@ -245,7 +238,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { */ private filterFlyoutBasedOnCapacity(event: AbstractEvent) { if ( - !this.flyoutWorkspace || + !this.flyout || (event && !( event.type === EventType.BLOCK_CREATE || @@ -254,11 +247,14 @@ export class BlockFlyoutInflater implements IFlyoutInflater { ) return; - this.flyoutWorkspace.getTopBlocks(false).forEach((block) => { - if (!this.permanentlyDisabledBlocks.has(block)) { - this.updateStateBasedOnCapacity(block); - } - }); + this.flyout + .getWorkspace() + .getTopBlocks(false) + .forEach((block) => { + if (!this.permanentlyDisabledBlocks.has(block)) { + this.updateStateBasedOnCapacity(block); + } + }); } /** diff --git a/core/button_flyout_inflater.ts b/core/button_flyout_inflater.ts index 2a9c3e289..665ce7a24 100644 --- a/core/button_flyout_inflater.ts +++ b/core/button_flyout_inflater.ts @@ -6,10 +6,10 @@ import {FlyoutButton} from './flyout_button.js'; import {FlyoutItem} from './flyout_item.js'; +import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import {ButtonOrLabelInfo} from './utils/toolbox.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; const BUTTON_TYPE = 'button'; @@ -21,13 +21,13 @@ export class ButtonFlyoutInflater implements IFlyoutInflater { * Inflates a flyout button from the given state and adds it to the flyout. * * @param state A JSON representation of a flyout button. - * @param flyoutWorkspace The workspace to create the button on. + * @param flyout The flyout to create the button on. * @returns A newly created FlyoutButton. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { + load(state: object, flyout: IFlyout): FlyoutItem { const button = new FlyoutButton( - flyoutWorkspace, - flyoutWorkspace.targetWorkspace!, + flyout.getWorkspace(), + flyout.targetWorkspace!, state as ButtonOrLabelInfo, false, ); diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 5b2e91b7c..e738470a6 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -678,7 +678,7 @@ export abstract class Flyout const type = info['kind'].toLowerCase(); const inflater = this.getInflaterForType(type); if (inflater) { - contents.push(inflater.load(info, this.getWorkspace())); + contents.push(inflater.load(info, this)); const gap = inflater.gapForItem(info, defaultGap); if (gap) { contents.push( diff --git a/core/interfaces/i_flyout_inflater.ts b/core/interfaces/i_flyout_inflater.ts index 2deab770d..e3c1f5db4 100644 --- a/core/interfaces/i_flyout_inflater.ts +++ b/core/interfaces/i_flyout_inflater.ts @@ -1,5 +1,5 @@ import type {FlyoutItem} from '../flyout_item.js'; -import type {WorkspaceSvg} from '../workspace_svg.js'; +import type {IFlyout} from './i_flyout.js'; export interface IFlyoutInflater { /** @@ -9,14 +9,14 @@ export interface IFlyoutInflater { * allow for code reuse. * * @param state A JSON representation of an element to inflate on the flyout. - * @param flyoutWorkspace The flyout's workspace, where the inflated element + * @param flyout The flyout on whose workspace the inflated element * should be created. If the inflated element is an `IRenderedElement` it * itself or the inflater should append it to the workspace; the flyout * will not do so itself. The flyout is responsible for positioning the * element, however. * @returns The newly inflated flyout element. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem; + load(state: object, flyout: IFlyout): FlyoutItem; /** * Returns the amount of spacing that should follow the element corresponding diff --git a/core/label_flyout_inflater.ts b/core/label_flyout_inflater.ts index 51899ef23..e4f3e3b54 100644 --- a/core/label_flyout_inflater.ts +++ b/core/label_flyout_inflater.ts @@ -6,11 +6,10 @@ import {FlyoutButton} from './flyout_button.js'; import {FlyoutItem} from './flyout_item.js'; +import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import {ButtonOrLabelInfo} from './utils/toolbox.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; - const LABEL_TYPE = 'label'; /** @@ -21,13 +20,13 @@ export class LabelFlyoutInflater implements IFlyoutInflater { * Inflates a flyout label from the given state and adds it to the flyout. * * @param state A JSON representation of a flyout label. - * @param flyoutWorkspace The workspace to create the label on. + * @param flyout The flyout to create the label on. * @returns A FlyoutButton configured as a label. */ - load(state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { + load(state: object, flyout: IFlyout): FlyoutItem { const label = new FlyoutButton( - flyoutWorkspace, - flyoutWorkspace.targetWorkspace!, + flyout.getWorkspace(), + flyout.targetWorkspace!, state as ButtonOrLabelInfo, true, ); diff --git a/core/separator_flyout_inflater.ts b/core/separator_flyout_inflater.ts index 0b9aa6026..63e533554 100644 --- a/core/separator_flyout_inflater.ts +++ b/core/separator_flyout_inflater.ts @@ -6,10 +6,10 @@ import {FlyoutItem} from './flyout_item.js'; import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; +import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; import * as registry from './registry.js'; import type {SeparatorInfo} from './utils/toolbox.js'; -import type {WorkspaceSvg} from './workspace_svg.js'; /** * @internal @@ -35,12 +35,11 @@ export class SeparatorFlyoutInflater implements IFlyoutInflater { * returned by gapForElement, which knows the default gap, unlike this method. * * @param _state A JSON representation of a flyout separator. - * @param flyoutWorkspace The workspace the separator belongs to. + * @param flyout The flyout to create the separator for. * @returns A newly created FlyoutSeparator. */ - load(_state: object, flyoutWorkspace: WorkspaceSvg): FlyoutItem { - const flyoutAxis = flyoutWorkspace.targetWorkspace?.getFlyout() - ?.horizontalLayout + load(_state: object, flyout: IFlyout): FlyoutItem { + const flyoutAxis = flyout.horizontalLayout ? SeparatorAxis.X : SeparatorAxis.Y; const separator = new FlyoutSeparator(0, flyoutAxis); From 3ae422a56657c728707b25842022c57e86f8ab3a Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Fri, 14 Feb 2025 01:26:34 +0000 Subject: [PATCH 097/102] feat: Add interfaces for focus management. Introduces the necessary base interfaces for representing different focusable contexts within Blockly. The actual logic for utilizing and implementing these interfaces will come in later PRs. --- core/blockly.ts | 4 +++ core/interfaces/i_focusable_node.ts | 36 ++++++++++++++++++++ core/interfaces/i_focusable_tree.ts | 53 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 core/interfaces/i_focusable_node.ts create mode 100644 core/interfaces/i_focusable_tree.ts diff --git a/core/blockly.ts b/core/blockly.ts index a743ca5a7..cf77bca3f 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -140,6 +140,8 @@ import { } from './interfaces/i_draggable.js'; import {IDragger} from './interfaces/i_dragger.js'; import {IFlyout} from './interfaces/i_flyout.js'; +import {IFocusableNode} from './interfaces/i_focusable_node.js'; +import {IFocusableTree} from './interfaces/i_focusable_tree.js'; import {IHasBubble, hasBubble} from './interfaces/i_has_bubble.js'; import {IIcon, isIcon} from './interfaces/i_icon.js'; import {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js'; @@ -544,6 +546,8 @@ export { IDragger, IFlyout, IFlyoutInflater, + IFocusableNode, + IFocusableTree, IHasBubble, IIcon, IKeyboardAccessible, diff --git a/core/interfaces/i_focusable_node.ts b/core/interfaces/i_focusable_node.ts new file mode 100644 index 000000000..87a0293ae --- /dev/null +++ b/core/interfaces/i_focusable_node.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFocusableTree} from './i_focusable_tree.js'; + +/** Represents anything that can have input focus. */ +export interface IFocusableNode { + /** + * Returns the DOM element that can be explicitly requested to receive focus. + * + * IMPORTANT: Please note that this element is expected to have a visual + * presence on the page as it will both be explicitly focused and have its + * style changed depending on its current focus state (i.e. blurred, actively + * focused, and passively focused). The element will have one of two styles + * attached (where no style indicates blurred/not focused): + * - blocklyActiveFocus + * - blocklyPassiveFocus + * + * The returned element must also have a valid ID specified, and unique to the + * element relative to its nearest IFocusableTree parent. + * + * It's expected the return element will not change for the lifetime of the + * node. + */ + getFocusableElement(): HTMLElement | SVGElement; + + /** + * Returns the closest parent tree of this node (in cases where a tree has + * distinct trees underneath it), which represents the tree to which this node + * belongs. + */ + getFocusableTree(): IFocusableTree; +} diff --git a/core/interfaces/i_focusable_tree.ts b/core/interfaces/i_focusable_tree.ts new file mode 100644 index 000000000..21f87678d --- /dev/null +++ b/core/interfaces/i_focusable_tree.ts @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {IFocusableNode} from './i_focusable_node.js'; + +/** + * Represents a tree of focusable elements with its own active/passive focus + * context. + * + * Note that focus is handled by FocusManager, and tree implementations can have + * at most one IFocusableNode focused at one time. If the tree itself has focus, + * then the tree's focused node is considered 'active' ('passive' if another + * tree has focus). + * + * Focus is shared between one or more trees, where each tree can have exactly + * one active or passive node (and only one active node can exist on the whole + * page at any given time). The idea of passive focus is to provide context to + * users on where their focus will be restored upon navigating back to a + * previously focused tree. + */ +export interface IFocusableTree { + /** + * Returns the current node with focus in this tree, or null if none (or if + * the root has focus). + * + * Note that this will never return a node from a nested sub-tree as that tree + * should specifically be called in order to retrieve its focused node. + */ + getFocusedNode(): IFocusableNode | null; + + /** + * Returns the top-level focusable node of the tree. + * + * It's expected that the returned node will be focused in cases where + * FocusManager wants to focus a tree in a situation where it does not + * currently have a focused node. + */ + getRootFocusableNode(): IFocusableNode; + + /** + * Returns the IFocusableNode corresponding to the select element, or null if + * the element does not have such a node. + * + * The provided element must have a non-null ID that conforms to the contract + * mentioned in IFocusableNode. + */ + findFocusableNodeFor( + element: HTMLElement | SVGElement, + ): IFocusableNode | null; +} From b343a13bbecd7db3b4359bd04abdfb5857318142 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Thu, 20 Feb 2025 08:56:57 -0800 Subject: [PATCH 099/102] fix: Fixes #8764 by moving the event grouping calls up to dragger.ts (#8781) --- core/dragging/block_drag_strategy.ts | 16 ++++++---------- core/dragging/bubble_drag_strategy.ts | 11 ----------- core/dragging/comment_drag_strategy.ts | 10 ---------- core/dragging/dragger.ts | 11 +++++++---- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/core/dragging/block_drag_strategy.ts b/core/dragging/block_drag_strategy.ts index 07b9bca5b..9a2cd747c 100644 --- a/core/dragging/block_drag_strategy.ts +++ b/core/dragging/block_drag_strategy.ts @@ -62,8 +62,8 @@ export class BlockDragStrategy implements IDragStrategy { */ private dragOffset = new Coordinate(0, 0); - /** Was there already an event group in progress when the drag started? */ - private inGroup: boolean = false; + /** Used to persist an event group when snapping is done async. */ + private originalEventGroup = ''; constructor(private block: BlockSvg) { this.workspace = block.workspace; @@ -96,10 +96,6 @@ export class BlockDragStrategy implements IDragStrategy { } this.dragging = true; - this.inGroup = !!eventUtils.getGroup(); - if (!this.inGroup) { - eventUtils.setGroup(true); - } this.fireDragStartEvent(); this.startLoc = this.block.getRelativeToSurfaceXY(); @@ -363,6 +359,7 @@ export class BlockDragStrategy implements IDragStrategy { this.block.getParent()?.endDrag(e); return; } + this.originalEventGroup = eventUtils.getGroup(); this.fireDragEndEvent(); this.fireMoveEvent(); @@ -388,20 +385,19 @@ export class BlockDragStrategy implements IDragStrategy { } else { this.block.queueRender().then(() => this.disposeStep()); } - - if (!this.inGroup) { - eventUtils.setGroup(false); - } } /** Disposes of any state at the end of the drag. */ private disposeStep() { + const newGroup = eventUtils.getGroup(); + eventUtils.setGroup(this.originalEventGroup); this.block.snapToGrid(); // Must dispose after connections are applied to not break the dynamic // connections plugin. See #7859 this.connectionPreviewer!.dispose(); this.workspace.setResizesEnabled(true); + eventUtils.setGroup(newGroup); } /** Connects the given candidate connections. */ diff --git a/core/dragging/bubble_drag_strategy.ts b/core/dragging/bubble_drag_strategy.ts index c2a5c58f4..8a5a67839 100644 --- a/core/dragging/bubble_drag_strategy.ts +++ b/core/dragging/bubble_drag_strategy.ts @@ -5,7 +5,6 @@ */ import {IBubble, WorkspaceSvg} from '../blockly.js'; -import * as eventUtils from '../events/utils.js'; import {IDragStrategy} from '../interfaces/i_draggable.js'; import * as layers from '../layers.js'; import {Coordinate} from '../utils.js'; @@ -13,9 +12,6 @@ import {Coordinate} from '../utils.js'; export class BubbleDragStrategy implements IDragStrategy { private startLoc: Coordinate | null = null; - /** Was there already an event group in progress when the drag started? */ - private inGroup: boolean = false; - constructor( private bubble: IBubble, private workspace: WorkspaceSvg, @@ -26,10 +22,6 @@ export class BubbleDragStrategy implements IDragStrategy { } startDrag(): void { - this.inGroup = !!eventUtils.getGroup(); - if (!this.inGroup) { - eventUtils.setGroup(true); - } this.startLoc = this.bubble.getRelativeToSurfaceXY(); this.workspace.setResizesEnabled(false); this.workspace.getLayerManager()?.moveToDragLayer(this.bubble); @@ -44,9 +36,6 @@ export class BubbleDragStrategy implements IDragStrategy { endDrag(): void { this.workspace.setResizesEnabled(true); - if (!this.inGroup) { - eventUtils.setGroup(false); - } this.workspace .getLayerManager() diff --git a/core/dragging/comment_drag_strategy.ts b/core/dragging/comment_drag_strategy.ts index 9e051d5bc..b7974d8b4 100644 --- a/core/dragging/comment_drag_strategy.ts +++ b/core/dragging/comment_drag_strategy.ts @@ -18,9 +18,6 @@ export class CommentDragStrategy implements IDragStrategy { private workspace: WorkspaceSvg; - /** Was there already an event group in progress when the drag started? */ - private inGroup: boolean = false; - constructor(private comment: RenderedWorkspaceComment) { this.workspace = comment.workspace; } @@ -34,10 +31,6 @@ export class CommentDragStrategy implements IDragStrategy { } startDrag(): void { - this.inGroup = !!eventUtils.getGroup(); - if (!this.inGroup) { - eventUtils.setGroup(true); - } this.fireDragStartEvent(); this.startLoc = this.comment.getRelativeToSurfaceXY(); this.workspace.setResizesEnabled(false); @@ -61,9 +54,6 @@ export class CommentDragStrategy implements IDragStrategy { this.comment.snapToGrid(); this.workspace.setResizesEnabled(true); - if (!this.inGroup) { - eventUtils.setGroup(false); - } } /** Fire a UI event at the start of a comment drag. */ diff --git a/core/dragging/dragger.ts b/core/dragging/dragger.ts index 8a9ac87c6..518351d5c 100644 --- a/core/dragging/dragger.ts +++ b/core/dragging/dragger.ts @@ -31,6 +31,9 @@ export class Dragger implements IDragger { /** Handles any drag startup. */ onDragStart(e: PointerEvent) { + if (!eventUtils.getGroup()) { + eventUtils.setGroup(true); + } this.draggable.startDrag(e); } @@ -119,13 +122,13 @@ export class Dragger implements IDragger { this.draggable.endDrag(e); if (wouldDelete && isDeletable(root)) { - // We want to make sure the delete gets grouped with any possible - // move event. - const newGroup = eventUtils.getGroup(); + // We want to make sure the delete gets grouped with any possible move + // event. In core Blockly this shouldn't happen, but due to a change + // in behavior older custom draggables might still clear the group. eventUtils.setGroup(origGroup); root.dispose(); - eventUtils.setGroup(newGroup); } + eventUtils.setGroup(false); } // We need to special case blocks for now so that we look at the root block From 22dbd75bd49999515179f1610d64e9d4c31c2f9e Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 24 Feb 2025 08:17:38 -0800 Subject: [PATCH 100/102] refactor: make CommentView more amenable to subclassing. (#8783) --- core/comments/comment_view.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/comments/comment_view.ts b/core/comments/comment_view.ts index f06c96f80..26623d40f 100644 --- a/core/comments/comment_view.ts +++ b/core/comments/comment_view.ts @@ -95,10 +95,10 @@ export class CommentView implements IRenderedElement { private resizePointerMoveListener: browserEvents.Data | null = null; /** Whether this comment view is currently being disposed or not. */ - private disposing = false; + protected disposing = false; /** Whether this comment view has been disposed or not. */ - private disposed = false; + protected disposed = false; /** Size of this comment when the resize drag was initiated. */ private preResizeSize?: Size; @@ -106,7 +106,7 @@ export class CommentView implements IRenderedElement { /** The default size of newly created comments. */ static defaultCommentSize = new Size(120, 100); - constructor(private readonly workspace: WorkspaceSvg) { + constructor(readonly workspace: WorkspaceSvg) { this.svgRoot = dom.createSvgElement(Svg.G, { 'class': 'blocklyComment blocklyEditable blocklyDraggable', }); From 0ed6c82acca280816069613a059e3830147f132b Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 27 Feb 2025 10:55:34 -0800 Subject: [PATCH 101/102] fix: Disallow and ignore x and y attributes for blocks in toolbox definitions. (#8785) * fix: Disallow and ignore x and y attributes for blocks in toolbox definitions. * chore: Clarify comment in BlockFlyoutInflater. --- core/block_flyout_inflater.ts | 9 +++++++++ core/utils/toolbox.ts | 2 -- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/block_flyout_inflater.ts b/core/block_flyout_inflater.ts index 6011b150e..b180dbc0c 100644 --- a/core/block_flyout_inflater.ts +++ b/core/block_flyout_inflater.ts @@ -101,6 +101,15 @@ export class BlockFlyoutInflater implements IFlyoutInflater { ) { blockDefinition['disabledReasons'] = [MANUALLY_DISABLED]; } + // These fields used to be allowed and may still be present, but are + // ignored here since everything in the flyout should always be laid out + // linearly. + if ('x' in blockDefinition) { + delete blockDefinition['x']; + } + if ('y' in blockDefinition) { + delete blockDefinition['y']; + } block = blocks.appendInternal(blockDefinition as blocks.State, workspace); } diff --git a/core/utils/toolbox.ts b/core/utils/toolbox.ts index 296bb6dcc..f81ebdc72 100644 --- a/core/utils/toolbox.ts +++ b/core/utils/toolbox.ts @@ -24,8 +24,6 @@ export interface BlockInfo { disabledReasons?: string[]; enabled?: boolean; id?: string; - x?: number; - y?: number; collapsed?: boolean; inline?: boolean; data?: string; From fa4fce5c12f8197b6459537cbf0e20249e545e36 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 27 Feb 2025 14:00:40 -0800 Subject: [PATCH 102/102] feat!: Added support for separators in menus. (#8767) * feat!: Added support for separators in menus. * chore: Do English gooder. * fix: Remove menu separators from the DOM during dispose. --- core/contextmenu.ts | 6 +++ core/contextmenu_registry.ts | 95 ++++++++++++++++++++++++++++++------ core/css.ts | 8 +++ core/extensions.ts | 5 +- core/field_dropdown.ts | 51 ++++++++++--------- core/menu.ts | 28 +++++++---- core/menu_separator.ts | 38 +++++++++++++++ core/utils/aria.ts | 3 ++ 8 files changed, 186 insertions(+), 48 deletions(-) create mode 100644 core/menu_separator.ts diff --git a/core/contextmenu.ts b/core/contextmenu.ts index b49dcba51..7123198c2 100644 --- a/core/contextmenu.ts +++ b/core/contextmenu.ts @@ -18,6 +18,7 @@ import type { import {EventType} from './events/type.js'; import * as eventUtils from './events/utils.js'; import {Menu} from './menu.js'; +import {MenuSeparator} from './menu_separator.js'; import {MenuItem} from './menuitem.js'; import * as serializationBlocks from './serialization/blocks.js'; import * as aria from './utils/aria.js'; @@ -111,6 +112,11 @@ function populate_( menu.setRole(aria.Role.MENU); for (let i = 0; i < options.length; i++) { const option = options[i]; + if (option.separator) { + menu.addChild(new MenuSeparator()); + continue; + } + const menuItem = new MenuItem(option.text); menuItem.setRightToLeft(rtl); menuItem.setRole(aria.Role.MENUITEM); diff --git a/core/contextmenu_registry.ts b/core/contextmenu_registry.ts index fb0d899d1..5bfb1eb63 100644 --- a/core/contextmenu_registry.ts +++ b/core/contextmenu_registry.ts @@ -87,21 +87,37 @@ export class ContextMenuRegistry { const menuOptions: ContextMenuOption[] = []; for (const item of this.registeredItems.values()) { if (scopeType === item.scopeType) { - const precondition = item.preconditionFn(scope); - if (precondition !== 'hidden') { + let menuOption: + | ContextMenuRegistry.CoreContextMenuOption + | ContextMenuRegistry.SeparatorContextMenuOption + | ContextMenuRegistry.ActionContextMenuOption; + menuOption = { + scope, + weight: item.weight, + }; + + if (item.separator) { + menuOption = { + ...menuOption, + separator: true, + }; + } else { + const precondition = item.preconditionFn(scope); + if (precondition === 'hidden') continue; + const displayText = typeof item.displayText === 'function' ? item.displayText(scope) : item.displayText; - const menuOption: ContextMenuOption = { + menuOption = { + ...menuOption, text: displayText, - enabled: precondition === 'enabled', callback: item.callback, - scope, - weight: item.weight, + enabled: precondition === 'enabled', }; - menuOptions.push(menuOption); } + + menuOptions.push(menuOption); } } menuOptions.sort(function (a, b) { @@ -134,9 +150,18 @@ export namespace ContextMenuRegistry { } /** - * A menu item as entered in the registry. + * Fields common to all context menu registry items. */ - export interface RegistryItem { + interface CoreRegistryItem { + scopeType: ScopeType; + weight: number; + id: string; + } + + /** + * A representation of a normal, clickable menu item in the registry. + */ + interface ActionRegistryItem extends CoreRegistryItem { /** * @param scope Object that provides a reference to the thing that had its * context menu opened. @@ -144,17 +169,38 @@ export namespace ContextMenuRegistry { * the event that triggered the click on the option. */ callback: (scope: Scope, e: PointerEvent) => void; - scopeType: ScopeType; displayText: ((p1: Scope) => string | HTMLElement) | string | HTMLElement; preconditionFn: (p1: Scope) => string; - weight: number; - id: string; + separator?: never; } /** - * A menu item as presented to contextmenu.js. + * A representation of a menu separator item in the registry. */ - export interface ContextMenuOption { + interface SeparatorRegistryItem extends CoreRegistryItem { + separator: true; + callback?: never; + displayText?: never; + preconditionFn?: never; + } + + /** + * A menu item as entered in the registry. + */ + export type RegistryItem = ActionRegistryItem | SeparatorRegistryItem; + + /** + * Fields common to all context menu items as used by contextmenu.ts. + */ + export interface CoreContextMenuOption { + scope: Scope; + weight: number; + } + + /** + * A representation of a normal, clickable menu item in contextmenu.ts. + */ + export interface ActionContextMenuOption extends CoreContextMenuOption { text: string | HTMLElement; enabled: boolean; /** @@ -164,10 +210,26 @@ export namespace ContextMenuRegistry { * the event that triggered the click on the option. */ callback: (scope: Scope, e: PointerEvent) => void; - scope: Scope; - weight: number; + separator?: never; } + /** + * A representation of a menu separator item in contextmenu.ts. + */ + export interface SeparatorContextMenuOption extends CoreContextMenuOption { + separator: true; + text?: never; + enabled?: never; + callback?: never; + } + + /** + * A menu item as presented to contextmenu.ts. + */ + export type ContextMenuOption = + | ActionContextMenuOption + | SeparatorContextMenuOption; + /** * A subset of ContextMenuOption corresponding to what was publicly * documented. ContextMenuOption should be preferred for new code. @@ -176,6 +238,7 @@ export namespace ContextMenuRegistry { text: string; enabled: boolean; callback: (p1: Scope) => void; + separator?: never; } /** diff --git a/core/css.ts b/core/css.ts index 57217f854..00bbc0e02 100644 --- a/core/css.ts +++ b/core/css.ts @@ -461,6 +461,14 @@ input[type=number] { margin-right: -24px; } +.blocklyMenuSeparator { + background-color: #ccc; + height: 1px; + border: 0; + margin-left: 4px; + margin-right: 4px; +} + .blocklyBlockDragSurface, .blocklyAnimationLayer { position: absolute; top: 0; diff --git a/core/extensions.ts b/core/extensions.ts index 0957b7f86..59d218d17 100644 --- a/core/extensions.ts +++ b/core/extensions.ts @@ -437,7 +437,10 @@ function checkDropdownOptionsInTable( } const options = dropdown.getOptions(); - for (const [, key] of options) { + for (const option of options) { + if (option === FieldDropdown.SEPARATOR) continue; + + const [, key] = option; if (lookupTable[key] === undefined) { console.warn( `No tooltip mapping for value ${key} of field ` + diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index 0be621d38..60977524a 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -23,6 +23,7 @@ import { } from './field.js'; import * as fieldRegistry from './field_registry.js'; import {Menu} from './menu.js'; +import {MenuSeparator} from './menu_separator.js'; import {MenuItem} from './menuitem.js'; import * as aria from './utils/aria.js'; import {Coordinate} from './utils/coordinate.js'; @@ -35,14 +36,10 @@ import {Svg} from './utils/svg.js'; * Class for an editable dropdown field. */ export class FieldDropdown extends Field { - /** Horizontal distance that a checkmark overhangs the dropdown. */ - static CHECKMARK_OVERHANG = 25; - /** - * Maximum height of the dropdown menu, as a percentage of the viewport - * height. + * Magic constant used to represent a separator in a list of dropdown items. */ - static MAX_MENU_HEIGHT_VH = 0.45; + static readonly SEPARATOR = 'separator'; static ARROW_CHAR = '▾'; @@ -323,7 +320,13 @@ export class FieldDropdown extends Field { const options = this.getOptions(false); this.selectedMenuItem = null; for (let i = 0; i < options.length; i++) { - const [label, value] = options[i]; + const option = options[i]; + if (option === FieldDropdown.SEPARATOR) { + menu.addChild(new MenuSeparator()); + continue; + } + + const [label, value] = option; const content = (() => { if (typeof label === 'object') { // Convert ImageProperties to an HTMLImageElement. @@ -667,7 +670,10 @@ export class FieldDropdown extends Field { suffix?: string; } { let hasImages = false; - const trimmedOptions = options.map(([label, value]): MenuOption => { + const trimmedOptions = options.map((option): MenuOption => { + if (option === FieldDropdown.SEPARATOR) return option; + + const [label, value] = option; if (typeof label === 'string') { return [parsing.replaceMessageReferences(label), value]; } @@ -748,28 +754,28 @@ export class FieldDropdown extends Field { } let foundError = false; for (let i = 0; i < options.length; i++) { - const tuple = options[i]; - if (!Array.isArray(tuple)) { + const option = options[i]; + if (!Array.isArray(option) && option !== FieldDropdown.SEPARATOR) { foundError = true; console.error( - `Invalid option[${i}]: Each FieldDropdown option must be an array. - Found: ${tuple}`, + `Invalid option[${i}]: Each FieldDropdown option must be an array or + the string literal 'separator'. Found: ${option}`, ); - } else if (typeof tuple[1] !== 'string') { + } else if (typeof option[1] !== 'string') { foundError = true; console.error( `Invalid option[${i}]: Each FieldDropdown option id must be a string. - Found ${tuple[1]} in: ${tuple}`, + Found ${option[1]} in: ${option}`, ); } else if ( - tuple[0] && - typeof tuple[0] !== 'string' && - typeof tuple[0].src !== 'string' + option[0] && + typeof option[0] !== 'string' && + typeof option[0].src !== 'string' ) { foundError = true; console.error( `Invalid option[${i}]: Each FieldDropdown option must have a string - label or image description. Found ${tuple[0]} in: ${tuple}`, + label or image description. Found ${option[0]} in: ${option}`, ); } } @@ -790,11 +796,12 @@ export interface ImageProperties { } /** - * An individual option in the dropdown menu. The first element is the human- - * readable value (text or image), and the second element is the language- - * neutral value. + * An individual option in the dropdown menu. Can be either the string literal + * `separator` for a menu separator item, or an array for normal action menu + * items. In the latter case, the first element is the human-readable value + * (text or image), and the second element is the language-neutral value. */ -export type MenuOption = [string | ImageProperties, string]; +export type MenuOption = [string | ImageProperties, string] | 'separator'; /** * A function that generates an array of menu options for FieldDropdown diff --git a/core/menu.ts b/core/menu.ts index 7746bb212..acb5a3780 100644 --- a/core/menu.ts +++ b/core/menu.ts @@ -12,7 +12,8 @@ // Former goog.module ID: Blockly.Menu import * as browserEvents from './browser_events.js'; -import type {MenuItem} from './menuitem.js'; +import type {MenuSeparator} from './menu_separator.js'; +import {MenuItem} from './menuitem.js'; import * as aria from './utils/aria.js'; import {Coordinate} from './utils/coordinate.js'; import type {Size} from './utils/size.js'; @@ -23,11 +24,9 @@ import * as style from './utils/style.js'; */ export class Menu { /** - * Array of menu items. - * (Nulls are never in the array, but typing the array as nullable prevents - * the compiler from objecting to .indexOf(null)) + * Array of menu items and separators. */ - private readonly menuItems: MenuItem[] = []; + private readonly menuItems: Array = []; /** * Coordinates of the mousedown event that caused this menu to open. Used to @@ -69,10 +68,10 @@ export class Menu { /** * Add a new menu item to the bottom of this menu. * - * @param menuItem Menu item to append. + * @param menuItem Menu item or separator to append. * @internal */ - addChild(menuItem: MenuItem) { + addChild(menuItem: MenuItem | MenuSeparator) { this.menuItems.push(menuItem); } @@ -227,7 +226,8 @@ export class Menu { while (currentElement && currentElement !== menuElem) { if (currentElement.classList.contains('blocklyMenuItem')) { // Having found a menu item's div, locate that menu item in this menu. - for (let i = 0, menuItem; (menuItem = this.menuItems[i]); i++) { + const items = this.getMenuItems(); + for (let i = 0, menuItem; (menuItem = items[i]); i++) { if (menuItem.getElement() === currentElement) { return menuItem; } @@ -309,7 +309,8 @@ export class Menu { private highlightHelper(startIndex: number, delta: number) { let index = startIndex + delta; let menuItem; - while ((menuItem = this.menuItems[index])) { + const items = this.getMenuItems(); + while ((menuItem = items[index])) { if (menuItem.isEnabled()) { this.setHighlighted(menuItem); break; @@ -459,4 +460,13 @@ export class Menu { menuSize.height = menuDom.scrollHeight; return menuSize; } + + /** + * Returns the action menu items (omitting separators) in this menu. + * + * @returns The MenuItem objects displayed in this menu. + */ + private getMenuItems(): MenuItem[] { + return this.menuItems.filter((item) => item instanceof MenuItem); + } } diff --git a/core/menu_separator.ts b/core/menu_separator.ts new file mode 100644 index 000000000..6f7f468ad --- /dev/null +++ b/core/menu_separator.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as aria from './utils/aria.js'; + +/** + * Representation of a section separator in a menu. + */ +export class MenuSeparator { + /** + * DOM element representing this separator in a menu. + */ + private element: HTMLHRElement | null = null; + + /** + * Creates the DOM representation of this separator. + * + * @returns An
element. + */ + createDom(): HTMLHRElement { + this.element = document.createElement('hr'); + this.element.className = 'blocklyMenuSeparator'; + aria.setRole(this.element, aria.Role.SEPARATOR); + + return this.element; + } + + /** + * Disposes of this separator. + */ + dispose() { + this.element?.remove(); + this.element = null; + } +} diff --git a/core/utils/aria.ts b/core/utils/aria.ts index 567ea95ef..8089298e4 100644 --- a/core/utils/aria.ts +++ b/core/utils/aria.ts @@ -48,6 +48,9 @@ export enum Role { // ARIA role for a tree item that sometimes may be expanded or collapsed. TREEITEM = 'treeitem', + + // ARIA role for a visual separator in e.g. a menu. + SEPARATOR = 'separator', } /**