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

Feature/language service plugin #154

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18",
"features": {
"ghcr.io/devcontainers-contrib/features/pnpm:2": {}
},

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm i -g turbo && pnpm install && git config --global core.editor 'code --wait'",

// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint"
]
}
}

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
node_modules
.pnp
.pnp.js
.pnpm-store/

# testing
coverage
Expand Down
5 changes: 3 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint"
]
"dbaeumer.vscode-eslint",
"ms-vscode-remote.remote-containers"
]
}
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"out": true // set this to false to include "out" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
"typescript.tsc.autoDetect": "off",
"typescript.tsserver.log": "normal"
}
10 changes: 9 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@ Your contributions will eventually help save countless hours for people struggli
1. Node.js version installed, [latest LTS is recommended](https://nodejs.org/en/about/releases/)
2. Install pnpm

### Using [devcontainer](https://code.visualstudio.com/docs/devcontainers/create-dev-container)

Devcontainers is an easy way to avoid "works on my machine" situations. Essentially, the development happens in a Docker container.

1. Make sure you've got Docker installed on your machine
2. Do install the recommended by VSCode extensions
3. Click "Reopen in Container" button in a popup

## How to start developing?

Clone the repo and install the needed dependencies for all the packages by following these steps:

```sh
git clone https://github.com/mattpocock/ts-error-translator.git
cd ts-error-translator
pnpm
pnpm install
pnpm dev # This will run the next app
```

Expand Down
7 changes: 4 additions & 3 deletions packages/engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
"name": "@total-typescript/error-translation-engine",
"version": "1.0.3",
"license": "MIT",
"main": "./src/index.ts",
"types": "./src/index.ts",
"main": "./out/index.js",
Copy link
Author

Choose a reason for hiding this comment

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

@mattpocock I needed this change to make plugin bundling work.

"types": "./out/index.d.ts",
"private": true,
"scripts": {
"test": "vitest run"
"test": "vitest run",
"build": "tsc"
},
"dependencies": {
"front-matter": "^4.0.2"
Expand Down
6 changes: 5 additions & 1 deletion packages/engine/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"outDir": "out"
},
"include": [
"src"
],
"exclude": [
"node_modules"
"node_modules",
"src/__tests__"
]
}
Empty file.
11 changes: 11 additions & 0 deletions packages/language-service-plugin/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Language Service Plugin

[Reference](https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin)

To test this plugin out, compile the code and open the `example` folder in a VSCode instance:

```
code ./example
```

Also, please, make sure the workspace version of TypeScript is used. Use the `TypeScript: Select TypeScript version` command for this.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsserver.log": "normal",
"typescript.tsdk": "node_modules/typescript/lib"
}
19 changes: 19 additions & 0 deletions packages/language-service-plugin/example/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function A(b: number): number {
return b;
}
A("test")


let a: { m: number[] };
let b = { m: [""] };
a = b;

// Extra Properties

type A = { m: number };
const w: A = { m: 10, n: "" };

// Union Assignments

type Thing = "none" | { name: string };
const e: Thing = { name: 0 };
8 changes: 8 additions & 0 deletions packages/language-service-plugin/example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@total-typescript/language-service-plugin-example",
"version": "0.1.0",
"dependencies": {
"ts-error-translator-tssplugin": "file:..",
"typescript": "^4.5.3"
}
}
7 changes: 7 additions & 0 deletions packages/language-service-plugin/example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"plugins": [{
"name": "ts-error-translator-tssplugin"
}]
}
}
26 changes: 26 additions & 0 deletions packages/language-service-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "ts-error-translator-tssplugin",
"version": "0.1.0",
"license": "MIT",
"main": "./out/index.js",
"private": true,
"files": [
"./out/**"
],
"scripts": {
"dev": "tsc --watch",
"build": "rollup -c rollup.config.mjs"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^11.0.0",
"rollup": "^3.14.0",
"tsconfig": "workspace:*",
"typescript": "^4.5.3"
},
"dependencies": {
"@total-typescript/error-translation-engine": "workspace:*"
}
}
21 changes: 21 additions & 0 deletions packages/language-service-plugin/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';

export default {
input: 'src/index.ts',
output: {
file: 'out/index.js',
sourcemap: true,
format: 'cjs'
},
plugins: [
nodeResolve({
extensions: ['.mjs', '.js', '.json', '.node', '.ts']
}),
commonjs({ extensions: ['.js', '.ts'] }),
typescript(),
json()
]
};
53 changes: 53 additions & 0 deletions packages/language-service-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { parseErrors } from '@total-typescript/error-translation-engine';
Copy link
Author

Choose a reason for hiding this comment

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

@mattpocock I'm not sure if this is the right function to import here


export default function init(modules: { typescript: typeof import("typescript/lib/tsserverlibrary") }) {
const ts = modules.typescript;

function withParsedError(messageText: string): string {
const parsed = parseErrors(messageText);
const allMessages = parsed.map(err => err.error).join('\n\n');
return `${messageText}\n\nIn other words,\n${allMessages}\n`;
}

function enrichDiagnostic(diagnostic: ts.Diagnostic): ts.Diagnostic {
if (typeof diagnostic.messageText === 'string') {
diagnostic.messageText = withParsedError(diagnostic.messageText);
return diagnostic;
}
if (diagnostic.messageText.category === ts.DiagnosticCategory.Error) {
const msg = withParsedError(diagnostic.messageText.messageText);
diagnostic.messageText.messageText = msg;

const nextMesgs = diagnostic.messageText.next;
if (nextMesgs) {
for (let i = 0; i < nextMesgs.length; i++) {
let nextMsg = nextMesgs[i];
nextMesgs[i].messageText = withParsedError(nextMsg.messageText);
}
}
}
return diagnostic;
}

function create(info: ts.server.PluginCreateInfo) {
// Set up decorator object
const proxy: ts.LanguageService = Object.create(null);

for (let k of Object.keys(info.languageService) as Array<keyof ts.LanguageService>) {
const x = info.languageService[k]!;
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
}

proxy.getSemanticDiagnostics = (filename) => {
return info.languageService.getSemanticDiagnostics(filename).map(enrichDiagnostic);
}

return proxy;
}

return { create };

}

// export = init;
18 changes: 18 additions & 0 deletions packages/language-service-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"outDir": "./out",
"rootDir": "src",
"strict": true,
"declaration": true,
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules", "out"
]
}
Loading