mo4islona / node-blockly

Blockly for Node.js and Browser via CommonJS module
133 stars 81 forks source link

Error when trying to generate javascript from xml that contains overridden shadows #32

Closed Alexejhero closed 4 years ago

Alexejhero commented 5 years ago

I'm having an issue saving variables with node-blockly. Here is my code:

First attempt (code) ```js const Blockly = require('node-blockly'); var xml = decodeURIComponent(data.req.body.xml); var dom = Blockly.Xml.textToDom(xml); var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(dom, workspace); var js = Blockly.JavaScript.workspaceToCode(workspace); ```

If there are no overridden shadows, the code is generated successfully. But if there are, I get the following error:

First attempt (error) ``` ReferenceError: Element is not defined at Object.module.exports.Blockly.Xml.domToVariables (node_modules\node-blockly\lib\blockly_compressed.js:997:93) at Object.module.exports.Blockly.Xml.domToWorkspace (node_modules\node-blockly\lib\blockly_compressed.js:991:441) at module.exports (src\requests\save.js:45:17) ```

Upon doing some research, I figured out that Element is a DOM interface which is not available in Node.JS, so I installed jsdom and jsdom-global and changed my code to this:

Second attempt (code) ```js const Blockly = require('node-blockly'); require('jsdom-global')(); var xml = decodeURIComponent(data.req.body.xml); var dom = Blockly.Xml.textToDom(xml); var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(dom, workspace); var js = Blockly.JavaScript.workspaceToCode(workspace); ```

This resulted in the following error:

Second attempt (error) ``` Error: Trying to set block style to list_blocks before theme was defined via Blockly.setTheme(). at module.exports.Blockly.Block.setStyle (node_modules\node-blockly\lib\blockly_compressed.js:1465:83) at module.exports.Blockly.Block.init (node_modules\node-blockly\lib\blocks_compressed.js:26:511) at new module.exports.Blockly.Block (node_modules\node-blockly\lib\blockly_compressed.js:1445:428) ```

So then I decided to set the style first, changing my code to this:

Third attempt (code) ```js const Blockly = require('node-blockly'); require('jsdom-global')(); Blockly.setTheme(Blockly.Themes.Classic); var xml = decodeURIComponent(data.req.body.xml); var dom = Blockly.Xml.textToDom(xml); var workspace = new Blockly.Workspace(); Blockly.Xml.domToWorkspace(dom, workspace); var js = Blockly.JavaScript.workspaceToCode(workspace); ```

Which then resulted in this error:

Third attempt (error) ``` TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'. at Object.convert (node_modules\node-blockly\node_modules\jsdom\lib\jsdom\living\generated\Node.js:749:11) at HTMLUnknownElement.appendChild (node_modules\node-blockly\node_modules\jsdom\lib\jsdom\living\generated\Node.js:280:29) at Object.module.exports.Blockly.Xml.blockToDom (node_modules\node-blockly\lib\blockly_compressed.js:12517:54) ```

The error originates from this statement:

