-
-
Notifications
You must be signed in to change notification settings - Fork 200
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
(feat) add svelte2tsx for better ts support #57
Conversation
Makes code more readable, no unnecessary interim stage
I think The lang/attribute setting is kind of weird to me though. Because it would change the entire file to ts, not just the script it annotated. I understand it's very hard to support multiple-languages in the same component. Maybe we should warn user that this is not supported. Or we could invent a new special comment/tag/detective that should be placed at the top of the file to specify |
tsxMap.sources = [uri]; | ||
} | ||
} catch (e) { | ||
text = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had this approach and found that it gave too man angry red squiggles when the document is in a state where it won't parse.
https://github.com/halfnelson/svelte-type-checker-vscode/blob/svelte-native-support/server/src/DocumentSnapshot.ts#L50
In my plugin I stash the parse error so that when I get a call to get the diagnostics, I can check for the existence of the error and return the parse error (instead of treating the file as blank). Is the intention to let the svelte plugin point out the location of an parse errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. At the moment there is no error at all shown if there are parsing errors. With your strategy this could be pointing to parser errors instead, as you said. I will look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Looks good to me 👍 Regarding the failing test for code actions. I had a bunch of trouble with off by one errors, especially due to the fact that TS's lines start at 0 and characters at 1, and sourcemap starts at 1,1 (from memory), So there might still be a mapping conversion error in there. |
Sorry, I don't fully understand what you mean. Do you mean the current implementation is confusing? Or that it would be confusing if we would add a config setting? I also wonder what's going on under the hood with if the user does not specifiy to use typescript, so the ending is |
@dummdidumm what I think is weird is that the lang/type attribute on one script would change the entire file's script kind. <script context="module">
let b = false;
b = 1; // get type error here
</script>
<script lang="typescript">
let a = 1;
</script>
<button tabindex="-1" /> <!--get type error here --> So I thought if it would better be if we have a new way to set the script kind at the top of the file. for example: <!--lang=typscript-->
<script>
</script>
<ComponentA /> |
Ah I understand. Yeah I think this new way would clear up confusion, but at the same time it could introduce new ones. As of now, all preprocessors look at |
Fair point. <script context="module" lang="javascript">
</script>
<script lang="typescript">
</script>
<button tabindex="-1" /> |
I would give typescript the priority since javascript is valid typescript but not the other way round. A warning is a good idea. |
Ok, I did test what happens if we use a What will not work is adding |
Ok I found the bug that produces the code actions error. This script: <script>let a = true</script> Gets transformed to this: <></>;function render() {
let a = true; /// <<---- additional ;
<></>
return { props: {}, slots: {} }}
export default class {
$$prop_def = __sveltets_partial(render().props)
$$slot_def = render().slots
} The code has added a |
There is an edge case where it fails, but that edge case is edgy enough to adjust the test. See sveltejs#57 (comment)
- adjust completions (some workarounds for wrong mappings needed) - add more completions tests
Quick update: I merged master into the branch and am now working hard on getting imports right for svelte components. Turns out that there are a lot of edge cases. Also I came across a major drawback of the For example this: <script>
</script>
<SomeComp is not recognized as valid by the compiler, so I have to place the import at the right position "by hand". EDIT: just had an idea how to simplify this. Doing this would mean to alway do the import below the script opening tag, not below the last previous import. But I think that's okay. |
Svelte imports are working now, without compromising the other imports. So there is only one thing left to discuss: Ditch |
I would like to retain support for Is it possible that we add it to the top of tsx if we detect it for now? This detection can be removed later if @orta do you know if is there any public typescript API that can detect /^\s*(\/\/[ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*@ts-(no)?check$)/
|
I added Some things could be refactored. For example I now need style tag info inside ts aswell, so we could move this extraction to the parent document. But I would like to keep these refactorings out of this PR because I fear it will get too big and will touch too many files. |
Find one issue, the template type check diagnoses needed to update if a dependent component is updated. But this seems needed quite some code to fix, I think, as you said this PR is getting too big, it could be done in another PR. Overall this is working quite nicely! |
Perfect, I was about to recommend |
@jasonlyu123 - no, no public API for that (it's a step in the parser for us) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great - a minor regex issue, but everything feels to be in place. Great work.
result.line += this.nrPrependesLines; | ||
return result; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
await new SourceMapConsumer(this.tsxMap), | ||
uri, | ||
this.nrPrependedLines, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a lot happening on a single express, might be worth a refactor later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely true, one of the first things I'm gonna look into after this is merged.
} | ||
} | ||
|
||
// eslint-disable-next-line | ||
const tsCheckRegex = /^\s*(\/\/[ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*(@ts-(no)?check)($|\n|\r\n))/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex might needs a tweak, here's some examples: https://regex101.com/r/ZXpJNc/2as I think TypeScript is more liberal (any type of comment, and any whitespace after ) in accepting ts-check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. I played around a little. Seems like it accepts the comment if
- it is before the first line of code (so other lines with comments before it are ok)
- must be
@ts-(no)check
- the comment which has
@ts-(no)check
can have any type of whitespace before it, but not other characters - what's coming after
@ts-(no)check
is irrelevant as long there is any kind of whitespace or line break, so this would be picked up, too:// @ts-check asdasd
.map((diagnostic) => mapDiagnosticToParent(fragment, diagnostic)) | ||
.filter( | ||
(diagnostic) => diagnostic.range.start.line >= 0 && diagnostic.range.end.line >= 0, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this could accidentally remove diagnostics which come from setup around the specific file? It seems unlikely, but at least worth bringing up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this because in some rare cases the diagnostic could not be mapped correctly. But VSCode or the LSP (don't know which one) then seems to swallow all other errors aswell as soon as it encounters one diagnostic with negative lines. I will add a comment.
commitCharacters: getCommitCharactersForScriptElement(comp.kind), | ||
preselect: comp.isRecommended, | ||
// Make sure svelte component takes precedence | ||
sortText: isSvelteComp ? '-1' : comp.sortText, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work
}; | ||
} | ||
|
||
private getCompletionLableAndInsert(comp: ts.CompletionEntry) { | ||
const { kind, kindModifiers, name } = comp; | ||
private getCompletionLableAndInsert(fragment: SnapshotFragment, comp: ts.CompletionEntry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
irrelevant: getCompletionLableAndInsert
has a typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is my fault lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Np, I will change it 😄
This PR adds
svelte2tsx
to get better typescript support.Still TODO:
There is one failing test for code actions. I think there is an edge case of source mapping there, the end of the replace range cannot be mapped. Not really sure how to deal with this. Change test to see if non-edge-cases work and then just leave it at that?see (feat) add svelte2tsx for better ts support #57 (comment)To discuss:
Right now it is differentiated between JSX and TSX based on whether or not the user usesthelang="typescript"
or not. Advantage: User does not get type errors he does not want because he uses JS. Disadvantage: You don't get component name/prop typechecking. What to do? Maybe add a settings option to make this configurable by the user?@ts-check
comment can be used for thatI think thewill work now@ts-check
comment at the top of script contents will not work anymore. Is this bad?@halfnelson could you also have a short look and see I'm not doing anything funky there?
Related #11