Skip to content

Commit c793f51

Browse files
authored
Merge pull request #53 from CodinGame/use-vscode-services
Use vscode services
2 parents d90401b + 7b46da0 commit c793f51

22 files changed

+2457
-4185
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ dist/*
22
stats.html
33
.vscode
44
node_modules
5+
/extensions

jest/resolver.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const browserResolve = require('browser-resolve');
2+
3+
module.exports = (path, options) => {
4+
try {
5+
return browserResolve.sync(path, options)
6+
} catch (error) {
7+
return options.defaultResolver(path, options)
8+
}
9+
}

package-lock.json

Lines changed: 1996 additions & 3844 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
"test:watch": "jest --watch",
99
"build": "npm run test && npm run compile && npm run generate-types",
1010
"compile": "rollup --config rollup.config.ts --configPlugin typescript",
11-
"generate-types": "tsc --project tsconfig.types.json && rollup --config rollup.types.config.ts --configPlugin typescript && rm -rf ./dist/types"
11+
"generate-types": "tsc --project tsconfig.types.json && rollup --config rollup.types.config.ts --configPlugin typescript && rm -rf ./dist/types",
12+
"preprepare": "./scripts/install-extensions"
1213
},
1314
"repository": {
1415
"type": "git",
1516
"url": "https://github.com/CodinGame/monaco-languageclient-wrapper"
1617
},
17-
"moduleResolution": "node",
1818
"main": "./dist/index.js",
1919
"module": "./dist/index.js",
2020
"files": [
@@ -23,52 +23,51 @@
2323
],
2424
"types": "./dist/index.d.ts",
2525
"dependencies": {
26-
"@codingame/monaco-editor-wrapper": "^1.14.8",
27-
"sweetalert": "^2.1.2",
28-
"vscode": "npm:@codingame/monaco-vscode-api@^1.68.4",
26+
"@codingame/monaco-editor-wrapper": "^2.1.1",
27+
"recast": "^0.21.1",
28+
"vscode": "npm:@codingame/monaco-vscode-api@~1.67.12",
2929
"vscode-languageserver-protocol": "^3.17.1",
30-
"vscode-ws-jsonrpc": "^1.0.0"
30+
"vscode-ws-jsonrpc": "^1.0.1"
3131
},
3232
"devDependencies": {
33-
"@babel/core": "7.18.5",
34-
"@babel/plugin-proposal-class-properties": "7.17.12",
35-
"@babel/plugin-proposal-optional-chaining": "7.17.12",
36-
"@babel/plugin-transform-modules-commonjs": "^7.18.2",
37-
"@babel/preset-env": "7.18.2",
38-
"@babel/preset-typescript": "7.17.12",
39-
"@babel/runtime": "7.18.3",
40-
"@codingame/eslint-config": "^1.1.2",
41-
"@codingame/tsconfig": "^1.0.5",
33+
"@babel/core": "7.18.6",
34+
"@babel/plugin-proposal-class-properties": "7.18.6",
35+
"@babel/plugin-proposal-optional-chaining": "7.18.6",
36+
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
37+
"@babel/preset-env": "7.18.6",
38+
"@babel/preset-typescript": "7.18.6",
39+
"@babel/runtime": "7.18.6",
40+
"@codingame/eslint-config": "^1.1.5",
41+
"@codingame/tsconfig": "^1.1.0",
4242
"@rollup/plugin-alias": "3.1.9",
4343
"@rollup/plugin-babel": "5.3.1",
44-
"@rollup/plugin-commonjs": "22.0.0",
44+
"@rollup/plugin-commonjs": "22.0.1",
4545
"@rollup/plugin-eslint": "8.0.2",
4646
"@rollup/plugin-json": "4.1.0",
4747
"@rollup/plugin-node-resolve": "13.3.0",
4848
"@rollup/plugin-typescript": "^8.3.3",
49-
"@types/jest": "^28.1.2",
49+
"@types/jest": "^28.1.4",
5050
"@types/once": "^1.4.0",
51-
"@types/rollup-plugin-node-builtins": "^2.1.2",
52-
"@types/vscode": "^1.68.0",
53-
"@typescript-eslint/eslint-plugin": "5.29.0",
54-
"@typescript-eslint/parser": "5.29.0",
55-
"canvas": "^2.9.1",
51+
"@types/vscode": "~1.67.0",
52+
"@typescript-eslint/eslint-plugin": "5.30.5",
53+
"@typescript-eslint/parser": "5.30.5",
54+
"browser-resolve": "^2.0.0",
55+
"canvas": "^2.9.3",
5656
"conventional-changelog-conventionalcommits": "^5.0.0",
5757
"delay": "^5.0.0",
58-
"eslint": "8.18.0",
58+
"eslint": "8.19.0",
5959
"eslint-config-standard": "17.0.0",
6060
"eslint-plugin-import": "2.26.0",
6161
"eslint-plugin-jest": "^26.5.3",
62-
"eslint-plugin-n": "^15.2.3",
62+
"eslint-plugin-n": "^15.2.4",
6363
"eslint-plugin-promise": "6.0.0",
6464
"eslint-plugin-unused-imports": "^2.0.0",
65-
"jest": "^28.1.1",
66-
"jest-environment-jsdom": "^28.1.1",
67-
"monaco-languageclient": "^2.0.0",
65+
"jest": "^28.1.2",
66+
"jest-environment-jsdom": "^28.1.2",
67+
"monaco-languageclient": "^2.0.2",
6868
"proxy-polyfill": "^0.3.2",
69-
"rollup": "2.75.7",
69+
"rollup": "2.76.0",
7070
"rollup-plugin-dts": "^4.2.2",
71-
"rollup-plugin-node-builtins": "^2.1.2",
7271
"rollup-plugin-postcss": "4.0.2",
7372
"rollup-plugin-visualizer": "5.6.0",
7473
"rollup-plugin-web-worker-loader": "1.6.1",
@@ -78,7 +77,7 @@
7877
"vscode-languageserver-protocol": "^3.17.1"
7978
},
8079
"resolutions": {
81-
"eslint": "8.18.0"
80+
"eslint": "8.19.0"
8281
},
8382
"browserslist": [
8483
"defaults",
@@ -89,6 +88,7 @@
8988
"not IE_Mob 11"
9089
],
9190
"jest": {
91+
"resolver": "<rootDir>/jest/resolver.js",
9292
"testEnvironment": "jest-environment-jsdom",
9393
"modulePathIgnorePatterns": [
9494
"<rootDir>/dist/"

rollup.config.ts

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
55
import eslint from '@rollup/plugin-eslint'
66
import { babel } from '@rollup/plugin-babel'
77
import * as rollup from 'rollup'
8-
import builtins from 'rollup-plugin-node-builtins'
8+
import * as recast from 'recast'
9+
import path from 'path'
910
import pkg from './package.json'
1011

12+
const PURE_ANNO = '#__PURE__'
13+
const EXTENSION_DIR = path.resolve(__dirname, 'extensions')
14+
1115
const externals = [
1216
...Object.keys(pkg.dependencies),
1317
'monaco-editor'
@@ -20,17 +24,25 @@ export default rollup.defineConfig({
2024
input: {
2125
index: 'src/index.ts'
2226
},
27+
treeshake: {
28+
annotations: true,
29+
moduleSideEffects: false
30+
},
2331
external: function isExternal (source, importer, isResolved) {
2432
if (isResolved) {
2533
return false
2634
}
35+
if (source.startsWith('extensions/')) {
36+
return false
37+
}
2738
if (externals.some(external => source === external || source.startsWith(`${external}/`))) {
2839
return true
2940
}
3041
return false
3142
},
3243
output: [{
3344
chunkFileNames: '[name].js',
45+
hoistTransitiveImports: false,
3446
dir: 'dist',
3547
format: 'esm',
3648
paths: {
@@ -39,7 +51,6 @@ export default rollup.defineConfig({
3951
}
4052
}],
4153
plugins: [
42-
builtins() as rollup.Plugin,
4354
eslint({
4455
throwOnError: true,
4556
throwOnWarning: true,
@@ -49,6 +60,15 @@ export default rollup.defineConfig({
4960
extensions,
5061
browser: true
5162
}),
63+
{
64+
name: 'resolve-extensions',
65+
resolveId (id) {
66+
if (id.startsWith('extensions/')) {
67+
return path.resolve(__dirname, `${id}.js`)
68+
}
69+
return undefined
70+
}
71+
},
5272
commonjs({
5373
esmExternals: (id) => {
5474
if (id === 'vscode') {
@@ -93,6 +113,57 @@ export default rollup.defineConfig({
93113
right: ').then(module => module)'
94114
}
95115
}
116+
},
117+
{
118+
name: 'improve-extension-treeshaking',
119+
transform (code, id) {
120+
if (id.startsWith(EXTENSION_DIR)) {
121+
const ast = recast.parse(code, {
122+
parser: require('recast/parsers/babylon')
123+
})
124+
let transformed: boolean = false
125+
function addComment (node: recast.types.namedTypes.Expression) {
126+
if (!(node.comments ?? []).some(comment => comment.value === PURE_ANNO)) {
127+
transformed = true
128+
node.comments = [recast.types.builders.commentBlock(PURE_ANNO, true)]
129+
}
130+
}
131+
recast.visit(ast.program.body, {
132+
visitNewExpression (path) {
133+
const node = path.node
134+
if (node.callee.type === 'Identifier') {
135+
addComment(node)
136+
}
137+
this.traverse(path)
138+
},
139+
visitCallExpression (path) {
140+
const node = path.node
141+
if (node.callee.type === 'Identifier') {
142+
addComment(node)
143+
} else if (node.callee.type === 'FunctionExpression') {
144+
// Mark IIFE as pure, because typescript compile enums as IIFE
145+
addComment(node)
146+
}
147+
this.traverse(path)
148+
return undefined
149+
},
150+
visitFunctionDeclaration () {
151+
// Do not treeshake code inside functions, only at root
152+
return false
153+
},
154+
visitThrowStatement () {
155+
return false
156+
}
157+
})
158+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
159+
if (transformed) {
160+
code = recast.print(ast).code
161+
code = code.replace(/\/\*#__PURE__\*\/\s+/g, '/*#__PURE__*/ ') // Remove space after PURE comment
162+
return code
163+
}
164+
}
165+
return undefined
166+
}
96167
}
97168
]
98169
})