Error details ![image](https://user-images.githubusercontent.com/32238504/60759831-02f70f00-a034-11e9-8f1d-92b2b85a4b45.png)

After dome debugging, I saw that the type of the parameter was HTMLUnknownElement.

I've been trying to fix this for a while but have made no progress, so I decided to open this issue.


Running an Express app on Node.JS version 8.15.1

File can be found here: https://github.com/AlexejheroYTB/Dlockly/blob/master/src/requests/save.js

mo4islona commented 5 years ago

First of all, library is already use jsdom in NodeJS env to avoid errors with missing DOM interfaces. Could you give an example of xml that throws error?

Alexejhero commented 5 years ago

I see that JSDOM is required, but still, the Element interface is not defined on the global object.

Anyway, I will provide an example xml shortly.

Alexejhero commented 5 years ago

Actually, I just realized that it may be from one of my custom blocks. I can use variables with default blocks just fine.

Alexejhero commented 5 years ago

Actually, I think I know what this is about. It's about blocks that have OVERRIDDEN SHADOWS


This works just fine:

image

Code ```xml EQ ADD 1 1 2 ```

But this does not:

image

Code ```xml EQ ADD 1 1 1 1 2 ```
Alexejhero commented 5 years ago

To clarify, by "overridden shadows", I mean blocks which have default values (shadows) that have been overridden with other blocks.

mo4islona commented 5 years ago

Please try latest 1.0.38 version

Alexejhero commented 5 years ago

Unfortunately I am unable to test it right now, but I will do so as soon as I can.

Alexejhero commented 5 years ago

Should I try 1.0.38 or 1.0.40?

Alexejhero commented 5 years ago

Tried 1.0.40, still the same error:

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
    at Object.convert (node_modules\jsdom\lib\jsdom\living\generated\Node.js:573:11)
    at HTMLUnknownElement.appendChild (node_modules\jsdom\lib\jsdom\living\generated\Node.js:273:31)
    at Object.module.exports.Blockly.Xml.blockToDom (node_modules\node-blockly\lib\blockly_compressed.js:987:24)
    at Object.module.exports.Blockly.Xml.blockToDom (node_modules\node-blockly\lib\blockly_compressed.js:987:95)
    at Object.module.exports.Blockly.Xml.blockToDom (node_modules\node-blockly\lib\blockly_compressed.js:987:95)
    at new module.exports.Blockly.Events.Create (node_modules\node-blockly\lib\blockly_compressed.js:967:172)
    at Object.module.exports.Blockly.Xml.domToBlock (node_modules\node-blockly\lib\blockly_compressed.js:998:243)
    at Object.module.exports.Blockly.Xml.domToWorkspace (node_modules\node-blockly\lib\blockly_compressed.js:993:13)
    at module.exports (src\requests\save.js:49:17)
Alexejhero commented 5 years ago

If I manually remove the shadow by changing the saved XML, it saves correctly even if I override it.

image

image

Alexejhero commented 5 years ago

Do you have any idea on what could be causing this issue? Could it be blocky itself, or just something with the node version?

Alexejhero commented 5 years ago

Or, are there any workarounds?

Alexejhero commented 5 years ago

I managed to find a workaround for this by manually removing shadow elements if there is a block element present at the same level.

Code ```js function removeOverwrittenShadowsRecursively(obj) { var shadowElement, blockElement; if (obj.elements) { for (var element of obj.elements) { if (element.name == "shadow") shadowElement = element; if (element.name == "block") blockElement = element; } } if (shadowElement && blockElement) removeFromArray(obj.elements, shadowElement); if (obj.elements) { for (var index in obj.elements) { obj.elements[index] = removeOverwrittenShadowsRecursively(obj.elements[index]); } } return obj; } function removeFromArray(arr) { var what, a = arguments, L = a.length, ax; while (L > 1 && arr.length) { what = a[--L]; while ((ax = arr.indexOf(what)) !== -1) { arr.splice(ax, 1); } } return arr; } ```

Nevertheless, this is still an issue that needs to be resolved with node-blockly.

mo4islona commented 4 years ago

I`ve added a test with your xml

https://github.com/mo4islona/node-blockly/blob/master/test/js_test.js#L132

Test are passed. No error. It produce 'if (1 + 1 == 2) {\n}\n' in JS.

Alexejhero commented 4 years ago

I have no idea why this is happening. I will try this with the latest version.

Alexejhero commented 4 years ago

I tried this again with the latest version, but I'm still having the same type error.

Alexejhero commented 4 years ago

Closing this due to inactivity. I haven't had this issue in a long time, although I've been using my script.

curlyz commented 2 years ago

@AlexejheroYTB I got the same problem, can you share how to use your script ? Where can I inject that ?

Alexejhero commented 2 years ago

Damn, it's been a while since I've touched this project. I'll look over it once I get home.