Skip to content

Instantly share code, notes, and snippets.

@okikio
Last active October 19, 2021 15:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okikio/e8de391154a8c85a90b39056e21ec80b to your computer and use it in GitHub Desktop.
Save okikio/e8de391154a8c85a90b39056e21ec80b to your computer and use it in GitHub Desktop.
ts-server.js
importScripts("https://unpkg.com/@typescript/vfs@1.3.5/dist/vfs.globals.js");
importScripts(
"https://cdnjs.cloudflare.com/ajax/libs/typescript/4.4.3/typescript.min.js"
);
importScripts("https://unpkg.com/@okikio/emitter@2.1.7/lib/api.js");
export type VFS = typeof import("https://cdn.esm.sh/@typescript/vfs");
export type EVENT_EMITTER = import("https://cdn.esm.sh/@okikio/emitter").EventEmitter;
export type Diagnostic = import("https://cdn.esm.sh/@codemirror/lint").Diagnostic;
var {
createDefaultMapFromCDN,
createSystem,
createVirtualTypeScriptEnvironment
} = globalThis.tsvfs as VFS;
var ts = globalThis.ts; // as TS
var EventEmitter = globalThis.emitter.EventEmitter;
var _emitter: EVENT_EMITTER = new EventEmitter();
globalThis.localStorage = globalThis.localStorage ?? ({} as Storage);
(async () => {
const compilerOpts = {
target: ts.ScriptTarget.ES2021,
module: ts.ScriptTarget.ES2020,
lib: ["es2021", "es2020", "dom", "webworker"],
esModuleInterop: true
};
let initialText = "const hello = 'hi'";
_emitter.once("updateText", (details) => {
initialText = details.text.join("\n");
});
const fsMap = await createDefaultMapFromCDN(
compilerOpts,
ts.version,
false,
ts
);
const ENTRY_POINT = "index.ts";
fsMap.set(ENTRY_POINT, initialText);
const system = createSystem(fsMap);
const env = createVirtualTypeScriptEnvironment(
system,
[ENTRY_POINT],
ts,
compilerOpts
);
// You can then interact with the languageService to introspect the code
postMessage({
event: "ready",
details: []
});
_emitter.on("updateText", (details) => {
env.updateFile(ENTRY_POINT, [].concat(details.text).join("\n"));
// console.log(details.text)
});
_emitter.on("autocomplete-request", ({ pos }) => {
let result = env.languageService.getCompletionsAtPosition(
ENTRY_POINT,
pos,
{}
);
postMessage({
event: "autocomplete-results",
details: result
});
});
_emitter.on("tooltip-request", ({ pos }) => {
let result = env.languageService.getQuickInfoAtPosition(
ENTRY_POINT,
pos
);
postMessage({
event: "tooltip-results",
details: result
? {
result,
tootltipText:
ts.displayPartsToString(result.displayParts) +
(result.documentation?.length
? "\n" +
ts.displayPartsToString(result.documentation)
: "")
}
: { result, tooltipText: "" }
});
});
_emitter.on("lint-request", () => {
let SyntacticDiagnostics = env.languageService.getSyntacticDiagnostics(
ENTRY_POINT
);
let SemanticDiagnostic = env.languageService.getSemanticDiagnostics(
ENTRY_POINT
);
let SuggestionDiagnostics = env.languageService.getSuggestionDiagnostics(
ENTRY_POINT
);
type Diagnostics = typeof SyntacticDiagnostics &
typeof SemanticDiagnostic &
typeof SuggestionDiagnostics;
let result: Diagnostics = [].concat(
SyntacticDiagnostics,
SemanticDiagnostic,
SuggestionDiagnostics
);
postMessage({
event: "lint-results",
details: result.map((v) => {
let from = v.start;
let to = v.start + v.length;
// let codeActions = env.languageService.getCodeFixesAtPosition(ENTRY_POINT, from, to, [v.category], {}, {});
let diag: Diagnostic = {
from,
to,
message: v.messageText as string,
source: v?.source,
severity: ["warning", "error", "info", "info"][
v.category
] as Diagnostic["severity"]
// actions: codeActions as any as Diagnostic["actions"]
};
return diag;
})
});
});
})();
addEventListener(
"message",
({ data }: MessageEvent<{ event: string; details: any }>) => {
let { event, details } = data;
_emitter.emit(event, details);
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment