diff --git a/src/playground-code-editor.ts b/src/playground-code-editor.ts index 74873047..1085ef80 100644 --- a/src/playground-code-editor.ts +++ b/src/playground-code-editor.ts @@ -632,7 +632,7 @@ export class PlaygroundCodeEditor extends LitElement { private _currentFiletypeSupportsCompletion() { // Currently we are only supporting code completion for TS. Change // this in a case that we start to support it for other languages too. - return this.type === 'ts'; + return this.type === 'ts' || this.type === 'js'; } override focus() { diff --git a/src/typescript-worker/language-service-context.ts b/src/typescript-worker/language-service-context.ts index 00d9cdbf..54dec804 100644 --- a/src/typescript-worker/language-service-context.ts +++ b/src/typescript-worker/language-service-context.ts @@ -13,6 +13,7 @@ const compilerOptions = { skipDefaultLibCheck: true, skipLibCheck: true, allowJs: true, + checkJs: true, moduleResolution: ts.ModuleResolutionKind.NodeJs, jsx: ts.JsxEmit.React, lib: ['dom', 'esnext'], @@ -66,12 +67,17 @@ class WorkerLanguageServiceHost implements ts.LanguageServiceHost { */ updateFileContentIfNeeded(fileName: string, content: string) { const file = this.files.get(fileName); - if (file && file.content !== content) { + if (file) { + if (file.content === content) { + // The file hasn't changed, exit early. + return; + } file.content = content; file.version += 1; - } else { - this.files.set(fileName, {content, version: 0}); + return; } + + this.files.set(fileName, {content, version: 0}); } /** diff --git a/src/typescript-worker/typescript-builder.ts b/src/typescript-worker/typescript-builder.ts index 544d4e44..67a9dc90 100644 --- a/src/typescript-worker/typescript-builder.ts +++ b/src/typescript-worker/typescript-builder.ts @@ -10,6 +10,8 @@ import {PackageJson} from './util.js'; import {makeLspDiagnostic} from './diagnostic.js'; import {WorkerContext} from './worker-context.js'; +const PROCESSED_FILE_ENDINGS = ['.ts', '.jsx', '.tsx']; + export async function* processTypeScriptFiles( workerContext: WorkerContext, results: AsyncIterable | Iterable @@ -20,22 +22,32 @@ export async function* processTypeScriptFiles( let packageJson: PackageJson | undefined; const compilerInputs = []; for await (const result of results) { + if (result.kind !== 'file') continue; + + // Collect filetypes that need to be compiled. They will be handled later on in the process. if ( - result.kind === 'file' && - (result.file.name.endsWith('.ts') || - result.file.name.endsWith('.jsx') || - result.file.name.endsWith('.tsx')) + PROCESSED_FILE_ENDINGS.some((ending) => result.file.name.endsWith(ending)) ) { compilerInputs.push(result.file); - } else { - yield result; - if (result.kind === 'file' && result.file.name === 'package.json') { - try { - packageJson = JSON.parse(result.file.content) as PackageJson; - } catch (e) { - // A bit hacky, but BareModuleTransformer already emits a diagnostic - // for this case, so we don't need another one. - } + continue; + } + // Everything that reaches this point should be usable out of the box without compiling. + // Therefore we can just yield the result to the caller. + yield result; + + // Even though we don't need to compile javascript files, we want to append them to our + // compilerinputs to get completions and diagnostics for those files. + if (result.file.name.endsWith('.js')) { + compilerInputs.push(result.file); + continue; + } + + if (result.file.name === 'package.json') { + try { + packageJson = JSON.parse(result.file.content) as PackageJson; + } catch (e) { + // A bit hacky, but BareModuleTransformer already emits a diagnostic + // for this case, so we don't need another one. } } }