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

[+] [Fix] [Bug] Dollar sign causing rendering issues #2843

Closed
wants to merge 13 commits into from

Conversation

H0llyW00dzZ
Copy link
Contributor

Ref : [Bug] Dollar sign causing rendering issues? #2841

@H0llyW00dzZ H0llyW00dzZ changed the title [Fix] Dollar sign causing rendering issues? #2841 [+] [Fix] [Bug] Dollar sign causing rendering issues Sep 15, 2023
@H0llyW00dzZ
Copy link
Contributor Author

Note:
For other developers, it is recommended to use <Markdown content={mdText} /> instead. If you use <Markdown content={mdText} onClick={copy} />, it will copy all the text in the markdown. This issue with the dollar sign has been fixed in the recent commits.

@a6z6
Copy link
Contributor

a6z6 commented Oct 4, 2023

@H0llyW00dzZ , you did a timely and great job! But I found a bug under iOS 15.x environment:

[Error] SyntaxError: Invalid regular expression: invalid group specifier name

	RegExp
	_MarkDownContent (markdown.tsx:152)
	renderWithHooks (react-dom.development.js:10697)
	updateFunctionComponent (react-dom.development.js:15180)
	callCallback (react-dom.development.js:19443)
	dispatchEvent
	invokeGuardedCallbackImpl (react-dom.development.js:19492)
	invokeGuardedCallback (react-dom.development.js:19567)
	beginWork (react-dom.development.js:25711)
	performUnitOfWork (react-dom.development.js:24540)
	workLoopSync (react-dom.development.js:24256)
	renderRootSync (react-dom.development.js:24211)
	recoverFromConcurrentError (react-dom.development.js:23446)
	performConcurrentWorkOnRoot (react-dom.development.js:23352)
	performConcurrentWorkOnRoot
	workLoop (scheduler.development.js:261)
	flushWork (scheduler.development.js:230)
	performWorkUntilDeadline (scheduler.development.js:537)

The trace stack points to the function you modified in markdown.tsx:

