Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: serialize AST node back to wikitext string #8258

Open
wants to merge 79 commits into
base: master
Choose a base branch
from

Conversation

linonetwo
Copy link
Contributor

@linonetwo linonetwo commented Jun 12, 2024

closes #8255

Currently just a demo, I will gradually move code from https://github.com/tiddly-gittly/wikiast/tree/master/packages/wikiast-util-to-wikitext to here.

Try it with tiddler (Well, if official website have share plugin installed, I can put a link here):

AAA test

---

\```js
var match = reEnd.exec(this.parser.source)
\```

end

and run this in console:

$tw.utils.serializeParseTree($tw.wiki.parseTiddler('New Tiddler').tree) 

Copy link

vercel bot commented Jun 12, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
tiddlywiki5 ✅ Ready (Inspect) Visit Preview Jun 12, 2024 5:39pm

@linonetwo linonetwo changed the title Feat/to string feat: serialize AST node back to wikitext string Jun 12, 2024
@pmario
Copy link
Member

pmario commented Jun 13, 2024

The problem here is, that the output of you test does not produce the same rendered HTML output as the original source. See the screenshot.

image

@linonetwo
Copy link
Contributor Author

linonetwo commented Jun 13, 2024

First line is wrapped by a p element, but I haven't find the rule that produce the p element. And there was no p html in the source, so I may need to add some attribute to ast to show this p element is "fake".

Anyway, this is just a demo for API, do you like the API name and their usage? The further task is just adding exports.serailize = xxx to each rule.

@pmario
Copy link
Member

pmario commented Jun 13, 2024

First line is wrapped by a p element, but I haven't find the rule that produce the p element. And there was no p html in the source, so I may need to add some attribute to ast to show this p element is "fake".

IMO the current parser has a "systemic" problem with redundant P-tags, that we probably may need to solve first.

Working around this problem with "fake" elements will just increase your code complexity, instead of solving the underlaying problem. It will also create an other dependency, that will make solving the problem, in the core, in backwards compatible way even harder as it is now.

};

exports.getParser = function(type,options) {
options = $tw.utils.extend({},options);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO your code will throw an RSOD if options is undefined
So options = options || {} should be used instead. We use this pattern all over the places.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copy $tw.utils.extend({},options) from somewhere nearby, I thought this will work.

@linonetwo
Copy link
Contributor Author

redundant P-tags

Can't remove then, many of my plugin style sheet is already depending on this structure. And p > text for block is following HTML5 semantic.

Another option is handle it like text node, regard it as a special case.

@pmario
Copy link
Member

pmario commented Jun 13, 2024

And p > text for block is following HTML5 semantic.

That's true, but we do have a lot of p > div which should not happen at all.

@linonetwo
Copy link
Contributor Author

linonetwo commented Jul 29, 2024

Handle the block rule by adding a rule: 'parseBlock' to WikiParser.prototype.parseBlock.

I've added some test for it.

@linonetwo
Copy link
Contributor Author

@rougsig Use edit button with a "T" in the view toolbar to enter WYSIWYG mode.

@BurningTreeC Those field is added in other PRs, this PR only generate type for them. start end is already in the core.

@linonetwo
Copy link
Contributor Author

how the conditional shortcut syntax is handled

That's why I need this in the core, instead of in a plugin.

@saqimtiaz
Copy link
Member

  • It would also be worth running every wikitext template in the core as test data too

@linonetwo from my perspective this is the missing next step, even if only to understand what if any shortcomings or peculiarities there are in the round trip from wikitext to parse tree and back.

@linonetwo
Copy link
Contributor Author

@saqimtiaz "every wikitext template in the core" contains many "WikiScript" that this API will never meet, but in this PR I only trying to support WikiText cases that WYSIWYG editor will use. Current test cases already cover most of them.

Well, covering all coner cases may enable some creazy use cases like a visual "WikiScript" editor, so I can add the test, but I'm afraid this kind of test will make test very slow.

@saqimtiaz
Copy link
Member

@linonetwo the goal is to better understand what use cases are and are not supported. Running a test using $:/core/ui/PageTemplate would be very informative.

Copy link

netlify bot commented Feb 19, 2025

Deploy Preview for tiddlywiki-previews ready!

Name Link
🔨 Latest commit a97aede
🔍 Latest deploy log https://app.netlify.com/sites/tiddlywiki-previews/deploys/67cdb55e5cf46c00087dc71a
😎 Deploy Preview https://deploy-preview-8258--tiddlywiki-previews.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@linonetwo
Copy link
Contributor Author

linonetwo commented Feb 19, 2025

图片

@saqimtiaz I render it in the view template below text, looks the same, is this what you mean? I will revert this commit before merge. Or you suggest add this test to CI?

@linonetwo linonetwo force-pushed the feat/to-string branch 2 times, most recently from 880c0a5 to dee3132 Compare February 19, 2025 10:05
@linonetwo
Copy link
Contributor Author

linonetwo commented Feb 19, 2025

It takes 5min to run, when limit to non-system tiddlers, on my i9 MacBookPro. But it will cause FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory on netlify deploy...

And if runs for both system tiddlers, it seems takes forever.


And it OOM on my computer. So I update it to only run it on browser. Take a look.

DEBUG: render result below body only on browser

DEBUG: render result below body

DEBUG: fix build

DEBUG: show render result as ViewTemplate
@saqimtiaz
Copy link
Member

@linonetwo I suggest we add a test along the lines of those in https://github.com/TiddlyWiki/TiddlyWiki5/blob/master/editions/test/tiddlers/tests/test-wikitext-parser.js

So for example:

  • render the page template
  • and then serialize the HTML and compare it to the original wikitext

@linonetwo
Copy link
Contributor Author

linonetwo commented Feb 20, 2025

@saqimtiaz This will result in many failed tests. In current preview webpage, you can find it will add or delete some space or \n. And it is very slow, if go through every tiddlers.

I suggest we add a test along the lines of those in editions/test/tiddlers/tests/test-wikitext-serialize.js, do you mean change the file name?

There is already tests in https://github.com/TiddlyWiki/TiddlyWiki5/pull/8258/files#diff-ac833214819c79e6c8b85db9a4bc7cac9e6fcae0bc361f0373f42b514da91e8f

render the page template

What do you mean? This feature only works on wikitext on text field, it doesn't care about rendering. It is ast to wikitext, not wikitext to HTML.

@linonetwo
Copy link
Contributor Author

WYSIWYG editor has been waiting this for too long!

When you are ready, I can revert commit DEBUG: render result and diff below body only on browser. So it can be merged. Before that you can see debug information on preview site.

@linonetwo
Copy link
Contributor Author

linonetwo commented Mar 9, 2025

Could this be merged before next release? WYSIWYG haven't update for nearly 2 years. Now I revert the debug message, so it is ready to merge.

@pmario
Copy link
Member

pmario commented Mar 9, 2025

Why did you also remove the filter: core/modules/filters/serializeparsetree.js -- You should only remove the ViewTemplate. IMO the filter needs to stay. IMO It is needed for debugging.

@linonetwo
Copy link
Contributor Author

linonetwo commented Mar 9, 2025

@pmario I don't like seeing core filters inflate more on my hand. It is only for debugging, no use cases. And this API is mainly for WYSIWYG editor, no many people other than me will use it, and I only use JS api, I will not using filter on this case. Other editor developers will probably only use JS API.

Of course I can add it back if you want to use it on your plugin.

// Return a node representing the comment that is not rendered
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
var commentText = this.parser.source.slice(commentStart, commentEnd);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO those variables are not needed. The code can directly be written into the return object. It is possible to debug the return object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be text: this.parser.source.slice(this.match.index, this.endMatch.index + this.endMatch[0].length), which is redundent and too long. It reuses commentStart

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remove the commentText

// Return a node representing the inline comment
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
var commentText = this.parser.source.slice(commentStart, commentEnd);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. Code should be within the return object. No need for extra variables

var currentMarker = findMarker(node.tag, child.tag);
// Handle class attributes
var classAttr = child.attributes && child.attributes.class ? "." + child.attributes.class.value : "";
// same level text nodes may be split into multiple children, and separated by deeper list sub-tree. We collect same level text nodes into this list, and concat then submit them before enter deeper list.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such a long comment should be split into 2 or more comment lines for easier readability.

title: Serialize/FunctionDefinition
type: text/vnd.tiddlywiki

\function name(param:defaultvalue,param2:defaultvalue)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the core we do have double quotes for parameter values.
IMO it should look like this:

\function name(param:"defaultvalue", param2:"defaultvalue")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pmario
Copy link
Member

pmario commented Mar 9, 2025

Of course I can add it back if you want to use it on your plugin.

The main problem is, that we have no easy to use possibility to test the stuff, if the filter is gone.

I did see your tests. They only contain plain text tiddlers and the test is: editions/test/tiddlers/tests/test-wikitext-serialize.js

That's OK. But it only can be tested using JS API. What we need is a possibility to use the new testcase-widgets to design new tests and also debug the existing tests.

IMO to be able to use the testcase-widget, we do need the filter. So we can do tests like the one you removed.

IMO There should be at least 1 test, that uses core/ui/ViewTemplate/body/default.tid in a testcase test.
For the structure see: https://github.com/TiddlyWiki/TiddlyWiki5/tree/master/editions/test/tiddlers/tests/data/conditionals

@linonetwo
Copy link
Contributor Author

linonetwo commented Mar 9, 2025

@pmario I spend some time tried this, and this is not possible. <$text can't render wikitext as-is. And <<text>> will render the wikitext.

And don't know why but test will wrap the Output with <p> which will break the test.

图片

uses core/ui/ViewTemplate/body/default.tid in a testcase test.

Don't know what you mean, this PR is about turn AST back to wikitext with syntax. Not rendering wikitext or AST into plain text or HTML. So don't need to involve ViewTemplate which is about rendering.

@pmario
Copy link
Member

pmario commented Mar 9, 2025

And don't know why but test will wrap the Output with

which will break the test.

That's a known problem with the current renderer, which needs to be fixed in the future. That's the reason, why all the other tests also have this P tag, in the Expected tiddler.

Don't know what you mean, this PR is about turn AST back to wikitext with syntax. Not rendering wikitext or AST into plain text or HTML. So don't need to involve ViewTemplate which is about rendering.

We do not necessarily use the ViewTemplate. I only want to have a possibility for easy testing without using JavaScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[IDEA] Serailize/toString of AST node
6 participants