leopard-js / sb-edit

Javascript library for manipulating Scratch project files
MIT License
55 stars 15 forks source link

fromSb3: Peculiarity with pen_menu_colorParam as shadow input (etc?) #144

Closed towerofnix closed 5 months ago

towerofnix commented 6 months ago

Investigating #141.

The basic processing for shadow inputs is to copy the inputs and fields of a shadow input into the parent block:

// In most cases, just copy the shadow block's fields and inputs
// into its parent
result = {
  ...result,
  ...translateInputs(blocks[value].inputs),
  ...translateFields(blocks[value].fields, blocks[value].opcode)
};

This is usually good enough, but there can be discrepancies between the names of inputs/fields on a shadow input and inputs/fields on the parent block. These need to be handled manually and aren't detected by TypeScript.

One such came up with pen_menu_colorParam, which has a strangely camelCased field:

export const fieldTypeMap = {
  ...
  [OpCode.pen_menu_colorParam]: { colorParam: "penColorParam" },
}

pen_menu_colorParam is a CONSTANT_CASED input on two blocks:

export const inputPrimitiveOrShadowMap = {
  ...
  [OpCode.pen_changePenColorParamBy]: { COLOR_PARAM: OpCode.pen_menu_colorParam, VALUE: BIS.MATH_NUM_PRIMITIVE },
  [OpCode.pen_setPenColorParamTo]: { COLOR_PARAM: OpCode.pen_menu_colorParam, VALUE: BIS.MATH_NUM_PRIMITIVE },
};

This results in COLOR_PARAM being undefined (possibly only in certain project.json scenarios), which breaks output formats that expect it to be there. Also a surprise colorParam input existing, of course, which isn't referenced by any output formats (it's not part of the sb-edit intermediate representation).

It would be nice if TypeScript could flag cases like this automatically. Right now inputPrimitiveOrShadowMap isn't typed at all, so it looks like some work could be done here.

towerofnix commented 6 months ago

It turns out pen_menu_colorParam is the only menu (currently implemented by sb-edit) which has this quirk.

towerofnix commented 6 months ago

Tested with sb-edit-playground and this project, no behavior change is needed for toSb3. However, toSb3, like toLeopard, requires the COLOR_INPUT input on Block to be present, and crashes without it. So this fix does affect both output formats.

Sample output with fixed fromSb3 and unmodified toSb3:

"$cZ9-1*N^|Dvl=,7gQ5(-COLOR_PARAM": {
    "opcode": "pen_menu_colorParam",
    "next": null,
    "parent": "$cZ9-1*N^|Dvl=,7gQ5(",
    "fields": {
        "colorParam": ["color"]
    },
    "inputs": {
    },
    "shadow": true,
    "topLevel": false
},

"$cZ9-1*N^|Dvl=,7gQ5(": {
    "opcode": "pen_setPenColorParamTo",
    "parent": "wJIc)f-`T0lDk!j+[VR@",
    "next": ",e]CCiibG}7f}6ZHo3G|",
    "topLevel": false,
    "inputs": {
        "COLOR_PARAM": [1, "$cZ9-1*N^|Dvl=,7gQ5(-COLOR_PARAM"],
        "VALUE": [1, [4, "50"]]
    },
    "fields": {
    },
    "shadow": false
},
towerofnix commented 6 months ago

Also, Leopard's implementation of these component-based pen color blocks is working correctly! 🥳