function _MarkDownContent(props: { content: string }) {
  const escapedContent = props.content.replace(
    /(`{3}[\s\S]*?`{3}|`[^`]*`)|(?<!\$)(\$(?!\$))/g,
    (match, codeBlock) => {
      // Exclude code blocks & math block from replacement
      if (codeBlock) {
        return match; // Return the code block as it is
      } else {
        return "&#36;"; // Escape dollar signs outside of code blocks
      }
    },
  );
  return (
...
  );
}

As GPT-4 suggests:

The bug is occurring due to the use of lookbehind assertions in your regular expression. Lookbehind assertions are a relatively new addition to JavaScript and are not supported in all environments. Specifically, they are not supported in iOS until version 14.2. Your regular expression:

/(`{3}[\s\S]*?`{3}|`[^`]*`)|(?<!\$)(\$(?!\$))/g

contains a negative lookbehind assertion (?<!\$). This is likely causing the error you are seeing in iOS 15.

To fix this issue, you will need to refactor your regular expression to not use lookbehind assertions. Unfortunately, JavaScript does not have a straightforward way to replicate the functionality of lookbehind assertions without using them. You may need to adjust your logic to first match and replace code blocks and then separately match and replace dollar signs outside of code blocks.

Here is a possible solution:

function _MarkDownContent(props: { content: string }) {
  let escapedContent = props.content.replace(
    /(`{3}[\s\S]*?`{3}|`[^`]*`)/g,
    (match, codeBlock) => {
      // Exclude code blocks & math block from replacement
      if (codeBlock) {
        return match; // Return the code block as it is
      } else {
        return match.replace(/\$(?!\$)/g, "&#36;"); // Escape dollar signs outside of code blocks
      }
    },
  );
  
  // rest of your code...
}

This code first matches and replaces code blocks, then within those matches that are not code blocks, it replaces dollar signs that are not followed by another dollar sign. It's not exactly the same behavior as your original code, but it might be close enough depending on your exact requirements.

But GPT-4's suggestion does not work at all:

Screenshot 2023-10-04 at 21 59 54

I do not have any solution right now, just provide some information I discovered, hope it helps.

@Yidadaa , did you find any other good work around?

@H0llyW00dzZ
Copy link
Contributor Author

@a6z6, you may need to whitelist user agents depending on the iOS 15.x environment or other iOS versions if you have a correct regex for it. Here is a sample code:

const userAgent = navigator.userAgent.toLowerCase();
const isAppleDevice = /(iphone|ipad|ipod|macintosh)/i.test(userAgent) || (userAgent.includes('mac') && 'ontouchend' in document);

let escapedContent = props.content;
if (isAppleDevice) {                      // custom-regex for unsupported Apple devices
  escapedContent = props.content.replace(/your-custom-regex/g, (match, codeBlock) => {
    // Replace the matched content with your desired replacement
    if (codeBlock) {
      return match; // Return the code block as it is
    } else {
      return "&#36;"; // Escape dollar signs outside of code blocks
    }
  });
} else {
  escapedContent = props.content.replace(/(`{3}[\s\S]*?`{3}|`[^`]*`)|(?<!\$)(\$(?!\$))/g, (match, codeBlock) => {
    // Exclude code blocks & math blocks from replacement
    if (codeBlock) {
      return match; // Return the code block as it is
    } else {
      return "&#36;"; // Escape dollar signs outside of code blocks
    }
  });
}

note that you should replace 'your-custom-regex' with the actual regex pattern you have for matching the unsupported Apple devices.

[+] fix(markdown.tsx): fix escaping of dollar signs outside of code blocks
[+] fix(markdown.tsx): add support for custom-regex for unsupported Apple devices
@vercel
Copy link

vercel bot commented Oct 4, 2023

@H0llyW00dzZ is attempting to deploy a commit to the NextWeb Team on Vercel.

A member of the Team first needs to authorize it.

H0llyW00dzZ and others added 2 commits October 5, 2023 02:11
[+] chore(markdown.tsx): import isIOS function from utils file
[+] refactor(markdown.tsx): replace userAgent check with isAppleDevice function
@a6z6
Copy link
Contributor

a6z6 commented Oct 5, 2023

@H0llyW00dzZ , Great, I tried to modify your code, works fine! 🙌🏻

function _MarkDownContent(props: { content: string }) {
  const userAgent = window.navigator.userAgent;
  const isAppleIosDevice = isIOS(); // Load isAppleIosDevice from isIOS functions

  // According to this post: https://www.drupal.org/project/next_webform/issues/3358901
  // iOS 16.4 is the first version to support lookbehind
  const iosVersionSupportsLookBehind = 16.4;
  let doesIosSupportLookBehind = false;

  if (isAppleIosDevice) {
    const match = /OS (\d+([_.]\d+)+)/.exec(userAgent);
    if (match && match[1]) {
      const iosVersion = parseFloat(match[1].replace("_", "."));
      doesIosSupportLookBehind = iosVersion >= iosVersionSupportsLookBehind;
    }
  }

  let escapedContent = props.content;
  if (isAppleIosDevice && !doesIosSupportLookBehind) {
    escapedContent = props.content.replace(
      // Exclude code blocks & math block from replacement
      // custom-regex for unsupported Apple devices
      /(`{3}[\s\S]*?`{3}|`[^`]*`)|(\$(?!\$))/g,
      (match, codeBlock) => {
        if (codeBlock) {
          return match; // Return the code block as it is
        } else {
          return "&#36;"; // Escape dollar signs outside of code blocks
        }
      },
    );
  } else {
    escapedContent = props.content.replace(
      // Exclude code blocks & math block from replacement
      /(`{3}[\s\S]*?`{3}|`[^`]*`)|(?<!\$)(\$(?!\$))/g,
      (match, codeBlock) => {
        if (codeBlock) {
          return match; // Return the code block as it is
        } else {
          return "&#36;"; // Escape dollar signs outside of code blocks
        }
      },
    );
  }

  return (

...

The actual testing result shows, iOS 15.4, iOS 16.1, iOS 16.6, Chrome Browser, all works well with dollar sign! 💰

Hope this helps!

@H0llyW00dzZ
Copy link
Contributor Author

@a6z6 nice I'll update the commits with ur code

[+] fix(markdown.tsx): rename isAppleDevice variable to isAppleIosDevice and add logic to check if iOS version supports lookbehind regex

Co-Authored-By: Amor Zara <[email protected]>
@H0llyW00dzZ
Copy link
Contributor Author

H0llyW00dzZ commented Oct 5, 2023

In the wilds
https://chatgpt.btz.sh/#/changelog

[+] fix(markdown.tsx): change window.navigator.userAgent to navigator.userAgent.toLowerCase() to get user agent in lowercase
[+] fix(markdown.tsx): fix regular expression to match "os" instead of "OS" in user agent string
@Yidadaa
Copy link
Collaborator

Yidadaa commented Oct 7, 2023

Great work! It could be better to extract the logic to a new function escapeMarkdownContent(content: string): string, and use it in the component with const escapedContent = useMemo(() => ...).

@H0llyW00dzZ
Copy link
Contributor Author

@Yidadaa alright I noted that
this issue would be fix in v2.9.9 later

H0llyW00dzZ and others added 2 commits October 8, 2023 06:21
[+] fix(markdown.tsx): add useMemo hook to escapeMarkdownContent function to improve performance
[+] feat(markdown.tsx): import and use isMacOS function from utils file in escapeMarkdownContent function
@H0llyW00dzZ
Copy link
Contributor Author

@Yidadaa check

@Yidadaa
Copy link
Collaborator

Yidadaa commented Oct 8, 2023

image

Looks like a fail on this simple case, here's the output on GitHub:


what is e = m c 2 ?


image

@H0llyW00dzZ
Copy link
Contributor Author

H0llyW00dzZ commented Oct 8, 2023

you have to add 4 backticks

image

@Yidadaa
Copy link
Collaborator

Yidadaa commented Oct 8, 2023

Why? What syntax is this? I have never seen this syntax for expressing mathematical formulas.

@H0llyW00dzZ
Copy link
Contributor Author

@Yidadaa its this one e = m c 2 but it not possible I think for trying fix this formula $e=mc^2$ (only this) in preview/user unless it response from ai.
and other formula should be work normally

@Yidadaa
Copy link
Collaborator

Yidadaa commented Oct 8, 2023

@H0llyW00dzZ My question is why should we "add 4 backticks" to it? Is it a workaround?

@H0llyW00dzZ
Copy link
Contributor Author

H0llyW00dzZ commented Oct 8, 2023

its default from package markdown I think
because in this pr $ it replaced by "&#36;"
you can test in ur site
image

@Yidadaa
Copy link
Collaborator

Yidadaa commented Oct 8, 2023

I understand what you mean. In most cases, chatgpt will try to wrap latex formulas in code block syntax. Your solution tries to parse the formulas in the code block, but this is not a commonly used markdown syntax.

Normal markdown The syntax is to use the $ symbol to wrap the formula directly in the text. We should learn how github handles formula input and only replace the text with blank characters before and after $.

@H0llyW00dzZ
Copy link
Contributor Author

H0llyW00dzZ commented Oct 8, 2023

yeah but its bug for dollar sign in markdown not easily fix and its looks weird

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically.


yeah but it's big for dollar sign in markdown

@Yidadaa
Copy link
Collaborator

Yidadaa commented Nov 12, 2023

#3237

@Yidadaa Yidadaa closed this Nov 12, 2023
@H0llyW00dzZ H0llyW00dzZ deleted the bug-markdown branch November 12, 2023 12:36
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.

None yet

4 participants