Elderjs / elderjs

Elder.js is an opinionated static site generator and web framework for Svelte built with SEO in mind.

Home Page:https://elderguide.com/tech/elderjs/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Catastrophic backtracking bug

eight04 opened this issue · comments

commented

/<(\S+) class="ejs-component[^]*?" data-ejs-component="([A-Za-z]+)" data-ejs-props="({[^]*?})" data-ejs-options="({[^]*?})"><\/\1>/gim,

This runs forever when:

  1. There are many ejs components.
  2. The last item <\/\1> doesn't match.

This happens naturally when there is another tag stick with ejs component. Here is an example:

<p><div class="ejs-component" data-ejs-component="Fumen" data-ejs-props="{blabla}" data-ejs-options="{blabla}"></div>
... and more ejs components ...
  1. The first capturing group matches p><div.
  2. The last item </p><div> can't match </div> in the file.
  3. All [^]*? expand down to the entire file.
  4. Still doesn't match. So it backtracks and test the previous [^]*? down to the entire file...

I think it will be better to write it as:

 /<([^<]+) class="ejs-component[^"]*" data-ejs-component="([A-Za-z]+)" data-ejs-props="({[^"]*})" data-ejs-options="({[^"]*})"><\/\1>/gim

Ensure that:

  1. The last item is a valid tag.
  2. Even if the last item doesn't match, it doesn't expand down to the entire file.

After the fix, the build time reduces from 5 minutes to 9 seconds.

commented

After changing the regex, I found that some tests failed:

mountComponentsInHtml.default({
page,
html: `<div class="svelte-datepicker"><div class="ejs-component" data-ejs-component="Datepicker" data-ejs-props="{ "a": "b" }" data-ejs-options="{ "loading": "lazy" }"></div></div>`,
hydrateOptions: undefined,
});
expect(hydrated).toEqual(['{"name":"Datepicker","props":{"a":"b"},"hydrateOptions":{"loading":"lazy"}}']);

It this a valid use case? While debugging the server, I saw data like " were encoded into &quote; to produce valid HTML. But the test file doesn't seem to quote them. It is not valid svelte syntax either.