scratchblocks-plus 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/LICENSE +19 -0
- package/README.md +193 -0
- package/browser.es.js +8 -0
- package/browser.js +8 -0
- package/build/scratchblocks-plus.min.es.js +12 -0
- package/build/scratchblocks-plus.min.es.js.map +1 -0
- package/build/scratchblocks-plus.min.js +12 -0
- package/build/scratchblocks-plus.min.js.map +1 -0
- package/build/translations-all-es.js +11 -0
- package/build/translations-all-es.js.map +1 -0
- package/build/translations-all.js +11 -0
- package/build/translations-all.js.map +1 -0
- package/build/translations-es.js +11 -0
- package/build/translations-es.js.map +1 -0
- package/build/translations.js +11 -0
- package/build/translations.js.map +1 -0
- package/index.d.ts +297 -0
- package/index.js +229 -0
- package/locales/ab.json +1630 -0
- package/locales/af.json +1630 -0
- package/locales/all.d.ts +108 -0
- package/locales/all.js +161 -0
- package/locales/am.json +1925 -0
- package/locales/an.json +1630 -0
- package/locales/ar.json +1924 -0
- package/locales/ast.json +1630 -0
- package/locales/az.json +1925 -0
- package/locales/be.json +1630 -0
- package/locales/bg.json +1924 -0
- package/locales/bn.json +1630 -0
- package/locales/ca.json +1930 -0
- package/locales/ckb.json +1630 -0
- package/locales/cs.json +1930 -0
- package/locales/cy.json +1929 -0
- package/locales/da.json +1924 -0
- package/locales/de.json +1929 -0
- package/locales/el.json +1931 -0
- package/locales/eo.json +1630 -0
- package/locales/es-419.json +1924 -0
- package/locales/es.json +1929 -0
- package/locales/et.json +1924 -0
- package/locales/eu.json +1924 -0
- package/locales/fa.json +1929 -0
- package/locales/fi.json +1924 -0
- package/locales/fil.json +1631 -0
- package/locales/forums.js +37 -0
- package/locales/fr.json +1929 -0
- package/locales/fy.json +1630 -0
- package/locales/ga.json +1924 -0
- package/locales/gd.json +1929 -0
- package/locales/gl.json +1924 -0
- package/locales/ha.json +1630 -0
- package/locales/he.json +1929 -0
- package/locales/hi.json +1635 -0
- package/locales/hr.json +1929 -0
- package/locales/ht.json +1630 -0
- package/locales/hu.json +1930 -0
- package/locales/hy.json +1630 -0
- package/locales/id.json +1929 -0
- package/locales/is.json +1924 -0
- package/locales/it.json +1929 -0
- package/locales/ja-Hira.json +1637 -0
- package/locales/ja.json +1931 -0
- package/locales/ka.json +1630 -0
- package/locales/kk.json +1632 -0
- package/locales/km.json +1630 -0
- package/locales/ko.json +1924 -0
- package/locales/ku.json +1632 -0
- package/locales/lt.json +1924 -0
- package/locales/lv.json +1924 -0
- package/locales/mi.json +1924 -0
- package/locales/mn.json +1631 -0
- package/locales/nb.json +1929 -0
- package/locales/nl.json +1929 -0
- package/locales/nn.json +1630 -0
- package/locales/nso.json +1630 -0
- package/locales/oc.json +1630 -0
- package/locales/or.json +1631 -0
- package/locales/pl.json +1929 -0
- package/locales/pt-br.json +1924 -0
- package/locales/pt.json +1929 -0
- package/locales/qu.json +1630 -0
- package/locales/rap.json +1632 -0
- package/locales/ro.json +1929 -0
- package/locales/ru.json +1929 -0
- package/locales/sk.json +1924 -0
- package/locales/sl.json +1929 -0
- package/locales/sr.json +1924 -0
- package/locales/sv.json +1924 -0
- package/locales/sw.json +1630 -0
- package/locales/th.json +1924 -0
- package/locales/tn.json +1630 -0
- package/locales/tr.json +1932 -0
- package/locales/uk.json +1924 -0
- package/locales/uz.json +1631 -0
- package/locales/vi.json +1925 -0
- package/locales/xh.json +1630 -0
- package/locales/zh-cn.json +1930 -0
- package/locales/zh-tw.json +1930 -0
- package/locales/zu.json +1918 -0
- package/package.json +81 -0
- package/scratch2/blocks.js +1000 -0
- package/scratch2/draw.js +452 -0
- package/scratch2/filter.js +78 -0
- package/scratch2/index.js +12 -0
- package/scratch2/style.css.js +148 -0
- package/scratch2/style.js +214 -0
- package/scratch3/blocks.js +1134 -0
- package/scratch3/draw.js +334 -0
- package/scratch3/index.js +12 -0
- package/scratch3/style.css.js +280 -0
- package/scratch3/style.js +877 -0
- package/syntax/blocks.js +921 -0
- package/syntax/commands.js +1755 -0
- package/syntax/dropdowns.js +688 -0
- package/syntax/extensions.js +34 -0
- package/syntax/index.js +17 -0
- package/syntax/model.js +566 -0
- package/syntax/syntax.js +1091 -0
package/syntax/blocks.js
ADDED
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
import { extensions, aliasExtensions } from "./extensions.js"
|
|
2
|
+
|
|
3
|
+
// List of classes we're allowed to override.
|
|
4
|
+
|
|
5
|
+
const overrideCategories = [
|
|
6
|
+
"motion",
|
|
7
|
+
"looks",
|
|
8
|
+
"sound",
|
|
9
|
+
"variables",
|
|
10
|
+
"list",
|
|
11
|
+
"events",
|
|
12
|
+
"control",
|
|
13
|
+
"sensing",
|
|
14
|
+
"operators",
|
|
15
|
+
"custom",
|
|
16
|
+
"custom-arg",
|
|
17
|
+
"extension",
|
|
18
|
+
"grey",
|
|
19
|
+
"obsolete",
|
|
20
|
+
...Object.keys(extensions),
|
|
21
|
+
...Object.keys(aliasExtensions),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const overrideShapes = [
|
|
25
|
+
"hat",
|
|
26
|
+
"cap",
|
|
27
|
+
"stack",
|
|
28
|
+
"boolean",
|
|
29
|
+
"reporter",
|
|
30
|
+
"ring",
|
|
31
|
+
"cat",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
// languages that should be displayed right to left
|
|
35
|
+
export const rtlLanguages = ["ar", "ckb", "fa", "he"]
|
|
36
|
+
|
|
37
|
+
// List of commands taken from Scratch
|
|
38
|
+
import scratchCommands from "./commands.js"
|
|
39
|
+
import {
|
|
40
|
+
getDropdowns as getScratchDropdowns,
|
|
41
|
+
getMakeyMakeySequenceDropdowns,
|
|
42
|
+
} from "./dropdowns.js"
|
|
43
|
+
|
|
44
|
+
const inputNumberPat = /%([0-9]+)/
|
|
45
|
+
export const inputPat = /(%[a-zA-Z0-9](?:\.[a-zA-Z0-9]+)?)/
|
|
46
|
+
const inputPatGlobal = new RegExp(inputPat.source, "g")
|
|
47
|
+
export const iconPat = /(@[a-zA-Z]+)/
|
|
48
|
+
const splitPat = new RegExp(`${inputPat.source}|${iconPat.source}| +`, "g")
|
|
49
|
+
|
|
50
|
+
export const hexColorPat = /^#(?:[0-9a-fA-F]{3}){1,2}?$/
|
|
51
|
+
|
|
52
|
+
export function parseInputNumber(part) {
|
|
53
|
+
const m = inputNumberPat.exec(part)
|
|
54
|
+
return m ? +m[1] : 0
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// used for procDefs
|
|
58
|
+
export function parseSpec(spec) {
|
|
59
|
+
const parts = spec.split(splitPat).filter(x => x)
|
|
60
|
+
const inputs = parts.filter(p => inputPat.test(p))
|
|
61
|
+
return { spec: spec, parts: parts, inputs: inputs, hash: hashSpec(spec) }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function hashSpec(spec) {
|
|
65
|
+
return minifyHash(spec.replace(inputPatGlobal, " _ "))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function minifyHash(hash) {
|
|
69
|
+
return hash
|
|
70
|
+
.replace(/_/g, " _ ")
|
|
71
|
+
.replace(/ +/g, " ")
|
|
72
|
+
.replace(/[,%?:]/g, "")
|
|
73
|
+
.replace(/ß/g, "ss")
|
|
74
|
+
.replace(/ä/g, "a")
|
|
75
|
+
.replace(/ö/g, "o")
|
|
76
|
+
.replace(/ü/g, "u")
|
|
77
|
+
.replace(". . .", "...")
|
|
78
|
+
.replace(/^…$/, "...")
|
|
79
|
+
.trim()
|
|
80
|
+
.toLowerCase()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const blocksById = {}
|
|
84
|
+
const allBlocks = scratchCommands.map(def => {
|
|
85
|
+
if (!def.id) {
|
|
86
|
+
if (!def.selector) {
|
|
87
|
+
throw new Error(`Missing ID: ${def.spec}`)
|
|
88
|
+
}
|
|
89
|
+
def.id = `sb2:${def.selector}`
|
|
90
|
+
}
|
|
91
|
+
if (!def.spec) {
|
|
92
|
+
throw new Error(`Missing spec: ${def.id}`)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const info = {
|
|
96
|
+
id: def.id, // Used for Scratch 3 translations
|
|
97
|
+
spec: def.spec, // Used for Scratch 2 translations
|
|
98
|
+
parts: def.spec.split(splitPat).filter(x => x),
|
|
99
|
+
selector: def.selector || `sb3:${def.id}`, // Used for JSON marshalling
|
|
100
|
+
inputs: def.inputs == null ? [] : def.inputs,
|
|
101
|
+
shape: def.shape,
|
|
102
|
+
category: def.category,
|
|
103
|
+
hasLoopArrow: !!def.hasLoopArrow,
|
|
104
|
+
}
|
|
105
|
+
if (blocksById[info.id]) {
|
|
106
|
+
throw new Error(`Duplicate ID: ${info.id}`)
|
|
107
|
+
}
|
|
108
|
+
blocksById[info.id] = info
|
|
109
|
+
return info
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
export const unicodeIcons = {
|
|
113
|
+
"@greenFlag": "⚑",
|
|
114
|
+
"@turnRight": "↻",
|
|
115
|
+
"@turnLeft": "↺",
|
|
116
|
+
"@addInput": "▸",
|
|
117
|
+
"@delInput": "◂",
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const allLanguages = {}
|
|
121
|
+
function loadLanguage(code, language) {
|
|
122
|
+
const blocksByHash = (language.blocksByHash = {})
|
|
123
|
+
|
|
124
|
+
Object.keys(language.commands).forEach(blockId => {
|
|
125
|
+
const nativeSpec = language.commands[blockId]
|
|
126
|
+
const block = blocksById[blockId]
|
|
127
|
+
|
|
128
|
+
const nativeHash = hashSpec(nativeSpec)
|
|
129
|
+
if (!blocksByHash[nativeHash]) {
|
|
130
|
+
blocksByHash[nativeHash] = []
|
|
131
|
+
}
|
|
132
|
+
blocksByHash[nativeHash].push(block)
|
|
133
|
+
|
|
134
|
+
// fallback image replacement, for languages without aliases
|
|
135
|
+
const m = iconPat.exec(block.spec)
|
|
136
|
+
if (m) {
|
|
137
|
+
const image = m[0]
|
|
138
|
+
const hash = nativeHash.replace(hashSpec(image), unicodeIcons[image])
|
|
139
|
+
if (!blocksByHash[hash]) {
|
|
140
|
+
blocksByHash[hash] = []
|
|
141
|
+
}
|
|
142
|
+
blocksByHash[hash].push(block)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
language.nativeAliases = {}
|
|
147
|
+
Object.keys(language.aliases).forEach(alias => {
|
|
148
|
+
const blockId = language.aliases[alias]
|
|
149
|
+
const block = blocksById[blockId]
|
|
150
|
+
if (block === undefined) {
|
|
151
|
+
throw new Error(`Invalid alias '${blockId}'`)
|
|
152
|
+
}
|
|
153
|
+
const aliasHash = hashSpec(alias)
|
|
154
|
+
if (!blocksByHash[aliasHash]) {
|
|
155
|
+
blocksByHash[aliasHash] = []
|
|
156
|
+
}
|
|
157
|
+
blocksByHash[aliasHash].push(block)
|
|
158
|
+
|
|
159
|
+
if (!language.nativeAliases[blockId]) {
|
|
160
|
+
language.nativeAliases[blockId] = []
|
|
161
|
+
}
|
|
162
|
+
language.nativeAliases[blockId].push(alias)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Some English blocks were renamed between Scratch 2 and Scratch 3. Wire them
|
|
166
|
+
// into language.blocksByHash
|
|
167
|
+
Object.keys(language.renamedBlocks || {}).forEach(alt => {
|
|
168
|
+
const id = language.renamedBlocks[alt]
|
|
169
|
+
if (!blocksById[id]) {
|
|
170
|
+
throw new Error(`Unknown ID: ${id}`)
|
|
171
|
+
}
|
|
172
|
+
const block = blocksById[id]
|
|
173
|
+
const hash = hashSpec(alt)
|
|
174
|
+
if (!english.blocksByHash[hash]) {
|
|
175
|
+
english.blocksByHash[hash] = []
|
|
176
|
+
}
|
|
177
|
+
english.blocksByHash[hash].push(block)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
language.nativeDropdowns = {}
|
|
181
|
+
Object.keys(language.dropdowns).forEach(name => {
|
|
182
|
+
const nativeName = language.dropdowns[name].value
|
|
183
|
+
const parents = language.dropdowns[name].parents
|
|
184
|
+
if (!language.nativeDropdowns[nativeName]) {
|
|
185
|
+
language.nativeDropdowns[nativeName] = []
|
|
186
|
+
}
|
|
187
|
+
language.nativeDropdowns[nativeName].push({ id: name, parents: parents })
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
language.code = code
|
|
191
|
+
allLanguages[code] = language
|
|
192
|
+
}
|
|
193
|
+
export function loadLanguages(languages) {
|
|
194
|
+
Object.keys(languages).forEach(code => loadLanguage(code, languages[code]))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export const english = {
|
|
198
|
+
aliases: {
|
|
199
|
+
"turn ccw %1 degrees": "MOTION_TURNLEFT",
|
|
200
|
+
"turn left %1 degrees": "MOTION_TURNLEFT",
|
|
201
|
+
"turn cw %1 degrees": "MOTION_TURNRIGHT",
|
|
202
|
+
"turn right %1 degrees": "MOTION_TURNRIGHT",
|
|
203
|
+
"when flag clicked": "EVENT_WHENFLAGCLICKED",
|
|
204
|
+
"when gf clicked": "EVENT_WHENFLAGCLICKED",
|
|
205
|
+
"when green flag clicked": "EVENT_WHENFLAGCLICKED",
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
renamedBlocks: {
|
|
209
|
+
"say %1 for %2 secs": "LOOKS_SAYFORSECS",
|
|
210
|
+
"think %1 for %2 secs": "LOOKS_THINKFORSECS",
|
|
211
|
+
"play sound %1": "SOUND_PLAY",
|
|
212
|
+
"wait %1 secs": "CONTROL_WAIT",
|
|
213
|
+
clear: "pen.clear",
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
definePrefix: ["define"],
|
|
217
|
+
defineSuffix: [],
|
|
218
|
+
|
|
219
|
+
// For ignoring the lt sign in the "when distance < _" block
|
|
220
|
+
ignorelt: ["when distance"],
|
|
221
|
+
|
|
222
|
+
// Valid arguments to "of" dropdown, for resolving ambiguous situations
|
|
223
|
+
math: [
|
|
224
|
+
"abs",
|
|
225
|
+
"floor",
|
|
226
|
+
"ceiling",
|
|
227
|
+
"sqrt",
|
|
228
|
+
"sin",
|
|
229
|
+
"cos",
|
|
230
|
+
"tan",
|
|
231
|
+
"asin",
|
|
232
|
+
"acos",
|
|
233
|
+
"atan",
|
|
234
|
+
"ln",
|
|
235
|
+
"log",
|
|
236
|
+
"e ^",
|
|
237
|
+
"10 ^",
|
|
238
|
+
],
|
|
239
|
+
|
|
240
|
+
// Language name is needed for the English locale as well
|
|
241
|
+
name: "English",
|
|
242
|
+
|
|
243
|
+
// Valid arguments to "go to" face sensing dropdown, for resolving ambiguous situations
|
|
244
|
+
faceParts: [
|
|
245
|
+
"nose",
|
|
246
|
+
"mouth",
|
|
247
|
+
"left eye",
|
|
248
|
+
"right eye",
|
|
249
|
+
"between eyes",
|
|
250
|
+
"left ear",
|
|
251
|
+
"right ear",
|
|
252
|
+
"top of head",
|
|
253
|
+
],
|
|
254
|
+
|
|
255
|
+
// Valid arguments to "sound effect" dropdown, for resolving ambiguous situations
|
|
256
|
+
soundEffects: ["pitch", "pan left/right"],
|
|
257
|
+
|
|
258
|
+
// Valid arguments to "microbit when" dropdown
|
|
259
|
+
microbitWhen: ["moved", "shaken", "jumped"],
|
|
260
|
+
|
|
261
|
+
// For detecting the "stop" cap / stack block
|
|
262
|
+
osis: ["other scripts in sprite", "other scripts in stage"],
|
|
263
|
+
|
|
264
|
+
dropdowns: {},
|
|
265
|
+
|
|
266
|
+
commands: {},
|
|
267
|
+
}
|
|
268
|
+
allBlocks.forEach(info => {
|
|
269
|
+
english.commands[info.id] = info.spec
|
|
270
|
+
})
|
|
271
|
+
getScratchDropdowns().forEach(info => {
|
|
272
|
+
english.dropdowns[info.id] = {
|
|
273
|
+
value: info.value,
|
|
274
|
+
parents: info.parents || [],
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
english.dropdowns = {
|
|
278
|
+
...english.dropdowns,
|
|
279
|
+
...getMakeyMakeySequenceDropdowns(english.dropdowns),
|
|
280
|
+
"translate.language.am": {
|
|
281
|
+
value: "Amharic",
|
|
282
|
+
parents: ["translate.translateBlock"],
|
|
283
|
+
},
|
|
284
|
+
"translate.language.ar": {
|
|
285
|
+
value: "Arabic",
|
|
286
|
+
parents: ["translate.translateBlock"],
|
|
287
|
+
},
|
|
288
|
+
"translate.language.az": {
|
|
289
|
+
value: "Azerbaijani",
|
|
290
|
+
parents: ["translate.translateBlock"],
|
|
291
|
+
},
|
|
292
|
+
"translate.language.eu": {
|
|
293
|
+
value: "Basque",
|
|
294
|
+
parents: ["translate.translateBlock"],
|
|
295
|
+
},
|
|
296
|
+
"translate.language.bg": {
|
|
297
|
+
value: "Bulgarian",
|
|
298
|
+
parents: ["translate.translateBlock"],
|
|
299
|
+
},
|
|
300
|
+
"translate.language.ca": {
|
|
301
|
+
value: "Catalan",
|
|
302
|
+
parents: ["translate.translateBlock"],
|
|
303
|
+
},
|
|
304
|
+
"translate.language.zh-cn": {
|
|
305
|
+
value: "Chinese (Simplified)",
|
|
306
|
+
parents: ["translate.translateBlock"],
|
|
307
|
+
},
|
|
308
|
+
"translate.language.zh-tw": {
|
|
309
|
+
value: "Chinese (Traditional)",
|
|
310
|
+
parents: ["translate.translateBlock"],
|
|
311
|
+
},
|
|
312
|
+
"translate.language.hr": {
|
|
313
|
+
value: "Croatian",
|
|
314
|
+
parents: ["translate.translateBlock"],
|
|
315
|
+
},
|
|
316
|
+
"translate.language.cs": {
|
|
317
|
+
value: "Czech",
|
|
318
|
+
parents: ["translate.translateBlock"],
|
|
319
|
+
},
|
|
320
|
+
"translate.language.da": {
|
|
321
|
+
value: "Danish",
|
|
322
|
+
parents: ["translate.translateBlock"],
|
|
323
|
+
},
|
|
324
|
+
"translate.language.nl": {
|
|
325
|
+
value: "Dutch",
|
|
326
|
+
parents: ["translate.translateBlock"],
|
|
327
|
+
},
|
|
328
|
+
"translate.language.en": {
|
|
329
|
+
value: "English",
|
|
330
|
+
parents: ["translate.translateBlock"],
|
|
331
|
+
},
|
|
332
|
+
"translate.language.et": {
|
|
333
|
+
value: "Estonian",
|
|
334
|
+
parents: ["translate.translateBlock"],
|
|
335
|
+
},
|
|
336
|
+
"translate.language.fi": {
|
|
337
|
+
value: "Finnish",
|
|
338
|
+
parents: ["translate.translateBlock"],
|
|
339
|
+
},
|
|
340
|
+
"translate.language.fr": {
|
|
341
|
+
value: "French",
|
|
342
|
+
parents: ["translate.translateBlock"],
|
|
343
|
+
},
|
|
344
|
+
"translate.language.gl": {
|
|
345
|
+
value: "Galician",
|
|
346
|
+
parents: ["translate.translateBlock"],
|
|
347
|
+
},
|
|
348
|
+
"translate.language.de": {
|
|
349
|
+
value: "German",
|
|
350
|
+
parents: ["translate.translateBlock"],
|
|
351
|
+
},
|
|
352
|
+
"translate.language.el": {
|
|
353
|
+
value: "Greek",
|
|
354
|
+
parents: ["translate.translateBlock"],
|
|
355
|
+
},
|
|
356
|
+
"translate.language.he": {
|
|
357
|
+
value: "Hebrew",
|
|
358
|
+
parents: ["translate.translateBlock"],
|
|
359
|
+
},
|
|
360
|
+
"translate.language.hu": {
|
|
361
|
+
value: "Hungarian",
|
|
362
|
+
parents: ["translate.translateBlock"],
|
|
363
|
+
},
|
|
364
|
+
"translate.language.is": {
|
|
365
|
+
value: "Icelandic",
|
|
366
|
+
parents: ["translate.translateBlock"],
|
|
367
|
+
},
|
|
368
|
+
"translate.language.id": {
|
|
369
|
+
value: "Indonesian",
|
|
370
|
+
parents: ["translate.translateBlock"],
|
|
371
|
+
},
|
|
372
|
+
"translate.language.ga": {
|
|
373
|
+
value: "Irish",
|
|
374
|
+
parents: ["translate.translateBlock"],
|
|
375
|
+
},
|
|
376
|
+
"translate.language.it": {
|
|
377
|
+
value: "Italian",
|
|
378
|
+
parents: ["translate.translateBlock"],
|
|
379
|
+
},
|
|
380
|
+
"translate.language.ja": {
|
|
381
|
+
value: "Japanese",
|
|
382
|
+
parents: ["translate.translateBlock"],
|
|
383
|
+
},
|
|
384
|
+
"translate.language.ko": {
|
|
385
|
+
value: "Korean",
|
|
386
|
+
parents: ["translate.translateBlock"],
|
|
387
|
+
},
|
|
388
|
+
"translate.language.lv": {
|
|
389
|
+
value: "Latvian",
|
|
390
|
+
parents: ["translate.translateBlock"],
|
|
391
|
+
},
|
|
392
|
+
"translate.language.lt": {
|
|
393
|
+
value: "Lithuanian",
|
|
394
|
+
parents: ["translate.translateBlock"],
|
|
395
|
+
},
|
|
396
|
+
"translate.language.mi": {
|
|
397
|
+
value: "Maori",
|
|
398
|
+
parents: ["translate.translateBlock"],
|
|
399
|
+
},
|
|
400
|
+
"translate.language.nb": {
|
|
401
|
+
value: "Norwegian",
|
|
402
|
+
parents: ["translate.translateBlock"],
|
|
403
|
+
},
|
|
404
|
+
"translate.language.fa": {
|
|
405
|
+
value: "Persian",
|
|
406
|
+
parents: ["translate.translateBlock"],
|
|
407
|
+
},
|
|
408
|
+
"translate.language.pl": {
|
|
409
|
+
value: "Polish",
|
|
410
|
+
parents: ["translate.translateBlock"],
|
|
411
|
+
},
|
|
412
|
+
"translate.language.pt": {
|
|
413
|
+
value: "Portuguese",
|
|
414
|
+
parents: ["translate.translateBlock"],
|
|
415
|
+
},
|
|
416
|
+
"translate.language.ro": {
|
|
417
|
+
value: "Romanian",
|
|
418
|
+
parents: ["translate.translateBlock"],
|
|
419
|
+
},
|
|
420
|
+
"translate.language.ru": {
|
|
421
|
+
value: "Russian",
|
|
422
|
+
parents: ["translate.translateBlock"],
|
|
423
|
+
},
|
|
424
|
+
"translate.language.gd": {
|
|
425
|
+
value: "Scots Gaelic",
|
|
426
|
+
parents: ["translate.translateBlock"],
|
|
427
|
+
},
|
|
428
|
+
"translate.language.sr": {
|
|
429
|
+
value: "Serbian",
|
|
430
|
+
parents: ["translate.translateBlock"],
|
|
431
|
+
},
|
|
432
|
+
"translate.language.sk": {
|
|
433
|
+
value: "Slovak",
|
|
434
|
+
parents: ["translate.translateBlock"],
|
|
435
|
+
},
|
|
436
|
+
"translate.language.sl": {
|
|
437
|
+
value: "Slovenian",
|
|
438
|
+
parents: ["translate.translateBlock"],
|
|
439
|
+
},
|
|
440
|
+
"translate.language.es": {
|
|
441
|
+
value: "Spanish",
|
|
442
|
+
parents: ["translate.translateBlock"],
|
|
443
|
+
},
|
|
444
|
+
"translate.language.sv": {
|
|
445
|
+
value: "Swedish",
|
|
446
|
+
parents: ["translate.translateBlock"],
|
|
447
|
+
},
|
|
448
|
+
"translate.language.th": {
|
|
449
|
+
value: "Thai",
|
|
450
|
+
parents: ["translate.translateBlock"],
|
|
451
|
+
},
|
|
452
|
+
"translate.language.tr": {
|
|
453
|
+
value: "Turkish",
|
|
454
|
+
parents: ["translate.translateBlock"],
|
|
455
|
+
},
|
|
456
|
+
"translate.language.uk": {
|
|
457
|
+
value: "Ukrainian",
|
|
458
|
+
parents: ["translate.translateBlock"],
|
|
459
|
+
},
|
|
460
|
+
"translate.language.vi": {
|
|
461
|
+
value: "Vietnamese",
|
|
462
|
+
parents: ["translate.translateBlock"],
|
|
463
|
+
},
|
|
464
|
+
"translate.language.cy": {
|
|
465
|
+
value: "Welsh",
|
|
466
|
+
parents: ["translate.translateBlock"],
|
|
467
|
+
},
|
|
468
|
+
"translate.language.zu": {
|
|
469
|
+
value: "Zulu",
|
|
470
|
+
parents: ["translate.translateBlock"],
|
|
471
|
+
},
|
|
472
|
+
"text2speech.language.ar": {
|
|
473
|
+
value: "Arabic",
|
|
474
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
475
|
+
},
|
|
476
|
+
"text2speech.language.zh-cn": {
|
|
477
|
+
value: "Chinese (Mandarin)",
|
|
478
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
479
|
+
},
|
|
480
|
+
"text2speech.language.da": {
|
|
481
|
+
value: "Danish",
|
|
482
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
483
|
+
},
|
|
484
|
+
"text2speech.language.nl": {
|
|
485
|
+
value: "Dutch",
|
|
486
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
487
|
+
},
|
|
488
|
+
"text2speech.language.en": {
|
|
489
|
+
value: "English",
|
|
490
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
491
|
+
},
|
|
492
|
+
"text2speech.language.fr": {
|
|
493
|
+
value: "French",
|
|
494
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
495
|
+
},
|
|
496
|
+
"text2speech.language.de": {
|
|
497
|
+
value: "German",
|
|
498
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
499
|
+
},
|
|
500
|
+
"text2speech.language.hi": {
|
|
501
|
+
value: "Hindi",
|
|
502
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
503
|
+
},
|
|
504
|
+
"text2speech.language.is": {
|
|
505
|
+
value: "Icelandic",
|
|
506
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
507
|
+
},
|
|
508
|
+
"text2speech.language.it": {
|
|
509
|
+
value: "Italian",
|
|
510
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
511
|
+
},
|
|
512
|
+
"text2speech.language.ja": {
|
|
513
|
+
value: "Japanese",
|
|
514
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
515
|
+
},
|
|
516
|
+
"text2speech.language.ko": {
|
|
517
|
+
value: "Korean",
|
|
518
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
519
|
+
},
|
|
520
|
+
"text2speech.language.nb": {
|
|
521
|
+
value: "Norwegian",
|
|
522
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
523
|
+
},
|
|
524
|
+
"text2speech.language.pl": {
|
|
525
|
+
value: "Polish",
|
|
526
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
527
|
+
},
|
|
528
|
+
"text2speech.language.pt-br": {
|
|
529
|
+
value: "Portuguese (Brazilian)",
|
|
530
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
531
|
+
},
|
|
532
|
+
"text2speech.language.pt": {
|
|
533
|
+
value: "Portuguese",
|
|
534
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
535
|
+
},
|
|
536
|
+
"text2speech.language.ro": {
|
|
537
|
+
value: "Romanian",
|
|
538
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
539
|
+
},
|
|
540
|
+
"text2speech.language.ru": {
|
|
541
|
+
value: "Russian",
|
|
542
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
543
|
+
},
|
|
544
|
+
"text2speech.language.es": {
|
|
545
|
+
value: "Spanish",
|
|
546
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
547
|
+
},
|
|
548
|
+
"text2speech.language.es-419": {
|
|
549
|
+
value: "Spanish (Latin American)",
|
|
550
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
551
|
+
},
|
|
552
|
+
"text2speech.language.sv": {
|
|
553
|
+
value: "Swedish",
|
|
554
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
555
|
+
},
|
|
556
|
+
"text2speech.language.tr": {
|
|
557
|
+
value: "Turkish",
|
|
558
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
559
|
+
},
|
|
560
|
+
"text2speech.language.cy": {
|
|
561
|
+
value: "Welsh",
|
|
562
|
+
parents: ["text2speech.setLanguageBlock"],
|
|
563
|
+
},
|
|
564
|
+
}
|
|
565
|
+
loadLanguages({ en: english })
|
|
566
|
+
|
|
567
|
+
/*****************************************************************************/
|
|
568
|
+
|
|
569
|
+
function registerCheck(id, func) {
|
|
570
|
+
if (!blocksById[id]) {
|
|
571
|
+
throw new Error(`Unknown ID: ${id}`)
|
|
572
|
+
}
|
|
573
|
+
blocksById[id].accepts = func
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function specialCase(id, func) {
|
|
577
|
+
if (!blocksById[id]) {
|
|
578
|
+
throw new Error(`Unknown ID: ${id}`)
|
|
579
|
+
}
|
|
580
|
+
blocksById[id].specialCase = func
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function disambig(id1, id2, test) {
|
|
584
|
+
registerCheck(id1, (_, children, lang) => {
|
|
585
|
+
return test(children, lang)
|
|
586
|
+
})
|
|
587
|
+
registerCheck(id2, (_, children, lang) => {
|
|
588
|
+
return !test(children, lang)
|
|
589
|
+
})
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
disambig("OPERATORS_MATHOP", "SENSING_OF", (children, lang) => {
|
|
593
|
+
// Operators if math function, otherwise sensing "attribute of" block
|
|
594
|
+
const first = children[0]
|
|
595
|
+
if (!first.isInput) {
|
|
596
|
+
return
|
|
597
|
+
}
|
|
598
|
+
const name = first.value
|
|
599
|
+
return lang.math.includes(name)
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
disambig("SOUND_CHANGEEFFECTBY", "LOOKS_CHANGEEFFECTBY", (children, lang) => {
|
|
603
|
+
// Sound if sound effect, otherwise default to graphic effect
|
|
604
|
+
for (const child of children) {
|
|
605
|
+
if (child.shape === "dropdown") {
|
|
606
|
+
const name = child.value
|
|
607
|
+
for (const effect of lang.soundEffects) {
|
|
608
|
+
if (minifyHash(effect) === minifyHash(name)) {
|
|
609
|
+
return true
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return false
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
disambig("SOUND_SETEFFECTO", "LOOKS_SETEFFECTTO", (children, lang) => {
|
|
618
|
+
// Sound if sound effect, otherwise default to graphic effect
|
|
619
|
+
for (const child of children) {
|
|
620
|
+
if (child.shape === "dropdown") {
|
|
621
|
+
const name = child.value
|
|
622
|
+
for (const effect of lang.soundEffects) {
|
|
623
|
+
if (minifyHash(effect) === minifyHash(name)) {
|
|
624
|
+
return true
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return false
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
disambig("DATA_LENGTHOFLIST", "OPERATORS_LENGTH", (children, _lang) => {
|
|
633
|
+
// List block if dropdown, otherwise operators
|
|
634
|
+
const last = children[children.length - 1]
|
|
635
|
+
if (!last.isInput) {
|
|
636
|
+
return
|
|
637
|
+
}
|
|
638
|
+
return last.shape === "dropdown"
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
disambig("DATA_LISTCONTAINSITEM", "OPERATORS_CONTAINS", (children, _lang) => {
|
|
642
|
+
// List block if dropdown, otherwise operators
|
|
643
|
+
const first = children[0]
|
|
644
|
+
if (!first.isInput) {
|
|
645
|
+
return
|
|
646
|
+
}
|
|
647
|
+
return first.shape === "dropdown"
|
|
648
|
+
})
|
|
649
|
+
|
|
650
|
+
disambig("pen.setColor", "pen.setHue", (children, _lang) => {
|
|
651
|
+
// Color block if color input, otherwise numeric
|
|
652
|
+
const last = children[children.length - 1]
|
|
653
|
+
// If variable, assume color input, since the RGBA hack is common.
|
|
654
|
+
// TODO fix Scratch :P
|
|
655
|
+
return (last.isInput && last.isColor) || last.isBlock
|
|
656
|
+
})
|
|
657
|
+
|
|
658
|
+
disambig("faceSensing.goToPart", "MOTION_GOTO", (children, lang) => {
|
|
659
|
+
// Face sensing if face part, otherwise default to motion block
|
|
660
|
+
for (const child of children) {
|
|
661
|
+
if (child.shape === "dropdown") {
|
|
662
|
+
const name = child.value
|
|
663
|
+
for (const effect of lang.faceParts) {
|
|
664
|
+
if (minifyHash(effect) === minifyHash(name)) {
|
|
665
|
+
return true
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return false
|
|
671
|
+
})
|
|
672
|
+
|
|
673
|
+
disambig("microbit.whenGesture", "gdxfor.whenGesture", (children, lang) => {
|
|
674
|
+
for (const child of children) {
|
|
675
|
+
if (child.shape === "dropdown") {
|
|
676
|
+
const name = child.value
|
|
677
|
+
// Yes, "when shaken" gdxfor block exists. But microbit is more common.
|
|
678
|
+
for (const effect of lang.microbitWhen) {
|
|
679
|
+
if (minifyHash(effect) === minifyHash(name)) {
|
|
680
|
+
return true
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return false
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
// This block does not need disambiguation in English;
|
|
689
|
+
// however, many other languages do require that.
|
|
690
|
+
disambig("ev3.buttonPressed", "microbit.isButtonPressed", (children, _lang) => {
|
|
691
|
+
for (const child of children) {
|
|
692
|
+
if (child.shape === "dropdown") {
|
|
693
|
+
// EV3 "button pressed" block uses numeric identifier
|
|
694
|
+
// and does not support "any".
|
|
695
|
+
switch (minifyHash(child.value)) {
|
|
696
|
+
case "1":
|
|
697
|
+
case "2":
|
|
698
|
+
case "3":
|
|
699
|
+
case "4":
|
|
700
|
+
return true
|
|
701
|
+
default:
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return false
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
specialCase("CONTROL_STOP", (_, children, lang) => {
|
|
709
|
+
// Cap block unless argument is "other scripts in sprite"
|
|
710
|
+
const last = children[children.length - 1]
|
|
711
|
+
if (!last.isInput) {
|
|
712
|
+
return
|
|
713
|
+
}
|
|
714
|
+
const value = last.value
|
|
715
|
+
if (lang.osis.includes(value)) {
|
|
716
|
+
return { ...blocksById.CONTROL_STOP, shape: "stack" }
|
|
717
|
+
}
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
function narrowByNativeDropdowns(collisions, children, languages) {
|
|
721
|
+
const dropdownValues = []
|
|
722
|
+
for (const child of children) {
|
|
723
|
+
if (!child) {
|
|
724
|
+
continue
|
|
725
|
+
}
|
|
726
|
+
const shape = child.shape || ""
|
|
727
|
+
if (shape.endsWith("dropdown") || shape === "dropdown") {
|
|
728
|
+
if (child.value != null) {
|
|
729
|
+
dropdownValues.push(child.value)
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (!dropdownValues.length) {
|
|
734
|
+
return collisions
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Preprocess: build a map value -> concatenated list of dropdown entry strings
|
|
738
|
+
const valueEntriesMap = new Map()
|
|
739
|
+
for (const lang of languages) {
|
|
740
|
+
for (const val of dropdownValues) {
|
|
741
|
+
if (
|
|
742
|
+
lang.nativeDropdowns &&
|
|
743
|
+
Object.prototype.hasOwnProperty.call(lang.nativeDropdowns, val)
|
|
744
|
+
) {
|
|
745
|
+
const arr = lang.nativeDropdowns[val]
|
|
746
|
+
if (arr && arr.length) {
|
|
747
|
+
if (!valueEntriesMap.has(val)) {
|
|
748
|
+
valueEntriesMap.set(val, [])
|
|
749
|
+
}
|
|
750
|
+
// arr: [{ id, parents }] ; merge (keep duplicates harmless)
|
|
751
|
+
valueEntriesMap.get(val).push(...arr)
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (!valueEntriesMap.size) {
|
|
757
|
+
return collisions
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const filtered = collisions.filter(block => {
|
|
761
|
+
const candidates = [
|
|
762
|
+
block.id,
|
|
763
|
+
block.selector && block.selector.replace(/^sb3:/, ""),
|
|
764
|
+
block.selector,
|
|
765
|
+
].filter(Boolean)
|
|
766
|
+
for (const entries of valueEntriesMap.values()) {
|
|
767
|
+
for (const entry of entries) {
|
|
768
|
+
if (!entry) {
|
|
769
|
+
continue
|
|
770
|
+
}
|
|
771
|
+
// entry can be { id, parents } per loadLanguage(); parents may be undefined
|
|
772
|
+
const parents = Array.isArray(entry.parents) ? entry.parents : []
|
|
773
|
+
// If any parent matches the block id/selector, keep it
|
|
774
|
+
if (parents.some(p => candidates.includes(p))) {
|
|
775
|
+
return true
|
|
776
|
+
}
|
|
777
|
+
// Fallback: some (older) data could have stored id as parent indicator
|
|
778
|
+
if (entry.id && candidates.includes(entry.id)) {
|
|
779
|
+
return true
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return false
|
|
784
|
+
})
|
|
785
|
+
return filtered.length ? filtered : collisions
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
export function lookupHash(hash, info, children, languages, overrides) {
|
|
789
|
+
for (const lang of languages) {
|
|
790
|
+
if (Object.prototype.hasOwnProperty.call(lang.blocksByHash, hash)) {
|
|
791
|
+
let collisions = lang.blocksByHash[hash]
|
|
792
|
+
|
|
793
|
+
if (overrides && overrides.length) {
|
|
794
|
+
// 1) Highest priority: If a value in overrides matches a category in collisions uniquely, return it directly
|
|
795
|
+
const collisionCategories = new Set(
|
|
796
|
+
collisions.map(b => b.category).filter(Boolean),
|
|
797
|
+
)
|
|
798
|
+
for (const o of overrides) {
|
|
799
|
+
if (!o) {
|
|
800
|
+
continue
|
|
801
|
+
}
|
|
802
|
+
// Only process if the override appears in the current collision category set
|
|
803
|
+
if (collisionCategories.has(o)) {
|
|
804
|
+
const matching = collisions.filter(b => b.category === o)
|
|
805
|
+
if (matching.length === 1) {
|
|
806
|
+
const block = matching[0]
|
|
807
|
+
// Keep shape filtering consistent with subsequent logic
|
|
808
|
+
if (
|
|
809
|
+
(info.shape === "reporter" &&
|
|
810
|
+
block.shape !== "reporter" &&
|
|
811
|
+
block.shape !== "ring") ||
|
|
812
|
+
(info.shape === "boolean" && block.shape !== "boolean")
|
|
813
|
+
) {
|
|
814
|
+
// If the shape is incompatible, do not break, continue to try other overrides
|
|
815
|
+
} else {
|
|
816
|
+
return { type: block, lang: lang }
|
|
817
|
+
}
|
|
818
|
+
} else if (matching.length > 1) {
|
|
819
|
+
// Multiple same categories, narrow down the collision range, continue further refinement
|
|
820
|
+
collisions = matching
|
|
821
|
+
break
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// 2) Secondary: Use the original mechanism, identify the first override in the allowed override category list
|
|
827
|
+
const categoryOverride = overrides.find(o =>
|
|
828
|
+
overrideCategories.includes(o),
|
|
829
|
+
)
|
|
830
|
+
if (categoryOverride) {
|
|
831
|
+
const filtered = collisions.filter(
|
|
832
|
+
b => b.category === categoryOverride,
|
|
833
|
+
)
|
|
834
|
+
if (filtered.length) {
|
|
835
|
+
// If only one remains, return it directly; otherwise, continue normal disambiguation
|
|
836
|
+
if (filtered.length === 1) {
|
|
837
|
+
return { type: filtered[0], lang: lang }
|
|
838
|
+
}
|
|
839
|
+
collisions = filtered
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Try to narrow down the collision set using nativeDropdowns
|
|
845
|
+
if (collisions.length > 1) {
|
|
846
|
+
collisions = narrowByNativeDropdowns(collisions, children, languages)
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
for (let block of collisions) {
|
|
850
|
+
if (
|
|
851
|
+
info.shape === "reporter" &&
|
|
852
|
+
block.shape !== "reporter" &&
|
|
853
|
+
block.shape !== "ring"
|
|
854
|
+
) {
|
|
855
|
+
continue
|
|
856
|
+
}
|
|
857
|
+
if (info.shape === "boolean" && block.shape !== "boolean") {
|
|
858
|
+
continue
|
|
859
|
+
}
|
|
860
|
+
if (collisions.length > 1) {
|
|
861
|
+
// Only check in case of collision;
|
|
862
|
+
// perform "disambiguation"
|
|
863
|
+
if (block.accepts && !block.accepts(info, children, lang)) {
|
|
864
|
+
continue
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (block.specialCase) {
|
|
868
|
+
block = block.specialCase(info, children, lang) || block
|
|
869
|
+
}
|
|
870
|
+
return { type: block, lang: lang }
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
export function lookupDropdown(name, parentType, languages) {
|
|
877
|
+
for (const lang of languages) {
|
|
878
|
+
if (Object.prototype.hasOwnProperty.call(lang.nativeDropdowns, name)) {
|
|
879
|
+
const objs = lang.nativeDropdowns[name]
|
|
880
|
+
for (const { id, parents } of objs) {
|
|
881
|
+
if (parents.includes(parentType)) {
|
|
882
|
+
return id
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
export function applyOverrides(info, overrides) {
|
|
890
|
+
for (const name of overrides) {
|
|
891
|
+
if (hexColorPat.test(name)) {
|
|
892
|
+
info.color = name
|
|
893
|
+
info.category = ""
|
|
894
|
+
info.categoryIsDefault = false
|
|
895
|
+
} else if (overrideCategories.includes(name)) {
|
|
896
|
+
info.category = name
|
|
897
|
+
info.categoryIsDefault = false
|
|
898
|
+
} else if (overrideShapes.includes(name)) {
|
|
899
|
+
info.shape = name
|
|
900
|
+
info.shapeIsDefault = false
|
|
901
|
+
} else if (name === "loop") {
|
|
902
|
+
info.hasLoopArrow = true
|
|
903
|
+
} else if (name === "+" || name === "-") {
|
|
904
|
+
info.diff = name
|
|
905
|
+
} else if (name === "reset") {
|
|
906
|
+
info.categoryIsDefault = false
|
|
907
|
+
info.isReset = true
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
export function blockName(block) {
|
|
913
|
+
const words = []
|
|
914
|
+
for (const child of block.children) {
|
|
915
|
+
if (!child.isLabel) {
|
|
916
|
+
return
|
|
917
|
+
}
|
|
918
|
+
words.push(child.value)
|
|
919
|
+
}
|
|
920
|
+
return words.join(" ")
|
|
921
|
+
}
|