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

content tag #162

Merged
merged 2 commits into from
Dec 1, 2023
Merged

content tag #162

merged 2 commits into from
Dec 1, 2023

Conversation

patricklx
Copy link
Contributor

@patricklx patricklx commented Nov 3, 2023

I did the update for eslint, and though that it might work for this as well.

design:

  1. Run Preprocessor.parse from content-tag to get template locations. manually convert gjs files with <template> tags into valid JS, which doesn't change location. The <template> tag gets converted into empty objects.
  2. convert empty object AST node to a custom Template Ast node, which holds the template content.
  3. Run the estree Prettier printer, which formats the valid JS above.
  4. Grab template contents from Template AST node described above.
  5. Run the hbs Prettier printer against the template contents.
  6. Replace the Template AST node with the results from above, wrapped in <template>

others:
</template> as TemplateOnlyComponent<Signature> will be left to prettiers default handling

@patricklx
Copy link
Contributor Author

@gitKrystan i think this works. But you would need to remove most of the ambiguous cases...

@gitKrystan
Copy link
Collaborator

Thanks. I will look into this ASAP. Might not be until next week though.

@patricklx
Copy link
Contributor Author

btw, i didn't remove the tests for the ambiguous parts. Wanted to wait on content-tag.

@NullVoxPopuli
Copy link
Member

Wanted to wait on content-tag.

how do you mean? is there an issue / failing test for that project?

@gitKrystan
Copy link
Collaborator

Can you re-run pnpm install? Seems like the lock file is out of date.

@patricklx
Copy link
Contributor Author

@gitKrystan
Copy link
Collaborator

The purpose of the ambiguous cases in the tests is that we don't introduce syntax errors when prettifying.

e.g.

<template>Hello World</template>
(oops) => {}

We should be able to detect this case and print:

<template>Hello World</template>;
(oops) => {}

@NullVoxPopuli
Copy link
Member

I'm adding failing tests for those to content-tag now 🎉

@patricklx
Copy link
Contributor Author

patricklx commented Nov 10, 2023

The purpose of the ambiguous cases in the tests is that we don't introduce syntax errors when prettifying.

e.g.

<template>Hello World</template>
(oops) => {}

We should be able to detect this case and print:

<template>Hello World</template>;
(oops) => {}

It would be converted to something like

export default template()
() => null

How would it happen that you introduce syntax errors? Although it works with typescript.
It cannot be parsed already by babel
Maybe it cannot happen anymore now?

@gitKrystan
Copy link
Collaborator

I have lots of thoughts, but no idea which ones are relevant. Please push the lockfile changes so I can run the tests and see what you are talking about. 🙏

.github/workflows/ci.yml Outdated Show resolved Hide resolved
@gitKrystan
Copy link
Collaborator

Looks like there are a few different types of test failure:

Missing visitor keys for 'Template'.

Cause unknown. This seems to be the majority of the failures.

Ambiguous cases that are now syntax errors.

With the previous ember-template-imports parsing, these were not a syntax error.

Example of a more realistic case.

const ListItem = <template><li>My Item</li></template> // no semi

<template>
  <ul>
    <ListItem />
    <ListItem />
    <ListItem />
  </ul>
</template>

If content-tag team says these are now syntax errors, we can continue to error as we do now and remove the relevant tests. (See below first, though.)

If content-tag team says these are not syntax errors, the issue needs to be fixed in the content-tag repo.

Change of behavior in other ambiguous cases.

These are still not considered syntax errors in the content-tag world, but how we are handling it seems to have changed. Will have to diff the snapshot output to determine how, but it's probably some combo of new-lines and semi-colons.

Here's an example of where the behavior change appears to be introducing a syntax error where there was none. The user added a semi-colon to prevent the syntax error and this plugin removed it.

[test:run]  FAIL  tests/unit-tests/ambiguous/arrow-parens-avoid.test.ts > ambiguous > config > arrowParens: "avoid" > (oh, no) => {} > with semi, with newline > it formats ../cases/gjs/default-export.gjs
[test:run] Error: Snapshot `ambiguous > config > arrowParens: "avoid" > (oh, no) => {} > with semi, with newline > it formats ../cases/gjs/default-export.gjs 1` mismatched
[test:run] 
[test:run] - Expected
[test:run] + Received
[test:run] 
[test:run]   "<template>
[test:run]     Explicit default export module top level component. Explicit default export
[test:run]     module top level component. Explicit default export module top level
[test:run]     component. Explicit default export module top level component. Explicit
[test:run]     default export module top level component.
[test:run] - </template>;
[test:run] + </template>
[test:run]   (oh, no) => {};
[test:run]   "
[test:run] 
[test:run]  ❯ behavesLikeFormattedAmbiguousCase tests/helpers/ambiguous.ts:95:20
[test:run]      93|   try {
[test:run]      94|     const result = await format(code, formatOptions);
[test:run]      95|     expect(result).toMatchSnapshot();
[test:run]        |                    ^
[test:run]      96|   } catch (error: unknown) {
[test:run]      97|     // Some of the ambiguous cases are Syntax Errors when parsed
[test:run]  ❯ tests/helpers/ambiguous.ts:64:13

Change of behavior with config templateExportDefault: true

Cause unknown. Maybe this case just isn't handled yet. With templateExportDefault: true, we should include export default for the relevant template export.

[test:run]  FAIL  tests/unit-tests/config/template-export-default.test.ts > config > templateExportDefault: true > it formats ../cases/gjs/default-export.gjs
[test:run] Error: Snapshot `config > templateExportDefault: true > it formats ../cases/gjs/default-export.gjs 1` mismatched
[test:run] 
[test:run] - Expected
[test:run] + Received
[test:run] 
[test:run] - "export default <template>
[test:run] + "<template>
[test:run]     Explicit default export module top level component. Explicit default export
[test:run]     module top level component. Explicit default export module top level
[test:run]     component. Explicit default export module top level component. Explicit
[test:run]     default export module top level component.
[test:run]   </template>
[test:run]   "
[test:run] 
[test:run]  ❯ tests/helpers/make-suite.ts:59:20
[test:run]      57|     const code = testCase.code.replaceAll(AMBIGUOUS_PLACEHOLDER, '');
[test:run]      58|     const result = await format(code, config.options);
[test:run]      59|     expect(result).toMatchSnapshot();
[test:run]        |                    ^
[test:run]      60|   });
[test:run]      61| }

