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

(JavaScript/TypeScript) Regular expression with quotes inside template literal breaks highlighting #4066

Open
JoaoFelipe3 opened this issue Jun 19, 2024 · 1 comment
Labels
autoclose Flag things to future autoclose. bug help welcome Could use help from community language

Comments

@JoaoFelipe3
Copy link

JoaoFelipe3 commented Jun 19, 2024

If a template literal with a regular expression that contains an odd number of quotes is highlighted, the last quote is treated as beginning a string and extends until closing it, at which point you still need to close the placeholder and the template literal itself.

I am testing with the javascript, but the same goes for the typescript grammar.

I am not using the language detection.

Here is some example code to test this on:

`${/"/}`
doStuff()
// "}`

I expected the quote to not open a string at all, and just be treated as part of the regular expression.

Here's the code this was found in (TypeScript):

const or = (fns: readonly (() => string)[]) => {
  for (const fn of fns) {
    try {
      return fn();
    } catch {
      continue;
    }
  }
  throw new Error("or failed");
};
function* many(fn: () => string) {
  while (code.length) {
    try {
      yield fn();
    } catch (_) {
      break;
    }
  }
}
const optional = (chr: string) => t(new RegExp(`^\\${chr}?`)) || chr;
const t = (re: RegExp) => {
  code = code.slice(code.search(/[^ ]/));
  const match = code.match(re)![0]; // throws if no match
  code = code.slice(match.length);
  return match;
};

const chain = () => or([triad, dyad, monad, infix]);
const arr = () =>
  t(/^\[/) + [...many(() => expr() + optional(","))].join("") + optional("]");
const num = () => `new $N(${Number(t(/^[+-]?(?:\d*\.\d+|\d+)/))})`;
const str = () => `new $S(${t(/^"(?:\\.|[^"])*"/)})`;
const chr = () => `new $S('${t(/^'./)[1]}')`;
const nme = () => t(/^[A-Z]/);
const arr = () =>
  t(/^\[/) + [...many(() => expr() + optional(","))].join("") + optional("]");
const nilad = () => or([arr, num, str, chr, nme]);
const triad = () => `.${t(/^[a-z][\u0324:]/)[0]}(${arg()},${arg()})`;
const dyad = () => `.${t(/^[a-z][\u0323\.]/)[0]}(${arg()})`;
const monad = () => `.${t(/^[a-z]/)}()`;
const infix = () => t(/^[+\-*/]/) + arg();
const chain = () => or([triad, dyad, monad, infix]);
function arg(): string {
  const z = () => or([nilad, () => "X" + chain()]);
  const p = () => t(/^\(/) + expr() + optional(")");
  return or([p, z]);
}
function expr() {
  return arg() + [...many(chain)].join("");
}
@JoaoFelipe3 JoaoFelipe3 added bug help welcome Could use help from community language labels Jun 19, 2024
@joshgoebel
Copy link
Member

joshgoebel commented Jun 19, 2024

The existing behavior is intentional. #3288

Regex is really hard to deal with without a full context-aware parser. I'll leave this open a bit to see if anyone wants to try and tackle this - and solve BOTH issues... but eventually if no one shows up we'll auto-close it a cant-fix.

@joshgoebel joshgoebel added the autoclose Flag things to future autoclose. label Jun 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autoclose Flag things to future autoclose. bug help welcome Could use help from community language
2 participants