@protorobotics/jenga 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
File without changes
package/README.md ADDED
File without changes
package/jenga.js ADDED
@@ -0,0 +1,213 @@
1
+ import { Block, CodeGenerator, common, Field, Toolbox } from "blockly";
2
+
3
+ /**
4
+ * @typedef {object} Category
5
+ * @property {string} name The name of the category.
6
+ * @property {string} color CSS color for the category.
7
+ * @property {Entry[]} entries The entries in the category.
8
+ */
9
+
10
+ /**
11
+ * @typedef {object} Entry
12
+ * @property {string} name The name of the entry.
13
+ * @property {string} description Description of the entry.
14
+ * @property {BlocklyField[]} blocklyTemplate The template used to make the blockly block.
15
+ * @property {BlocklyIOConnection?} blocklyInput The input connection for the block.
16
+ * @property {BlocklyIOConnection?} blocklyOutput The output connection for the block.
17
+ * @property {CodeGenFunction} codeGenerator The code generator function used by blockly.
18
+ */
19
+
20
+ /**
21
+ * @typedef {object} BlocklyField
22
+ * @property {string?} name The name of the field.
23
+ * @property {Field?} field The blockly field object.
24
+ * @property {string?} text Text displayed in place of the field.
25
+ */
26
+
27
+ /**
28
+ * @typedef {object} BlocklyIOConnection
29
+ * @property {BlocklyType} type The type of the connection.
30
+ * @property {string} name The name of the connection.
31
+ */
32
+
33
+ // TODO: define vocab objects
34
+
35
+ /**
36
+ * @enum {string}
37
+ */
38
+ const BlocklyType = {
39
+ bool: "Boolean",
40
+ // TODO: Add other types
41
+ };
42
+
43
+ /**
44
+ * @callback CodeGenFunction
45
+ * @param {Block} block The blockly block.
46
+ * @returns {string} The generated code.
47
+ */
48
+
49
+ /**
50
+ * Processes a collection of categories to produce a blockly toolbox and a
51
+ * function vocabulary.
52
+ * @param {Category[]} categories The categories from which everything is built.
53
+ * @param {CodeGenerator} generator The blockly code generator.
54
+ * @returns {{toolbox: Toolbox, vocab: Vocabulary}} The generated structures.
55
+ */
56
+ export function process(categories, generator) {
57
+ const blocklyCategories = [];
58
+
59
+ for (const category of categories) {
60
+ // TODO: add vocab functions
61
+ const blocklyCategory = initBlocklyCategory(category);
62
+ blocklyCategories.push(blocklyCategory);
63
+
64
+ for (const entry of category.entries) {
65
+ const blocklyBlock = initBlocklyBlock(entry, category, generator);
66
+ blocklyCategory.contents.push(blocklyBlock);
67
+ }
68
+ }
69
+
70
+ const toolbox = initBlocklyToolbox(blocklyCategories);
71
+
72
+ return { toolbox: toolbox, vocab: null };
73
+ }
74
+
75
+ /**
76
+ * @param {Category} category The category.
77
+ * @returns {{kind: string, name: string, colour: string, contents: object[]}} The blockly category.
78
+ */
79
+ function initBlocklyCategory(category) {
80
+ return {
81
+ kind: "category",
82
+ name: category.name,
83
+ colour: category.color || "#000000",
84
+ contents: [],
85
+ };
86
+ }
87
+
88
+ /**
89
+ * @param {Entry} entry The entry.
90
+ * @param {Category} category The category that contains the entry.
91
+ * @param {CodeGenerator} generator The blockly code generator.
92
+ * @returns {{kind: string, type: string}} The blockly category entry.
93
+ */
94
+ function initBlocklyBlock(entry, category, generator) {
95
+ const blockDefinition = {
96
+ init: function () {
97
+ const inputConn = entry.blocklyInput;
98
+ const rootInput = !inputConn
99
+ ? this.appendDummyInput()
100
+ : this.appendValueInput(inputConn.name).setCheck(inputConn.type);
101
+
102
+ for (const field of entry.blocklyTemplate) {
103
+ if (field.text) {
104
+ // Plain text
105
+ rootInput.appendField(field.text);
106
+ } else {
107
+ // Additional user input
108
+ rootInput.appendField(field.field, field.name);
109
+ }
110
+ }
111
+
112
+ const outputConn = entry.blocklyOutput;
113
+ if (!outputConn) {
114
+ this.setPreviousStatement(true, null);
115
+ this.setNextStatement(true, null);
116
+ } else {
117
+ this.setOutput(true, outputConn.type);
118
+ }
119
+
120
+ this.setTooltip(entry.description || "");
121
+ this.setHelpUrl("");
122
+ this.setColour(category.color);
123
+ },
124
+ };
125
+
126
+ // Define the block globally
127
+ common.defineBlocks({ [entry.name]: blockDefinition });
128
+ // Add a generator function for the block
129
+ generator.forBlock[entry.name] = entry.codeGenerator;
130
+
131
+ return {
132
+ kind: "block",
133
+ type: entry.name,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * @param {object[]} blocklyCategories The blockly categories to add to the toolbox.
139
+ * @returns {{kind: string, contents: object[]}} The blockly toolbox.
140
+ */
141
+ function initBlocklyToolbox(blocklyCategories) {
142
+ // TODO: filter default categories
143
+ const defaultCategories = [
144
+ {
145
+ kind: "category",
146
+ name: "Flow",
147
+ colour: "#e9a719",
148
+ contents: [
149
+ {
150
+ kind: "block",
151
+ type: "controls_if",
152
+ },
153
+ {
154
+ kind: "block",
155
+ type: "logic_compare",
156
+ },
157
+ {
158
+ kind: "block",
159
+ type: "logic_operation",
160
+ },
161
+ {
162
+ kind: "block",
163
+ type: "logic_negate",
164
+ },
165
+ {
166
+ kind: "block",
167
+ type: "logic_boolean",
168
+ },
169
+ {
170
+ kind: "block",
171
+ type: "controls_repeat_ext",
172
+ inputs: {
173
+ TIMES: {
174
+ block: {
175
+ type: "math_number",
176
+ fields: {
177
+ NUM: 10,
178
+ },
179
+ },
180
+ },
181
+ },
182
+ },
183
+ {
184
+ kind: "block",
185
+ type: "controls_whileUntil",
186
+ },
187
+ ],
188
+ },
189
+ {
190
+ kind: "category",
191
+ name: "Math",
192
+ colour: "#cc44cc",
193
+ contents: [
194
+ {
195
+ kind: "block",
196
+ type: "math_number",
197
+ fields: {
198
+ NUM: 123,
199
+ },
200
+ },
201
+ {
202
+ kind: "block",
203
+ type: "math_arithmetic",
204
+ },
205
+ ],
206
+ },
207
+ ];
208
+
209
+ return {
210
+ kind: "categoryToolbox",
211
+ contents: blocklyCategories.concat(defaultCategories),
212
+ };
213
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@protorobotics/jenga",
3
+ "version": "1.0.0",
4
+ "description": "Build a function vocabulary and a blockly instance from one JSON object",
5
+ "keywords": [
6
+ "blockly",
7
+ "proto"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/proto-robotics/jenga"
12
+ },
13
+ "license": "MIT",
14
+ "author": "PROTO Robotics",
15
+ "type": "commonjs",
16
+ "main": "jenga.js",
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ },
20
+ "dependencies": {
21
+ "blockly": "^12.3.1"
22
+ }
23
+ }