scripts/install-extensions

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
set -e
3+
4+
rm -rf "`pwd`/extensions"
5+
mkdir -p "`pwd`/extensions"
6+
7+
./scripts/install-java-extension

scripts/install-java-extension

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# In java, the vscode extension contains a lot of code to implement advanced features (jdt file provider, inlay hints, source action commands...)
5+
# Instead of copy-pasting this code, let's download it, build it and import it from our code
6+
7+
output_directory="`pwd`/extensions/java"
8+
9+
build_directory=`mktemp -d`
10+
echo "Downloading extension in $build_directory..."
11+
12+
curl -L --max-redirs 5 https://github.com/redhat-developer/vscode-java/tarball/v1.8.0 | tar -xz -C $build_directory --strip-components=1 redhat-developer-vscode-java-a0ac341
13+
cd $build_directory
14+
15+
echo "Installing dependencies..."
16+
npm install -y
17+
18+
# Remove useless files
19+
rm -rf test
20+
21+
echo "Patching code..."
22+
cd src
23+
24+
# Change import syntax so it builds to ESM
25+
find . -type f -exec sed -E -i 's/import (.*) = require\((.*)\)/import * as \1 from \2/g' {} \;
26+
27+
# Import from vscode-languageclient/lib/common/api instead of vscode-languageclient/node
28+
sed -i -E 's/import \{ (.*)LanguageClient(.*) \} from [\x27"]vscode-languageclient\/node[\x27"];/import { \1BaseLanguageClient as LanguageClient\2 } from \x27vscode-languageclient\/lib\/common\/api\x27;/g' sourceAction.ts inlayHintsProvider.ts
29+
30+
# Change syntax due to incompatibility between vscode-languageclient versions
31+
sed -i -E 's/languageClient.protocol2CodeConverter.asWorkspaceEdit\(/await languageClient.protocol2CodeConverter.asWorkspaceEdit(/g' sourceAction.ts extension.ts
32+
sed -i 's/function applyWorkspaceEdit(obj, languageClient): Thenable<boolean>/async function applyWorkspaceEdit(obj, languageClient): Promise<boolean>/g' extension.ts
33+
34+
echo "Building extension..."
35+
tsc --declaration --importHelpers --module es2020 --outDir "$output_directory/"
36+
37+
echo "Cleaning..."
38+
rm -rf $build_directory

src/createLanguageClient.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class CGLSPConnectionProvider implements IConnectionProvider {
134134
}
135135
}
136136

137-
function createLanguageClient (
137+
async function createLanguageClient (
138138
id: LanguageClientId,
139139
infrastructure: Infrastructure,
140140
{
@@ -145,7 +145,7 @@ function createLanguageClient (
145145
}: LanguageClientOptions,
146146
errorHandler: ErrorHandler,
147147
middleware?: Middleware
148-
): MonacoLanguageClient {
148+
): Promise<MonacoLanguageClient> {
149149
const client = new MonacoLanguageClient({
150150
id: `${id}-languageclient`,
151151
name: `CodinGame ${id} Language Client`,
@@ -165,7 +165,7 @@ function createLanguageClient (
165165
client.registerTextDocumentSaveFeatures()
166166

167167
if (createAdditionalFeatures != null) {
168-
client.registerFeatures(createAdditionalFeatures(client))
168+
client.registerFeatures(await createAdditionalFeatures(client))
169169
}
170170

171171
return client

src/extensionConfiguration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { loadConfigurationForExtension } from '@codingame/monaco-editor-wrapper/dist/features/extensionConfigurations'
1+
import { loadConfigurationForExtension } from '@codingame/monaco-editor-wrapper/features/extensionConfigurations'
22
import { getLanguageClientOptions, LanguageClientId } from './languageClientOptions'
33

44
/**

src/extensions/cobol.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
import {
2-
Disposable, MonacoLanguageClient
3-
} from 'monaco-languageclient'
4-
import { StaticFeature, FeatureState, ProtocolRequestType } from 'vscode-languageclient/lib/common/api'
1+
import { MonacoLanguageClient } from 'monaco-languageclient'
2+
import { ProtocolRequestType } from 'vscode-languageclient/lib/common/api'
53
import { DocumentSelector, ServerCapabilities } from 'vscode-languageserver-protocol'
64
import * as vscode from 'vscode'
5+
import { ExtensionFeature } from './tools'
76

87
export const ResolveCobolSubroutineRequestType = new ProtocolRequestType<string, string | undefined, never, void, void>('cobol/resolveSubroutine')
9-
export class CobolResolveSubroutineFeature implements StaticFeature {
10-
private onRequestDisposable: Disposable | undefined
8+
export class CobolResolveSubroutineFeature extends ExtensionFeature {
119
constructor (private languageClient: MonacoLanguageClient) {
10+
super()
1211
}
1312

14-
fillClientCapabilities (): void {}
15-
16-
initialize (capabilities: ServerCapabilities, documentSelector: DocumentSelector): void {
17-
this.onRequestDisposable = this.languageClient.onRequest(ResolveCobolSubroutineRequestType, (routineName: string): string | undefined => {
13+
activate (context: vscode.ExtensionContext, capabilities: ServerCapabilities, documentSelector: DocumentSelector): void {
14+
context.subscriptions.push(this.languageClient.onRequest(ResolveCobolSubroutineRequestType, (routineName: string): string | undefined => {
1815
const constantRoutinePaths: Partial<Record<string, string>> = {
1916
'assert-equals': `file:${vscode.workspace.rootPath ?? '/tmp/project'}/deps/assert-equals.cbl`
2017
}
@@ -26,16 +23,6 @@ export class CobolResolveSubroutineFeature implements StaticFeature {
2623
.filter(textDocument => vscode.languages.match(documentSelector, textDocument))
2724
.filter(document => document.getText().match(new RegExp(`PROGRAM-ID\\.\\W+${routineName}\\.`, 'gi')))
2825
.sort((a, b) => a.uri.toString().localeCompare(b.uri.toString()))[0]?.uri.toString()
29-
})
30-
}
31-
32-
getState (): FeatureState {
33-
return {
34-
kind: 'static'
35-
}
36-
}
37-
38-
dispose (): void {
39-
this.onRequestDisposable?.dispose()
26+
}))
4027
}
4128
}

0 commit comments

Comments
 (0)