{"id":18109656,"url":"https://github.com/val-town/codemirror-ts","last_synced_at":"2025-05-15T18:09:46.181Z","repository":{"id":207831262,"uuid":"719168953","full_name":"val-town/codemirror-ts","owner":"val-town","description":"lint, hover, goto, autocomplete, and twoslash extensions for CodeMirror + TypeScript","archived":false,"fork":false,"pushed_at":"2025-03-11T13:53:18.000Z","size":2565,"stargazers_count":192,"open_issues_count":3,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-11T18:19:35.078Z","etag":null,"topics":["autocompletion","codemirror","codemirror6","lint","lsp","ts","typescript"],"latest_commit_sha":null,"homepage":"https://val-town.github.io/codemirror-ts/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/val-town.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-15T15:45:47.000Z","updated_at":"2025-04-04T14:18:13.000Z","dependencies_parsed_at":"2023-12-18T23:26:19.122Z","dependency_job_id":"46f79dd1-882d-4f2b-8974-59346ce4284e","html_url":"https://github.com/val-town/codemirror-ts","commit_stats":null,"previous_names":["val-town/codemirror-ts"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/val-town%2Fcodemirror-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/val-town%2Fcodemirror-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/val-town%2Fcodemirror-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/val-town%2Fcodemirror-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/val-town","download_url":"https://codeload.github.com/val-town/codemirror-ts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248456378,"owners_count":21106605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autocompletion","codemirror","codemirror6","lint","lsp","ts","typescript"],"created_at":"2024-11-01T00:01:53.479Z","updated_at":"2025-04-11T22:29:45.503Z","avatar_url":"https://github.com/val-town.png","language":"TypeScript","funding_links":[],"categories":["Plugins"],"sub_categories":[],"readme":"# codemirror-ts\n\n\n\u003ca href=\"https://www.npmjs.com/package/@valtown/codemirror-ts\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/npm/dw/@valtown/codemirror-ts.svg\" alt=\"npm\"\u003e\u003c/a\u003e\n\n_[Made by val.town](https://www.val.town/), a social website to write and deploy backend services._\n\nOn npm as `@valtown/codemirror-ts`\n\n- [Demo on StackBlitz](https://stackblitz.com/edit/vitejs-vite-giwkc3?file=index.html)\n- [Demo on StackBlitz using Web Workers](https://stackblitz.com/edit/vitejs-vite-qsncw4?file=src%2Fmain.ts)\n\nTypeScript extensions for CodeMirror. This aims to support\nas much of the basic interactions with TypeScript code as possible\nin CodeMirror.\n\n## Currently provides\n\n- Hover hints for types\n- Autocomplete\n- Diagnostics (lints, in CodeMirror's terminology)\n- Go-to definition\n- Twoslash support\n\n## Peer dependencies\n\nThis module does not depend on anything: your project should\nhave direct dependencies to:\n\n- `@codemirror/view`\n- `@codemirror/lint`\n- `@codemirror/autocomplete`\n\n## Setup\n\nUsing a [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker), you can\nrun TypeScript separately from the rest of your JavaScript, which can make\nboth faster and more reliable. Depending on how you're building applications,\nyou'll need to consult their documentation on setting up web workers:\n\n- [Using workers with Vite](https://vitejs.dev/guide/features#web-workers)\n- With Next.js, you'll need to make sure that you're [using Webpack 5](https://nextjs.org/docs/messages/webpack5)\n- With Remix, you'll need [a separate entry point](https://github.com/remix-run/remix/discussions/4416?sort=new) (or it may work automatically if you've switched to using Vite with Remix)\n\nWith that out of the way:\n\n1. Create your worker\n\nIn a file like `worker.ts`, you'll need something like this:\n\n```ts\nimport {\n  createDefaultMapFromCDN,\n  createSystem,\n  createVirtualTypeScriptEnvironment,\n} from \"@typescript/vfs\";\nimport ts from \"typescript\";\nimport * as Comlink from \"comlink\";\nimport { createWorker } from \"@valtown/codemirror-ts/worker\";\n\nComlink.expose(\n  createWorker(async function () {\n    const fsMap = await createDefaultMapFromCDN(\n      { target: ts.ScriptTarget.ES2022 },\n      \"5.7.3\",\n      false,\n      ts,\n    );\n    const system = createSystem(fsMap);\n    const compilerOpts = {};\n    return createVirtualTypeScriptEnvironment(system, [], ts, compilerOpts);\n  }),\n);\n```\n\nThis code should look familiar if you read the section about setting this up\nwith the main thread: it's the same setting-up of the TypeScript environment,\nbut this time wrapping it in `Comlink.expose`, and, importantly, setting\nthe third parameter of `createDefaultMapFromCDN` to false.\n\nThe third option in `createDefaultMapFromCDN` is whether to cache files: it uses `localStorage` to power\nthat cache, and Web Workers don't support `localStorage`. You can [implement](https://github.com/microsoft/TypeScript-Website/blob/v2/packages/typescript-vfs/src/index.ts#L368) your own `storer` instead.\n\nThere is an optional fifth option in `createDefaultMapFromCDN` to pass in `lzstring` to compress files that as well. You can follow [this example](https://github.com/microsoft/TypeScript-Website/blob/v2/packages/sandbox/src/index.ts#L8) and add a `lzstring.min.js` file to your codebase if you want.\n\n2. Initialize the worker\n\nNow, on the application side (in the code in which you're initializing CodeMirror),\nyou'll need to import and initialize the worker:\n\n```ts\nimport { type WorkerShape } from \"@valtown/codemirror-ts/worker\";\nimport * as Comlink from \"comlink\";\n\nconst innerWorker = new Worker(new URL(\"./worker.ts\", import.meta.url), {\n  type: \"module\",\n});\nconst worker = Comlink.wrap\u003cWorkerShape\u003e(innerWorker);\nawait worker.initialize();\n```\n\n3. Add extensions\n\nIn short, there are `*`Worker versions of each of the extension\nthat accept the `worker` instead of `env` as an argument.\n\n```ts\n[\n  tsFacetWorker.of({ worker, path }),\n  tsSync(),\n  tsLinter(),\n  autocompletion({\n    override: [tsAutocomplete()],\n  }),\n  tsHover(),\n  tsGoto(),\n  tsTwoslash(),\n];\n```\n\n## Using ATA\n\nThe example above will give you a working TypeScript setup, but if you\nimport a module from NPM, that module will not have types. Usually TypeScript\nexpects you to be installing modules with npm and expects that they'll be stored\nin a `node_modules` directory. `codemirror-ts` is on the internet in a WebWorker,\nso obviously it is not running NPM.\n\nYou can emulate what you'd get in a local editor by using [ATA](https://www.npmjs.com/package/@typescript/ata), or\n'automatic type acquisition'. The setup looks like this example,\nand is a change to your WebWorker setup. We use the `onFileUpdated`\ncallback passed to `createWorker`, trigger ATA to get new types,\nand then create those files on path.\n\n```ts\n// … import createWorker etc.\n// Import setupTypeAcquisition from @typescript/ata\n\nconst worker = createWorker({\n  env: (async () =\u003e {\n    const fsMap = await createDefaultMapFromCDN(\n      { target: ts.ScriptTarget.ES2022 },\n      ts.version,\n      false,\n      ts,\n    );\n    const system = createSystem(fsMap);\n    return createVirtualTypeScriptEnvironment(system, [], ts, {\n      lib: [\"ES2022\"],\n    });\n  })(),\n  onFileUpdated(_env, _path, code) {\n    ata(code);\n  },\n});\n\nconst ata = setupTypeAcquisition({\n  projectName: \"My ATA Project\",\n  typescript: ts,\n  logger: console,\n  delegate: {\n    receivedFile: (code: string, path: string) =\u003e {\n      worker.getEnv().createFile(path, code);\n    },\n  },\n});\n\nComlink.expose(worker);\n```\n\n\u003e [!NOTE]\n\u003e If you are targeting a _non-Node_ environment, like Deno or\n\u003e a web browser, ATA will not help you with your HTTP imports or prefixed\n\u003e imports. It narrowly targets the Node \u0026 NPM way of doing imports.\n\n## Calling other methods in the worker\n\nThe provided `createWorker` method creates a standard object with methods\nthat the frontend code knows about and can call to power TypeScript support.\nIf you want to do something else with Worker, like transpiling or\nrunning a code formatter, you can nest the result of createWorker. See\n[the demo for an example](https://val-town.github.io/codemirror-ts/):\nthe gist is:\n\nIn your worker, nest the `worker` instead of directly exposing it.\n\n```ts\nComlink.expose({\n  worker,\n  anotherMethod() {\n    return 'another-result';\n  }\n})\n```\n\nIn the front-end, reach in for the exposed worker:\n\n```ts\ntsFacet.of({ worker: worker.worker, path }),\n```\n\n## Conceptual notes: persisted code\n\nThere are a few different approaches to building CodeMirror + TypeScript\nintegrations. Each of the things that this does - linting, hovering,\nautocompleting - they all require TypeScript to know about your source\ncode. It's tempting to send it over all the time: you get your whole\nsource code and call something like\n\n```ts\nlint(sourceCode);\n```\n\nHowever, this has an overhead, and it combines poorly: if you're linting,\nand hovering, and autocompleting, it's inefficient to send the whole code\nover for each of those. Hence how these extensions start with the _sync_\nmethod, which updates TypeScript's version of the code contents.\n\nThis has some drawbacks: maybe the version gets out of sync, especially\nwhen the TypeScript environment is in a worker. But we think it's worth\nit, and it yields some other benefits.\n\n## Conceptual notes: file names\n\nThese extensions expect your client-side CodeMirror instance to be attached\nto a filename, like `index.ts`. By sharing a TypeScript environment,\nthis lets you have two CodeMirror instances, say, editing `a.ts` and `b.ts`,\nand for one to import values from the other and get the correct types -\nbecause TypeScript automatically include both.\n\nNote, however: these extensions currently _only support creating and updating files_ - if you support removing or deleting files, they won't be possible to do that. It would be really nice to support those other parts of the lifecycle - PRs gladly accepted!\n\n## Conceptual notes: Comlink\n\nThis uses [Comlink](https://github.com/GoogleChromeLabs/comlink) as an\nabstraction for the WebWorker. There are certainly other ways to build it -\nwe could write our own similar abstraction. But, Comlink is a pretty nifty\nway to use Web Workers - it allows you to call functions in a web worker\nfrom the top page.\n\nLike any other communication across `postMessage`, there are limits\non the kinds of values you can pass. So we can't pass the raw `CompletionContext` object\nacross the boundary. Right now this module works around that limitation\nby just passing the properties we need. There may be other solutions\nin the future.\n\nComlink is [lightweight](https://bundlephobia.com/package/comlink@4.4.1) (4.7kb gzipped).\n\n## Conceptual notes: LSP\n\nThis module uses TypeScript’s public APIs to power its functionality:\nit _doesn't_ use the [Language Server Protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol), which is\na specification developed by Microsoft and intended for functionality like\nthis. [TypeScript itself does not have a first-party LSP implementation](https://github.com/microsoft/TypeScript/issues/39459)\nand LSP is usually used across a network. Most good TypeScript language\ntooling, like VS Code’s autocompletion, does not use the LSP specification.\nUnfortunately, most TypeScript language tooling in other editors is based directly\noff of the VS Code implementation.\n\n### ❤️ Other great CodeMirror plugins\n\n- [codemirror-vim](https://github.com/replit/codemirror-vim)\n- [codemirror-copilot](https://github.com/asadm/codemirror-copilot)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fval-town%2Fcodemirror-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fval-town%2Fcodemirror-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fval-town%2Fcodemirror-ts/lists"}