question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

nested validation stacks break because they've already been normalized

See original GitHub issue

Do you want to request a feature or report a bug?

Bug.

What’s the current behavior?

If you write a custom normalize function for a schema, and it happens to do something like change.moveNodeByKey, there’s a chance that calling that change method will initialize its own validation stack, fixing problems that the parent validation stack assumes are still there.

For example, consider that you have two child text nodes adjacent to each other, which is invalid in Slate. If in your normalize function you make any change to the parent of those text nodes, that change will end up normalizing internally, and the text nodes will be combined. However, the parent validation stack still thinks that an invalid rule that needs to be fixed, so it tries to normalize them again, and fails.

What’s the expected behavior?

Not sure.

The ideal would be to prevent the double-checking from happening. I haven’t dug into this yet, so I’m not sure if it’s impossible to do or not.

Another option would be to automatically pass options.normalize: false to all change methods called while performing a validations. The “core” validateNode handlers already do this automatically. But this feels like it might be too magic-y?

Have others run into this? Thoughts?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:15 (13 by maintainers)

github_iconTop GitHub Comments

1reaction
ianstormtaylorcommented, Aug 28, 2018

This can be solved by using deferNormalization, in combination with improvements to the performance from https://github.com/ianstormtaylor/slate/issues/2136.

1reaction
alanchrtcommented, Nov 11, 2017

Pretty sure I’m running into this with wrapBlockByKey. Here’s an example trace (pardon webpack indirection) that shows the multiple normalization passes with wrapBlockByKey calling moveNodeByKey internally. In the trace, it’s isolated down to a single schema rule and a single validation failure:

Uncaught Error: Could not find a node with key "3".
    at Document.assertNode (http://localhost:3000/static/js/bundle.js:204111:15)
    at Document.getPath (http://localhost:3000/static/js/bundle.js:205363:24)
    at Document.object.(anonymous function) [as getPath] (http://localhost:3000/static/js/bundle.js:210941:30)
    at ./node_modules/slate/lib/changes/by-key.js.Changes.mergeNodeByKey (http://localhost:3000/static/js/bundle.js:199649:23)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as mergeNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at http://localhost:3000/static/js/bundle.js:201370:16
    at List.__iterate (http://localhost:3000/static/js/bundle.js:30578:13)
    at List.forEach (http://localhost:3000/static/js/bundle.js:32753:19)
    at http://localhost:3000/static/js/bundle.js:201369:26
    at iterate (http://localhost:3000/static/js/bundle.js:201084:5)
    at normalizeNode (http://localhost:3000/static/js/bundle.js:201105:3)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201047:5)
    at _loop (http://localhost:3000/static/js/bundle.js:201020:7)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201042:5)
    at ./node_modules/slate/lib/changes/with-schema.js.Changes.normalizeNodeByKey (http://localhost:3000/static/js/bundle.js:200975:3)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as normalizeNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at ./node_modules/slate/lib/changes/by-key.js.Changes.moveNodeByKey (http://localhost:3000/static/js/bundle.js:199700:12)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as moveNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at ./node_modules/slate/lib/changes/by-key.js.Changes.wrapBlockByKey (http://localhost:3000/static/js/bundle.js:200181:10)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as wrapBlockByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at Object.normalize (http://localhost:3000/static/js/bundle.js:226701:100)
    at http://localhost:3000/static/js/bundle.js:207420:34
    at iterate (http://localhost:3000/static/js/bundle.js:201084:5)
    at normalizeNode (http://localhost:3000/static/js/bundle.js:201105:3)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201047:5)
    at _loop (http://localhost:3000/static/js/bundle.js:201020:7)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201042:5)
    at ./node_modules/slate/lib/changes/with-schema.js.Changes.normalizeNodeByKey (http://localhost:3000/static/js/bundle.js:200975:3)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as normalizeNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at ./node_modules/slate/lib/changes/by-key.js.Changes.moveNodeByKey (http://localhost:3000/static/js/bundle.js:199700:12)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as moveNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at ./node_modules/slate/lib/changes/by-key.js.Changes.wrapBlockByKey (http://localhost:3000/static/js/bundle.js:200181:10)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as wrapBlockByKey] (http://localhost:3000/static/js/bundle.js:202161:15)
    at Object.normalize (http://localhost:3000/static/js/bundle.js:226701:100)
    at http://localhost:3000/static/js/bundle.js:207420:34
    at iterate (http://localhost:3000/static/js/bundle.js:201084:5)
    at normalizeNode (http://localhost:3000/static/js/bundle.js:201105:3)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201047:5)
    at _loop (http://localhost:3000/static/js/bundle.js:201020:7)
    at normalizeNodeAndChildren (http://localhost:3000/static/js/bundle.js:201042:5)
    at ./node_modules/slate/lib/changes/with-schema.js.Changes.normalizeNodeByKey (http://localhost:3000/static/js/bundle.js:200975:3)
    at Change.call (http://localhost:3000/static/js/bundle.js:202102:10)
    at Change.(anonymous function) [as normalizeNodeByKey] (http://localhost:3000/static/js/bundle.js:202161:15)

This is a blocker for some of the more complex operations (most of them) in my schema rules. I can’t seem to find a way around it. Maybe validateNode is best for now on the stuff that may trigger this, until there’s a way to prevent the extra normalization?

I’m not sure how I feel about needing to pass options.normalize: false on every change method (could get redundant). Feels kind of clunky compared to the rest of the lib, especially when chaining lots of methods. Maybe the change object itself could be callable and take a normalize option, then return a new change object internally configured not to normalize when its change methods are called?

So instead of:

change
  .removeTextByKey(textNode.key, 0, length, { normalize: false })
  .setNodeByKey(node.key, 'title', { normalize: false })
  .wrapBlockByKey(node.key, 'folder', { normalize: false }); 

It could be:

change({ normalize: false })
  .removeTextByKey(textNode.key, 0, length)
  .setNodeByKey(node.key, 'title')
  .wrapBlockByKey(node.key, 'folder'); 

But, then, in that case is it not mutating the change object that ultimately gets applied? If it has to be the original change throughout the rule, maybe something semantically along the lines of:

change.pauseNormalization();
change
  .removeTextByKey(textNode.key, 0, length)
  .setNodeByKey(node.key, 'title')
  .wrapBlockByKey(node.key, 'folder');
change.resumeNormalization();

That almost looks like a context manager. Is there syntax for that in js?

It definitely wouldn’t feel too magical to me to have normalization always disabled inside schema rules, if there were a way to still have the nodes undergo internal normalization after the fact. Is that possible? Maybe there would be a way to collect keys where normalizeNodeByKey was called within a schema rule, then attempt to normalize those keys after the rule normalization is finished? Not sure if that could get too weird with the rule normalization already having performed its own changes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

The correct way to normalize time series data - Cross Validated
You should stick to the first approach. Or its variation when you calculate the separate scale for each series. That's a short answer, ......
Read more >
Nested Data Normalization createEntityAdapter - Stack Overflow
This is a tough one to normalize due to the Voter object which lacks an id property of its own. I had to...
Read more >
SQL Database Normalization Techniques - DevCamp
In this guide we're going to talk about database normalization now database ... where we have a user with multiple records so they...
Read more >
Hibernate Validator 8.0.0.Final - Jakarta Bean Validation ...
Validating data is a common task that occurs throughout all application layers, from the presentation to the persistence layer.
Read more >
What frustrates you about MATLAB? #2 - MathWorks
As if the MATLAB linter was available for other editors too! ... But that leaves us with bloat, in the sense that we...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found