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: handle regexp as default export #167

Merged
merged 1 commit into from Mar 19, 2024
Merged

Conversation

fpipita
Copy link
Contributor

@fpipita fpipita commented Mar 14, 2024

Hi,

this pull request aims at handling another case of division/regexp ambiguity which I encountered in the attempt of parsing the recently added module https://github.com/markdown-it/uc.micro/blob/master/categories/S/regex.mjs:

The ambiguity can be triggered by trying to parse this minimal example:

export default /[`]/

The solution I came up with to decide whether the next token was a regexp, was to basically check if the last token position was compatible with the position of the last detected export name.

@guybedford
Copy link
Owner

Thanks for finding this and putting together a fix.

The approach isn't quite right unfortunately - this wouldn't handle the false positive - export default 1 / 2 and would think that it is a regex.

Instead the fix here is to integrate the default keyword itself into the regular expression logic. Because the default keyword cannot come in any other positions, it should be enough to add it to this detection list in isExpressionKeyword - https://github.com/guybedford/es-module-lexer/blob/main/src/lexer.c#L854.

That detection is saying that if the preceding keyword is one of those, then it must be a regex, as it is the start of an expression and not an internal part of a logical expression.

It should also be an even smaller diff I believe. Let me know if that works out.

@guybedford
Copy link
Owner

Ah it seems I spoke too soon - this is correct because you are validating that the regex comes immediately after the export default and not in any other position.

I would be grateful if we could add some tests for this case and also some tests for having comments between the export default and the regex:

export default 1/2
export default /* asdf */ 1/2
export default /* asdf */ /regex/
export default
// line comment
/regex/
export default
// line comment
1 / 2

, but then it seems we should be fine to land actually.

@fpipita
Copy link
Contributor Author

fpipita commented Mar 15, 2024

Hi, thank for your quick reply and review.

I've added the unit tests and I can confirm that, by inspecting the execution through the debugger, all of them are parsed as expected.

However, in order to improve the reliability of the unit tests for the particularly tricky regexp/division scenario, in my opinion it would be useful to expose the value of the lastSlashWasDivision flag as "private metadata" to each export.

With this information available, in unit tests we could make sure that the ambiguity is handled as expected, eg.:

test("Regexp default export", () => {
  const [, exports] = parse("export default /[`]/");
  assert.deepStrictEqual(
    exports.map(expt => ({name: expt.n, regexp: expt.regexp})), 
    [{name: "default", regexp: true}]
  );
});

@guybedford guybedford merged commit d78f7d4 into guybedford:main Mar 19, 2024
1 check passed
@guybedford
Copy link
Owner

Great, many thanks for checking the edge cases here. Will post out the patch release now.

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

2 participants