Repository navigation
API migration help for TypeScript 5.0 #52847
Description
Suggestion
🔍 Search Terms
createLanguageServiceSourceFile- Language server
- Language service plugin
- TypeScript 5.0 API
✅ Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
⭐ Suggestion
Background
I'm currently trying to get my TypeScript plugin (typescript-plugin-css-modules) ready for TypeScript 5.0.
This plugin adds autocompletion and go to definition support for CSS by generating virtual DTS files.
When running in TypeScript 5.0, I'm hitting this issue:
Info 27 [13:59:50.911] Plugin activation failed: TypeError: Cannot set property createLanguageServiceSourceFile of #<Object> which has only a getter
As I understand it, this is because of this TS 5.0 breaking change:
The exported API is no longer defined as a "configurable" object
Source: https://github.com/microsoft/TypeScript/wiki/API-Breaking-Changes#typescript-50
What would help
I understand that the original design of this plugin may not be ideal, but I'd like to get this working in TypeScript 5.0.
I can see that proxying the LanguageService will help with most functions, but some of the methods I've been wrapping are not available on the LanguageService - namely createLanguageServiceSourceFile and updateLanguageServiceSourceFile.
The offending lines are here:
- https://github.com/mrmckeb/typescript-plugin-css-modules/blob/78acea703b3112243d8a73eb72835709332cb9e2/src/index.ts#L106-L107
- https://github.com/mrmckeb/typescript-plugin-css-modules/blob/78acea703b3112243d8a73eb72835709332cb9e2/src/index.ts#L136-L137
As someone that isn't an expert in TS plugins, I'd love a migration guide or an example of how to migrate implementations like this.
📃 Motivating Example
N/A
💻 Use Cases
N/A
Activity
jakebailey commentedon Feb 19, 2023
TS 5.0 also adds support for
d.tsfiles for arbitrary extensions: https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#allowarbitraryextensionsThis seems pretty similar to what you're trying to do in your plugin, in that one can define a
styles.d.css.tsfile and provide types. It's possible that you could implement it by providing ad.tsandd.ts.mapfile via a plugin (though, I'm less familiar with how much can be proxied there). That or, use some sort of codegen that puts the d.ts files next to the css files, that way they can be used outside of the LS too.mrmckeb commentedon Feb 20, 2023
Thanks Jake Bailey (@jakebailey), I missed that
allowArbitraryExtensionswas coming and that looks really interesting.Do you know who might be able to help with information around proxying other methods needed to read/process non-TS files? Perhaps a better alternative to using the now immutable
createLanguageServiceSourceFileandupdateLanguageServiceSourceFilemethods?For context, this plugin has around 200k+ weekly downloads, which I think (from a quick search) makes it one of the most popular language service plugins. It allows users to have type information from CSS (including Less, Sass, etc) without needing to watch and generate DTS files for those files in a separate process.
jakebailey commentedon Feb 21, 2023
Ron Buckton (@rbuckton) has suggested that you could provide
styles.d.css.tsvia the host, but Sheetal Nandi (@sheetalkamat) may also have ideas.I'm planning on trying to go through as many plugins and patchers as possible to get a handle on which APIs people are trying to patch. I was hoping that the lack of feedback regarding this meant that it wasn't so widespread (this change happened circa November 2022), but, it seems like people are coming out of the woodwork now that the RC is approaching (which is unfortunate given a "fix" for this on the TS side is likely to be nontrivial).
jakebailey commentedon Feb 22, 2023
I've been working on that collected "ts patchers" list and stumbled upon Vue's LS plugin; they appear to proxy the host to provide similar functionality, so I believe that it's possible to do something like you already do within the current API:
sheetalkamat commentedon Feb 22, 2023
Sorry i missed this notification yesterday.
You would want to proxy following methods on
languageServiceHostthats passed in through plugin create info.mrmckeb commentedon Feb 24, 2023
Thanks so much for all of the detail Jake Bailey (@jakebailey), and for the additional info Sheetal Nandi (@sheetalkamat).
This is an unsponsored project, so I'll take a look at migrating to these APIs over the weekend!
typescript-bot commentedon Feb 26, 2023
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow or the TypeScript Discord community.
mrmckeb commentedon Mar 11, 2023
Thanks again for the help on this issue. I managed to get it working this weekend, and feeling very relieved!
mrmckeb/typescript-plugin-css-modules#211
jakebailey commentedon Mar 13, 2023
Glad you got it working. I left some comments on the PR which you may want to look at; in general, plugins should not import
typescript, only ever using thetsvalue passed into init, otherwise they will be different objects entirely and may cause oddities.yoyo930021 commentedon Apr 17, 2023
Sorry for the disturbance, I am the current primary maintainer of Vetur. Vetur now relies on
createLanguageServiceSourceFileto inject the export default object wrapped withVue.extendsinto each Vue SFC. This layer is added directly to the AST and is set to not exist in the document through a hack.If we want to change to the method mentioned above, we need to switch to a text-based approach combined with sourcemaps, which would be equivalent to rewriting the entire project. I would like to confirm if there are any similar hackable methods available? Otherwise, Vetur might have to give up on continuing support for TypeScript 5 and beyond.
jakebailey commentedon Apr 17, 2023
I am assuming you're referring to: https://github.com/vuejs/vetur/blob/96aaa707f8ca629f0883c57a47adb0e58995936d/server/src/services/typescriptService/preprocess.ts
If I'm reading this correctly, you're calling the original
createLanguageServiceSourceFile, then using its AST, modifying it, reprinting it, and then reparsing it, correct?In which case, can you just do the same thing but skip the final re-parse step and return source in
getScriptSnapshot? The only other bit I can see is that it automagically adds imports, which I think can be done in other ways, either also by source modification, or by using a globald.tsfile which declares these for you. I know that volar does some of this.Though, I'm a bit confused; I thought vetur was deprecated in favor of volar, which I think is working with TS 5.0?
yoyo930021 commentedon Apr 18, 2023
The main logic is in this line:
https://github.com/vuejs/vetur/blob/96aaa707f8ca629f0883c57a47adb0e58995936d/server/src/services/typescriptService/preprocess.ts#L184
It inserts additional AST and sets the AST's position to 0, so that TS will not generate messages at incorrect positions. If changed to use the
getScriptSnapshotmethod, an extra sourcemap would be required to map the code position information back, which would be equivalent to rewriting the entire project.The rest of the logic is actually not that important.
Volar is the new official Vue extension, but it mainly focuses on Vue 3 projects; Vetur now focuses on supporting older Vue 2 projects, with limited support for Vue 3 and only providing basic maintenance, without adding new features.