-
Notifications
You must be signed in to change notification settings - Fork 3.8k
JSON Block Definition interface #9402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@gonfunko bump, will this be considered? 👀 |
|
Yes, sorry for the delay on this! Will try to get you an initial review this week, thank you for the ping on it. |
gonfunko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks promising; added a couple notes. I'd like to run this by my colleagues before merging, but as you may have seen we're transitioning from Google to the Raspberry Pi Foundation so it may be a couple weeks until things are settled.
| interface CommonArg { | ||
| name?: string; | ||
| } | ||
|
|
||
| /** Input Args */ | ||
| interface InputValueArg extends CommonArg { | ||
| type: 'input_value'; | ||
| check?: string | string[]; | ||
| align?: FieldsAlign | ||
| } | ||
| interface InputStatementArg extends CommonArg { | ||
| type: 'input_statement'; | ||
| check?: string | string[]; | ||
| } | ||
| interface InputDummyArg extends CommonArg { | ||
| type: 'input_dummy'; | ||
| } | ||
|
|
||
| /** Field Args */ | ||
| interface FieldInputArg extends CommonArg{ | ||
| type: 'field_input' | ||
| text: string | ||
| } | ||
|
|
||
| interface FieldNumberArg extends CommonArg { | ||
| type: 'field_number'; | ||
| value?: number; | ||
| min?: number; | ||
| max?: number; | ||
| precision?: number; | ||
| } | ||
|
|
||
| interface FieldDropdownArg extends CommonArg { | ||
| type: 'field_dropdown'; | ||
| options: [string, string][]; | ||
| } | ||
|
|
||
| interface FieldCheckboxArg extends CommonArg { | ||
| type: 'field_checkbox'; | ||
| checked?: boolean | 'TRUE' | 'FALSE'; | ||
| } | ||
|
|
||
| interface FieldImageArg { | ||
| type: 'field_image'; | ||
| src: string; | ||
| width: number; | ||
| height: number; | ||
| alt?: string; | ||
| flipRtl?: boolean | 'TRUE' | 'FALSE'; | ||
| } | ||
|
|
||
| interface FieldVariableArg extends CommonArg { | ||
| type: 'field_variable' | ||
| variable: string | null | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each of the Field classes defines and exports a FieldXYZFromJsonConfig interface, which I think should be used in place of these to avoid duplication/skew.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ohh, didn't know these configs existed 👀
interface FieldInputArg extends FieldTextInputFromJsonConfig {
name: string
type: 'field_input'
}
interface FieldNumberArg extends FieldNumberFromJsonConfig {
name: string
type: 'field_number'
}
// ...wdyt 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gonfunko bump again, hope this finds you well since there was all the migration from google to rpf and stuff 👀
I would definitely want to include your suggested changes, but before I do, can you run this and lmk if it works?
Thanks 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the bump, and yes, we're all moved over and all is well. The approach to the interfaces you proposed in your prior comment makes sense to me, so updating it along those lines sounds good.
|
converted this to draft, will implement @gonfunko's review feedback sooner or later :> |
|
The following new changes have been made:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new JsonBlockDefinition TypeScript interface to provide type safety when defining blocks using JSON, replacing the previous AnyDuringMigration type. The interface defines the structure for JSON block definitions including properties for styling, connections, messages, arguments, and extensions. However, the PR contains several critical bugs related to the removal of 'output': null declarations from getter blocks, which will break their functionality.
Key Changes
- Added
JsonBlockDefinitionandBlockArginterfaces in a new filecore/interfaces/i_json_block_definition.ts - Migrated
jsonInit,jsonInitFactory, and related functions to use the new typed interfaces instead ofAnyDuringMigration - Updated property access from bracket notation to dot notation throughout block initialization code
- Removed explicit
'output': nulland'variable': nulldeclarations from block definitions in theblocks/directory
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| core/interfaces/i_json_block_definition.ts | New interface file defining JsonBlockDefinition and BlockArg types with field and input configuration interfaces |
| core/common.ts | Updated function signatures to use JsonBlockDefinition instead of AnyDuringMigration and changed bracket to dot notation for property access |
| core/block.ts | Updated jsonInit and helper methods to use typed interfaces and dot notation; removed backwards compatibility code for hat styles |
| blocks/variables.ts | Removed 'output': null declaration from variables_get block (critical bug - will break block functionality) |
| blocks/variables_dynamic.ts | Removed 'output': null declaration from variables_get_dynamic block (critical bug - will break block functionality) |
| blocks/loops.ts | Removed 'variable': null declarations from loop variable fields (acceptable change - makes fields truly optional) |
| blocks/logic.ts | Removed 'output': null declarations from logic_null and logic_ternary blocks (critical bugs - will break block functionality) |
Comments suppressed due to low confidence (1)
core/block.ts:1833
- The logic in this function is flawed. The condition checks if json.colour is truthy, but then inside that block it checks if json.colour === undefined. If json.colour is truthy (line 1822), it cannot be undefined (line 1823), making the warning on line 1824 unreachable. The outer check should be 'colour' in json instead of json.colour to properly distinguish between missing and undefined properties.
if (json.colour) {
if (json.colour === undefined) {
console.warn(warningPrefix + 'Undefined colour value.');
} else {
const rawValue = json.colour;
try {
this.setColour(rawValue);
} catch {
console.warn(warningPrefix + 'Illegal colour value: ', rawValue);
}
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (1)
blocks/variables_dynamic.ts:44
- Missing
'output': nullproperty for getter block. Thevariables_get_dynamicblock is a getter that should have an output connection to return a value. The removal of this property is incorrect - getter blocks need an output to be used in expressions. Compare with thevariables_getblock in variables.ts (line 40) which correctly has'output': null.
// Block for variable getter.
{
'type': 'variables_get_dynamic',
'message0': '%1',
'args0': [
{
'type': 'field_variable',
'name': 'VAR',
'variable': '%{BKY_VARIABLES_DEFAULT_NAME}',
},
],
'style': 'variable_dynamic_blocks',
'helpUrl': '%{BKY_VARIABLES_GET_HELPURL}',
'tooltip': '%{BKY_VARIABLES_GET_TOOLTIP}',
'extensions': ['contextMenu_variableDynamicSetterGetter'],
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
blocks/logic.ts
Outdated
|
|
||
| // Register provided blocks. | ||
| defineBlocks(blocks); | ||
| defineBlocks(blocks) |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent code style across block definition files. This file has been reformatted to remove semicolons and use different import/object spacing, but other files in the blocks/ directory (e.g., blocks/lists.ts, blocks/math.ts, blocks/procedures.ts) still use semicolons and the original formatting. This creates inconsistency across the codebase. Either all block files should be reformatted consistently, or this file should maintain the original style to match the rest of the directory.
| defineBlocks(blocks) | |
| defineBlocks(blocks); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
gonfunko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! If you could run npm run format and commit the results that should take care of aligning the formatting with our standards and reduce the diff size substantially.
| import {FieldVariableFromJsonConfig} from '../field_variable'; | ||
|
|
||
| export interface JsonBlockDefinition { | ||
| type?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type should be required; we can't do anything with a block definition that doesn't specify what type of block it's defining.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree, but there are snippets like these which would no longer be accepted, and would require an additional type even though it is is given by assigning blocks itself:
blocks['text_reverse'] = {
/**
* Block for reversing a string.
*/
init: function (this: Block) {
this.jsonInit({
'message0': Msg['TEXT_REVERSE_MESSAGE0'],
'args0': [
{
'type': 'input_value',
'name': 'TEXT',
'check': 'String',
},
],
'output': 'String',
'inputsInline': true,
'style': 'text_blocks',
'tooltip': Msg['TEXT_REVERSE_TOOLTIP'],
'helpUrl': Msg['TEXT_REVERSE_HELPURL'],
});
},
};|
Since @gonfunko is already looking at this I don't think I need to. Seems like the PR assigner rotation thing kinda goofed during the transition, but not a big deal. |
maribethb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the pull request! It's great to make some progress in this area. I think there's more work before this is ready to go in, however.
- This is a promising start for typing the built-in block definitions, but we need developers to be able to customize it more. For example, if a developer has defined a custom input or field, currently with this typing there is no way for them to provide a valid typed json object because
BlockArgtype is not going to include their custom object. We need a solution for this. - Because of (1) I would like to see a test case in
tests/typescriptthat registers a custom block using json that uses the custom field already in that test suite (FieldMitosis) - This is going to be a breaking change for typescript developers if
jsonInitand related methods require their arguments to conform to this type. I think the best path forward would be to include this interface now but leave the arguments to the various init/define functions asAnyDuringMigration, so that developers can go ahead and update their code to use the new type when they want without being required to do so. In the next major release we could then make the breaking change of requiring the types. This would also let us soft-launch the types and test/change them before we require their use. - You've changed from bracket access to dot access in some of the block initialization code, but I think you should revert those changes. The reason for the bracket access is because Blockly is compatible with closure compiler's advanced compilation mode, which does a lot of property renames. The bracket access says not to rename those properties, which is important if your block definitions are not also compiled with closure compiler. Overall I think block definitions are likely to be compiled, unlike, say, the json from a serialized workspace, where it's important we continue to use bracket access. And, I would guess that approximately nobody except blockly-games (which does not even use this version of blockly) is using advanced compilation anyway. At some point we may decide that we don't care about maintaining that compatibility. But for now, I think there is some risk in removing this (however small) and not much upside. So I would recommend that you revert those changes. They are not really relevant to this change anyway.
|
tests for the custom input / fields will be added soon :D |
The basics
The details
Resolves
Implements JSON Block Definition interface proposed in #9387
Proposed Changes
Introduces a new
JsonBlockDefinitionincore/interfaces/core/interfaces/i_json_block_definition.tswithJsonBlockDefinitionandBlockArgdefinitionsBlock.jsonInit,jsonInitFactory,defineBlocksWithJsonArrayandcreateBlockDefinitionsFromJsonArrayto use the new interfaceinterpolateto use the newBlockArgtypeblocks/to explicitly set'output': nullto match the default behaviour in the block factoryAnyDuringMigrationusage for JSON block definitionsReason for Changes
Makes it easier to write valid JSON Block definitions without having to always rely on the block factory
Test Coverage
I ran the unit test suite and manually loaded the playground with the updated blocks to ensure they still render and connect correctly
Documentation
Not needed
Additional Information
I found another issue while testing (unrelated to this) in the default Playground, when
Categories: (typed variables)is selected, the colour category errors out because of an invalidcolour_pickerdefinition