Skip to content

Commit 0bdae14

Browse files
authored
feat: Add a JSON Block definition interface (#9613)
1 parent 0efc502 commit 0bdae14

3 files changed

Lines changed: 161 additions & 10 deletions

File tree

packages/blockly/core/block.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,8 +1721,8 @@ export class Block {
17211721

17221722
// Validate that each arg has a corresponding message
17231723
let n = 0;
1724-
while (json['args' + n]) {
1725-
if (json['message' + n] === undefined) {
1724+
while (json[`args${n}`]) {
1725+
if (json[`message${n}`] === undefined) {
17261726
throw Error(
17271727
warningPrefix +
17281728
`args${n} must have a corresponding message (message${n}).`,
@@ -1732,14 +1732,13 @@ export class Block {
17321732
}
17331733

17341734
// Set basic properties of block.
1735-
// Makes styles backward compatible with old way of defining hat style.
1736-
if (json['style'] && json['style'].hat) {
1737-
this.hat = json['style'].hat;
1735+
// Handle legacy style object format for backwards compatibility
1736+
if (json['style'] && typeof json['style'] === 'object') {
1737+
this.hat = (json['style'] as {hat?: string}).hat;
17381738
// Must set to null so it doesn't error when checking for style and
17391739
// colour.
17401740
json['style'] = null;
17411741
}
1742-
17431742
if (json['style'] && json['colour']) {
17441743
throw Error(warningPrefix + 'Must not have both a colour and a style.');
17451744
} else if (json['style']) {
@@ -1750,12 +1749,12 @@ export class Block {
17501749

17511750
// Interpolate the message blocks.
17521751
let i = 0;
1753-
while (json['message' + i] !== undefined) {
1752+
while (json[`message${i}`] !== undefined) {
17541753
this.interpolate(
1755-
json['message' + i],
1756-
json['args' + i] || [],
1754+
json[`message${i}`] || '',
1755+
json[`args${i}`] || [],
17571756
// Backwards compatibility: lastDummyAlign aliases implicitAlign.
1758-
json['implicitAlign' + i] || json['lastDummyAlign' + i],
1757+
json[`implicitAlign${i}`] || (json as any)[`lastDummyAlign${i}`],
17591758
warningPrefix,
17601759
);
17611760
i++;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {FieldCheckboxFromJsonConfig} from '../field_checkbox.js';
8+
import {FieldDropdownFromJsonConfig} from '../field_dropdown';
9+
import {FieldImageFromJsonConfig} from '../field_image';
10+
import {FieldNumberFromJsonConfig} from '../field_number';
11+
import {FieldTextInputFromJsonConfig} from '../field_textinput';
12+
import {FieldVariableFromJsonConfig} from '../field_variable';
13+
import {Align} from '../inputs/align.js';
14+
15+
/**
16+
* Defines the JSON structure for a block definition.
17+
*
18+
* @example
19+
* ```typescript
20+
* const blockDef: JsonBlockDefinition = {
21+
* type: 'custom_block',
22+
* message0: 'move %1 steps',
23+
* args0: [
24+
* {
25+
* 'type': 'field_number',
26+
* 'name': 'INPUT',
27+
* },
28+
* ],
29+
* previousStatement: null,
30+
* nextStatement: null,
31+
* };
32+
* ```
33+
*/
34+
export interface JsonBlockDefinition {
35+
type: string;
36+
style?: string | null;
37+
colour?: string | number;
38+
output?: string | string[] | null;
39+
previousStatement?: string | string[] | null;
40+
nextStatement?: string | string[] | null;
41+
outputShape?: number;
42+
inputsInline?: boolean;
43+
tooltip?: string;
44+
helpUrl?: string;
45+
extensions?: string[];
46+
mutator?: string;
47+
enableContextMenu?: boolean;
48+
suppressPrefixSuffix?: boolean;
49+
50+
[key: `message${number}`]: string | undefined;
51+
[key: `args${number}`]: JsonBlockArg[] | undefined;
52+
[key: `implicitAlign${number}`]: string | undefined;
53+
}
54+
55+
export type JsonBlockArg =
56+
| InputValueArg
57+
| InputStatementArg
58+
| InputDummyArg
59+
| InputEndRowArg
60+
| FieldInputArg
61+
| FieldNumberArg
62+
| FieldDropdownArg
63+
| FieldCheckboxArg
64+
| FieldImageArg
65+
| FieldVariableArg
66+
| UnknownArg;
67+
68+
interface UnknownArg {
69+
type: string;
70+
[key: string]: unknown;
71+
}
72+
73+
/** Input args */
74+
interface InputValueArg {
75+
type: 'input_value';
76+
name?: string;
77+
check?: string | string[];
78+
align?: Align;
79+
}
80+
81+
interface InputStatementArg {
82+
type: 'input_statement';
83+
name?: string;
84+
check?: string | string[];
85+
}
86+
87+
interface InputDummyArg {
88+
type: 'input_dummy';
89+
name?: string;
90+
}
91+
92+
interface InputEndRowArg {
93+
type: 'input_end_row';
94+
name?: string;
95+
}
96+
97+
/** Field args */
98+
interface FieldInputArg extends FieldTextInputFromJsonConfig {
99+
type: 'field_input';
100+
name?: string;
101+
}
102+
103+
interface FieldNumberArg extends FieldNumberFromJsonConfig {
104+
type: 'field_number';
105+
name?: string;
106+
}
107+
108+
interface FieldDropdownArg extends FieldDropdownFromJsonConfig {
109+
type: 'field_dropdown';
110+
name?: string;
111+
}
112+
113+
interface FieldCheckboxArg extends FieldCheckboxFromJsonConfig {
114+
type: 'field_checkbox';
115+
name?: string;
116+
}
117+
118+
interface FieldImageArg extends FieldImageFromJsonConfig {
119+
type: 'field_image';
120+
name?: string;
121+
}
122+
123+
interface FieldVariableArg extends FieldVariableFromJsonConfig {
124+
type: 'field_variable';
125+
name?: string;
126+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {defineBlocksWithJsonArray} from 'blockly-test/core';
8+
import type {JsonBlockDefinition} from 'blockly-test/core/interfaces/i_json_block_definition';
9+
10+
import './different_user_input';
11+
12+
const mitosisBlockDefinition: JsonBlockDefinition = {
13+
type: 'mitosis_block',
14+
message0: 'split cell %1',
15+
args0: [
16+
{
17+
type: 'field_mitosis',
18+
name: 'CELL',
19+
cellId: 'cell-A',
20+
},
21+
],
22+
previousStatement: null,
23+
nextStatement: null,
24+
};
25+
26+
defineBlocksWithJsonArray([mitosisBlockDefinition]);

0 commit comments

Comments
 (0)