8 KiB
TypeScript plugin for Syndicate
Rewrites Syndicate DSL syntax into plain TypeScript as a tsserver
plugin, allowing your IDE to work directly with Syndicate constructs
and not requiring a separate preprocessing step.
Sadly, tsc
doesn't pay attention to plugins (not as of April 2021,
anyway). If you're using tsc
as part of your build, you will need to
use @syndicate-lang/tsc
's syndicate-tsc
command instead.
Installing the plugin
package.json
:
{
"devDependencies": {
"@syndicate-lang/ts-plugin": "file:../..",
...
},
...
}
then yarn install
.
Enabling the plugin in the TypeScript compiler
tsconfig.json
:
{
"compilerOptions": {
"plugins": [
{ "name": "@syndicate-lang/ts-plugin" }
],
...
},
...
}
Getting it to work with specific editors
Emacs with Tide
It should Just Work, if the node_modules
next to tsconfig.json
has
a typescript/
subdirectory.
If no such typescript/
subdirectory exists in node_modules
, then
because
tsserver loads plugins from relative to tsserver.js rather than tsconfig.json,
you will have to tell tide-mode
about where your project's
tsserver
lives.
One easy way to do that is to create a symlink in your node_modules
:
ln -s /FULL/PATH/TO/YOUR/PROJECT/node_modules/typescript ./node_modules/
Another way to do it is to put a .dir-locals.el
file in your project
root, containing
((tide-mode
. ((tide-tsserver-executable
. "/FULL/PATH/TO/YOUR/PROJECT/node_modules/typescript/bin/tsserver"))))
I don't know of any way of automatically resolving a relative path
specification with respect to the directory containing
.dir-locals.el
without using eval
, but if you're happy to do so,
you can use the following:
((typescript-mode
. ((eval . (setq tide-tsserver-executable
(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))))
If you use the .dir-locals.el
methods, you may need to run
tide-restart-server
once after opening the first TypeScript file in
your project (and then close and re-open that TypeScript file).
Emacs with LSP
Tell lsp-mode to automatically find and use your project's tsserver
Since lsp-mode version 8.0.1, the first thing to try is to set
lsp-clients-typescript-prefer-use-project-ts-server
to t
. From the lsp-mode documentation:
lsp-clients-typescript-prefer-use-project-ts-server
Type:
boolean
Default:
nil
When set, prefers using the tsserver.js from your project. This can allow loading plugins configured in your tsconfig.json.
When lsp-clients-typescript-prefer-use-project-ts-server
is set, but your emacs hasn't
downloaded and installed the ts-ls
lsp-mode backend yet, lsp-mode will prompt you to download
and install ts-ls
. After that process has completed, it should then look for and load your
project's tsserver.
If lsp-clients-typescript-prefer-use-project-ts-server
is not available (e.g. your lsp-mode
is older than 8.0.1), or if, for some reason, it doesn't work, read on.
Explicitly configuring your project's tsserver with lsp-mode
LSP will, by default (for versions older than 8.0.1 or when
lsp-clients-typescript-prefer-use-project-ts-server
is nil
), use its own tsserver
, no
matter what is in the local node_modules
. Because of the issue with tsserver's approach to
plugin loading, this means that by default it will not load
the Syndicate plugin.
Overriding the tsserver
location is similar to the way it's done for
Tide, but instead of a variable value change, a function has to be
called. One good way to do it is to use .dir-locals.el
, as above:
((typescript-mode
. ((eval . (progn
(require 'lsp-javascript)
(lsp-dependency
'typescript
`(:system ,(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))))))
And, of course, you can make changes for both Tide and LSP at once, if you like:
((typescript-mode
. ((eval
. (progn
;; For TIDE:
(setq tide-tsserver-executable
(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))
;; For LSP:
(require 'lsp-javascript)
(lsp-dependency 'typescript
`(:system ,(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))
))))
Finally, I've had some trouble with LSP when I've not had
typescript-language-server
, which is different to tsserver
(?),
installed. Then, I've had to install the typescript-language-server
npm package, as well as typescript
, and to take an approach similar
to this to point LSP at it:
((typescript-mode
. ((eval
. (progn
(require 'lsp-javascript)
(let ((node-modules (concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/")))
(lsp-dependency 'typescript-language-server
`(:system ,(concat node-modules
"typescript-language-server/lib/cli.mjs")))
(lsp-dependency 'typescript
`(:system ,(concat node-modules
"typescript/lib/tsserver.js")))))
))))
Older versions of typescript-language-server
use cli.js
instead of
cli.mjs
above.
Visual Studio Code
After yarn install
, if you have a node_modules/typescript
directory, then the following will work. (Otherwise, there may not be
an option to select "Use Workspace Version", and you may need to
symlink a typescript
directory into node_modules
as described for
Emacs Tide above.)
Open VS Code, and select the version of TypeScript contained therein by following instructions here.
Specifically, when selecting a TypeScript version, choose "Use Workspace Version".
For me, the net effect of this is to create a .vscode/settings.json
file containing:
{
"typescript.tsdk": "node_modules/typescript/lib"
}
Debugging
Emacs with Tide
You can get verbose logs from Tide's tsserver by setting the Emacs
variable tide-tsserver-process-environment
:
(setq tide-tsserver-process-environment '("TSS_LOG=-file /tmp/tss.log"))
You can also enable "verbose" output, if that's useful:
(setq tide-tsserver-process-environment '("TSS_LOG=-level verbose -file /tmp/tss.log"))
Finally, you can set these options in a .dir-locals.el
file, too:
((typescript-mode
. ((tide-tsserver-process-environment . ("TSS_LOG=-level verbose -file /tmp/tss.log")))))
Emacs with LSP
Older versions of lsp-mode
by default helpfully put logs in a .log/
directory in your
project root. Newer versions seem not to have that logging enabled by default; for these
versions, set (customize) the variable lsp-clients-typescript-server-args
to include the
strings "--tsserver-log-verbosity" "verbose"
. For example,
(setq lsp-clients-typescript-server-args '("--stdio" "--tsserver-log-verbosity" "verbose"))