@patricklx
Copy link
Contributor Author

I think i missed something when pushing...
Locally i didn't have Missing visitor keys for 'Template'. and had like ~300 failing tests
Will check tomorrow.
Basically there were only syntax errors.

@gitKrystan
Copy link
Collaborator

Thanks again for working on this!

@patricklx
Copy link
Contributor Author

mmm, still 600 failing tests in ci... I'll check again tomorrow

@patricklx patricklx marked this pull request as draft November 15, 2023 13:41
@patricklx
Copy link
Contributor Author

vitest was somehow auto updating all tests snapshots... this will need more work

@patricklx patricklx marked this pull request as ready for review November 15, 2023 14:32
@patricklx
Copy link
Contributor Author

patricklx commented Nov 15, 2023

okay, now down to 360.
There are some changes to semi handling.

Also, some export default where added... Not sure if they should be there .
I don't think they should as default is false for it.
But somehow the option.exportDefault is true

@patricklx
Copy link
Contributor Author

patricklx commented Nov 17, 2023

I can probably revert the semi change by changing the ast type to function expression for the template. I think.

@NullVoxPopuli
Copy link
Member

After reverting all the snapshot changes, it looks like a lot of the failures are unexpected export default

@patricklx
Copy link
Contributor Author

patricklx commented Nov 23, 2023

@gitKrystan are you okay with this changes to semi handling?
note that in the the end < template > will be converted to a function call, not a function declaration.
shall we change the ast node to CallExpression instead?
and what shall we do about the syntax errors. delete the tests causing it? I just changed the catch clause to handle the parse errors from content-tag

it looks like you expected this to happen?

In this case, some of the ambiguous expressions may result in a syntax error, in which case our Prettier plugin would error instead of formatting, similar to how Prettier already handles plain JavaScript syntax errors. Other ambiguous expressions may have their "ambiguity" resolved within the parser, allowing them to be printed as the recommendations show above.

see link

@patricklx
Copy link
Contributor Author

now all green

@patricklx
Copy link
Contributor Author

patricklx commented Nov 23, 2023

nope, example is failing. content-tag does not like vite build.
can we just tsc build to dist, or do you want to have this work in browser env as well?

edit: just set content-tag as external, now works. but browser env will not

@NullVoxPopuli
Copy link
Member

NullVoxPopuli commented Nov 23, 2023

content-tag does not like vite build.

Content-tag in browsers won't work until this is merged: embroider-build/content-tag#18

Demo of usage: https://github.com/NullVoxPopuli/limber/blob/main/packages/ember-repl/addon/src/browser/gjs.ts#L14

cc @ef4

@patricklx
Copy link
Contributor Author

patricklx commented Nov 24, 2023

@gitKrystan I think this is ready.

I wonder if the ambiguous handling is still relevant with content-tag?
its using a custom parser to transform the code, so syntax errors will cause an error here as well.
So now the ambiguous handling only has impact at runtime. maybe it should be the responsibility of eslint or glint to warn the user of constructs like
<template></template> + x
<template></template>['as']

edit: I realized now that its not ready... some ambiguous constructs actually can cause content-tag to fail parsing.
So custom semi handling is required,
I was trying to emulate it with AST nodes, but that does not seem possible

@patricklx
Copy link
Contributor Author

@gitKrystan i was able to minimize the changes to semi handling.
what do you think?
i also thought of another way to check if a semi is required or not. by printing the next node with semi: false, look at the result and then fixup the previous builders.doc result.
i will cleanup the code more later.

src/print/index.ts Outdated Show resolved Hide resolved
@@ -1938,17 +1916,16 @@ export interface Signature {
Yields: [];
}

<template>
export default (<template>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like we picked up an accidental export default here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its because i'm leaving as TemplateOnlyComponent<Signature> to prettiers default handling.
Since it now remains an expression, we cannot safely remove or add default exports to it.
are you okay with this?

Copy link
Collaborator

@gitKrystan gitKrystan Nov 28, 2023

Choose a reason for hiding this comment

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

Seems fine. Let's see if anyone complains.

@gitKrystan
Copy link
Collaborator

Thanks again for all this work!

Re: the cases causing syntax errors. Let's keep them for now since they get swallowed anyway. As we've discovered, what counts as a syntax error might change as the implementation of content-tag evolves.

Re: ambiguous cases, we want to follow Prettier's current patterns as discussed here. We can/should update that analysis if necessary since content-tag doesn't produce an array like ember-template-imports did. Check out this example.

@patricklx
Copy link
Contributor Author

ambiguous cases:
i think the only difference is when there are multiple templates in succession. then no semi is needed anymore.

<template></template>
<template></template>

its either wrapped in a static {} for class properties or exported default. or will end up with a function call, which also works without semi

src/parse.ts Outdated Show resolved Hide resolved
@patricklx
Copy link
Contributor Author

@gitKrystan squashed commits, its ready now

@gitKrystan gitKrystan merged commit d232f8f into ember-tooling:main Dec 1, 2023
3 checks passed
@gitKrystan gitKrystan added the breaking Breaking changes label Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Breaking changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants