Skip to content

Commit

Permalink
feat: add standalone typescript feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Loïc Mangeonjean committed Jun 26, 2024
1 parent d0d8214 commit 1d65da7
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Those feature can be used in the workbench feature is enabled:
- `@codingame/monaco-editor-wrapper/features/extensionGallery` enables the extension gallery panel and the possibility to install extensions from the marketplace
- `@codingame/monaco-editor-wrapper/features/terminal` enables the terminal panel
- `@codingame/monaco-editor-wrapper/features/testing` enables the testing panels
- `@codingame/monaco-editor-wrapper/features/typescriptStandalone` enables the monaco standalone typescript language feature worker

### Embed language IntelliSense

Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
"./features/profile": {
"types": "./dist/features/profile.d.ts",
"default": "./dist/features/profile.js"
},
"./features/typescriptStandalone": {
"types": "./dist/features/typescriptStandalone.d.ts",
"default": "./dist/features/typescriptStandalone.js"
}
},
"typesVersions": {
Expand Down Expand Up @@ -100,6 +104,9 @@
],
"features/profile": [
"./dist/features/profile.d.ts"
],
"features/typescriptStandalone": [
"./dist/features/typescriptStandalone.d.ts"
]
}
},
Expand Down Expand Up @@ -167,6 +174,7 @@
"@codingame/monaco-vscode-shellscript-default-extension": "^6.0.1",
"@codingame/monaco-vscode-snippets-service-override": "^6.0.1",
"@codingame/monaco-vscode-sql-default-extension": "^6.0.1",
"@codingame/monaco-vscode-standalone-typescript-language-features": "^6.0.3",
"@codingame/monaco-vscode-storage-service-override": "^6.0.1",
"@codingame/monaco-vscode-swift-default-extension": "^6.0.1",
"@codingame/monaco-vscode-terminal-service-override": "^6.0.1",
Expand All @@ -177,15 +185,16 @@
"@codingame/monaco-vscode-theme-seti-default-extension": "^6.0.1",
"@codingame/monaco-vscode-timeline-service-override": "^6.0.1",
"@codingame/monaco-vscode-typescript-basics-default-extension": "^6.0.1",
"@codingame/monaco-vscode-user-data-profile-service-override": "^6.0.1",
"@codingame/monaco-vscode-vb-default-extension": "^6.0.1",
"@codingame/monaco-vscode-view-status-bar-service-override": "^6.0.1",
"@codingame/monaco-vscode-views-service-override": "^6.0.1",
"@codingame/monaco-vscode-workbench-service-override": "^6.0.1",
"@codingame/monaco-vscode-working-copy-service-override": "^6.0.1",
"@codingame/monaco-vscode-xml-default-extension": "^6.0.1",
"@codingame/monaco-vscode-yaml-default-extension": "^6.0.1",
"@codingame/monaco-vscode-user-data-profile-service-override": "^6.0.1",
"monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^6.0.1",
"typescript-worker-node-types": "npm:@types/node@^16.11.7",
"vscode": "npm:@codingame/monaco-vscode-api@^6.0.1"
},
"devDependencies": {
Expand Down
39 changes: 34 additions & 5 deletions rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import typescript from '@rollup/plugin-typescript'
import * as rollup from 'rollup'
import vsixPlugin, { IExtensionManifest } from '@codingame/monaco-vscode-rollup-vsix-plugin'
import glob from 'fast-glob'
import { addExtension } from '@rollup/pluginutils'
import { addExtension, dataToEsm } from '@rollup/pluginutils'
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets'
import path from 'path'
import fs from 'fs'
import pkg from './package.json' assert { type: 'json' }

const externals = Object.keys(pkg.dependencies)
Expand All @@ -29,7 +30,8 @@ export default rollup.defineConfig({
'features/notifications': 'src/features/notifications.ts',
'features/extensionGallery': 'src/features/extensionGallery.ts',
'features/workbench': 'src/features/workbench.ts',
'features/profile': 'src/features/profile.ts'
'features/profile': 'src/features/profile.ts',
'features/typescriptStandalone': 'src/features/typescriptStandalone.ts'
},
output: [{
dir: 'dist',
Expand Down Expand Up @@ -74,17 +76,44 @@ export default rollup.defineConfig({
return undefined
}
},
{
name: 'd-ts-glob-import',
async resolveId (source, importer) {
if (source.startsWith('types:')) {
return `types:${path.resolve(path.dirname(importer!), source.slice(6))}`
}
return undefined
},
async load (importee) {
if (importee.startsWith('types:')) {
const cwd = importee.slice(6)
const files = await glob('**/*.d.ts', {
cwd
})

const data = Object.fromEntries(await Promise.all(files.map(async f => {
const data = await fs.promises.readFile(path.resolve(cwd, f))
return [
f,
data.toString('utf-8')
]
})))
return dataToEsm(data)
}
return undefined
}
},
{
name: 'glob-vsix-import',
async resolveId (source, importer) {
if (source.endsWith('*.vsix')) {
return `glob:${path.resolve(path.dirname(importer!), source)}`
return `vsixGlob:${path.resolve(path.dirname(importer!), source)}`
}
return undefined
},
async load (importee) {
if (importee.startsWith('glob:')) {
const files = await glob(importee.slice(5))
if (importee.startsWith('vsixGlob:')) {
const files = await glob(importee.slice(9))

return `
${files.map((file, index) => `import { whenReady as whenReady${index} } from '${file}'`).join('\n')}
Expand Down
120 changes: 120 additions & 0 deletions src/features/typescriptStandalone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import '@codingame/monaco-vscode-standalone-typescript-language-features'
import * as monaco from 'monaco-editor'
import { FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode, FileType, IFileSystemProviderWithFileReadWriteCapability, IStat, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'
import * as vscode from 'vscode'
import { registerWorkerLoader } from '../worker.js'

const global = `
declare global {
/**
* Read a line from stdin
*/
function readline(): string;
/**
* Print a string to stdout
* @deprecated Use console.log instead
*/
function print(word: string): void;
}
// It needs to be a module
export {}
`

const compilerOptions: Parameters<typeof monaco.languages.typescript.typescriptDefaults.setCompilerOptions>[0] = {
target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
noEmit: true,
lib: ['es2020']
}

class TypescriptWorkerTypeFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability {
capabilities = FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.PathCaseSensitive | FileSystemProviderCapabilities.Readonly

constructor (private getWorker: () => Promise<monaco.languages.typescript.TypeScriptWorker>) {
}

private async getExtraLib (resource: monaco.Uri) {
const content = await (await this.getWorker()).getScriptText(resource.path.slice(1))

return content
}

async readFile (resource: monaco.Uri): Promise<Uint8Array> {
const file = await this.getExtraLib(resource)
if (file != null) {
return new TextEncoder().encode(file)
}
throw FileSystemProviderError.create('file not found', FileSystemProviderErrorCode.FileNotFound)
}

async stat (resource: monaco.Uri): Promise<IStat> {
const file = await this.getExtraLib(resource)
if (file != null) {
return {
type: FileType.File,
size: file.length,
mtime: 0,
ctime: 0
}
}
throw FileSystemProviderError.create('file not found', FileSystemProviderErrorCode.FileNotFound)
}

async writeFile (): Promise<void> {
throw FileSystemProviderError.create('not allowed', FileSystemProviderErrorCode.NoPermissions)
}

onDidChangeCapabilities = new vscode.EventEmitter<never>().event
onDidChangeFile = new vscode.EventEmitter<never>().event
watch (): monaco.IDisposable {
return {
dispose () {}
}
}

async mkdir (): Promise<void> {
throw FileSystemProviderError.create('Not allowed', FileSystemProviderErrorCode.NoPermissions)
}

async readdir () {
return []
}

async delete (): Promise<void> {
throw FileSystemProviderError.create('Not allowed', FileSystemProviderErrorCode.NoPermissions)
}

async rename (): Promise<void> {
throw FileSystemProviderError.create('Not allowed', FileSystemProviderErrorCode.NoPermissions)
}
}

monaco.languages.typescript.typescriptDefaults.setCompilerOptions(compilerOptions)
monaco.languages.typescript.javascriptDefaults.setCompilerOptions(compilerOptions)
monaco.languages.typescript.typescriptDefaults.addExtraLib(global, 'global.d.ts')
monaco.languages.typescript.javascriptDefaults.addExtraLib(global, 'global.d.ts')

monaco.languages.onLanguage('typescript', async () => {
registerFileSystemOverlay(-1, new TypescriptWorkerTypeFileSystemProvider(async () => (await monaco.languages.typescript.getTypeScriptWorker())()))

const types = (await import('types:../../node_modules/typescript-worker-node-types')).default

for (const [file, content] of Object.entries(types)) {
monaco.languages.typescript.typescriptDefaults.addExtraLib(content, `node/${file}`)
}
})
monaco.languages.onLanguage('javascript', async () => {
registerFileSystemOverlay(-1, new TypescriptWorkerTypeFileSystemProvider(async () => (await monaco.languages.typescript.getJavaScriptWorker())()))

const types = (await import('types:../../node_modules/typescript-worker-node-types')).default

for (const [file, content] of Object.entries(types)) {
monaco.languages.typescript.javascriptDefaults.addExtraLib(content, `node/${file}`)
}
})

const workerLoader = () => new Worker(new URL('@codingame/monaco-vscode-standalone-typescript-language-features/worker', import.meta.url))
registerWorkerLoader('typescript', workerLoader)
registerWorkerLoader('javascript', workerLoader)
4 changes: 4 additions & 0 deletions src/types/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module 'types:*' {
const types: Record<string, string>
export default types
}

0 comments on commit 1d65da7

Please sign in to comment.