feat: bun automatic type acquisition in frontend directly (#2884)

* foo

* ata

* done

* remove bun from lsp

* update all
This commit is contained in:
Ruben Fiszel
2023-12-20 12:52:01 +01:00
committed by GitHub
parent 2155a6c133
commit d507ce449b
35 changed files with 46493 additions and 4658 deletions
+11 -10
View File
@@ -47,10 +47,9 @@ impl Visit for ImportsFinder {
pub fn parse_expr_for_imports(code: &str) -> anyhow::Result<Vec<String>> {
let cm: Lrc<SourceMap> = Default::default();
let fm = cm.new_source_file(FileName::Custom("main.ts".into()), code.into());
let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()), code.into());
let lexer = Lexer::new(
// We want to parse ecmascript
Syntax::Es(EsConfig { jsx: false, ..Default::default() }),
Syntax::Typescript(TsConfig::default()),
// EsVersion defaults to es5
Default::default(),
StringInput::from(&*fm),
@@ -64,9 +63,9 @@ pub fn parse_expr_for_imports(code: &str) -> anyhow::Result<Vec<String>> {
err_s += &e.into_kind().msg().to_string();
}
let expr = parser
.parse_module()
.map_err(|_| anyhow::anyhow!("Error while parsing code, it is invalid TypeScript"))?;
let expr = parser.parse_module().map_err(|e| {
anyhow::anyhow!("Error while parsing code, it is invalid TypeScript: {err_s}, {e:?}")
})?;
let mut visitor = ImportsFinder { imports: HashSet::new() };
swc_ecma_visit::visit_module(&mut visitor, &expr);
@@ -119,9 +118,9 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result<Vec<(String, String)>> {
err_s += &e.into_kind().msg().to_string();
}
let expr = parser
.parse_module()
.map_err(|_| anyhow::anyhow!("Error while parsing code, it is invalid TypeScript"))?;
let expr = parser.parse_module().map_err(|e| {
anyhow::anyhow!("Error while parsing code, it is invalid TypeScript: {err_s}, {e:?}")
})?;
let mut visitor = OutputFinder { idents: HashSet::new() };
swc_ecma_visit::visit_module(&mut visitor, &expr);
@@ -150,7 +149,9 @@ pub fn parse_deno_signature(code: &str, skip_dflt: bool) -> anyhow::Result<MainA
let ast = parser
.parse_module()
.map_err(|_| anyhow::anyhow!("Error while parsing code, it is invalid TypeScript"))?
.map_err(|e| {
anyhow::anyhow!("Error while parsing code, it is invalid TypeScript: {err_s}, {e:?}")
})?
.body;
let params = ast.into_iter().find_map(|x| match x {
@@ -3,7 +3,7 @@
"collaborators": [
"Ruben Fiszel <ruben@windmill.dev>"
],
"version": "1.222.0",
"version": "1.226.9",
"files": [
"windmill_parser_wasm_bg.wasm",
"windmill_parser_wasm.js",
@@ -14,4 +14,4 @@
"sideEffects": [
"./snippets/*"
]
}
}
@@ -14,6 +14,11 @@ export function parse_outputs(code: string): string;
* @param {string} code
* @returns {string}
*/
export function parse_ts_imports(code: string): string;
/**
* @param {string} code
* @returns {string}
*/
export function parse_bash(code: string): string;
/**
* @param {string} code
@@ -67,6 +72,7 @@ export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly parse_deno: (a: number, b: number, c: number) => void;
readonly parse_outputs: (a: number, b: number, c: number) => void;
readonly parse_ts_imports: (a: number, b: number, c: number) => void;
readonly parse_bash: (a: number, b: number, c: number) => void;
readonly parse_powershell: (a: number, b: number, c: number) => void;
readonly parse_go: (a: number, b: number, c: number) => void;
@@ -97,6 +97,15 @@ function getInt32Memory0() {
return cachedInt32Memory0;
}
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
@@ -115,15 +124,6 @@ function getFloat64Memory0() {
return cachedFloat64Memory0;
}
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let cachedBigInt64Memory0 = null;
function getBigInt64Memory0() {
@@ -243,6 +243,29 @@ export function parse_outputs(code) {
}
}
/**
* @param {string} code
* @returns {string}
*/
export function parse_ts_imports(code) {
let deferred2_0;
let deferred2_1;
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
wasm.parse_ts_imports(retptr, ptr0, len0);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
deferred2_0 = r0;
deferred2_1 = r1;
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
}
}
/**
* @param {string} code
* @returns {string}
@@ -518,10 +541,6 @@ function __wbg_get_imports() {
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbg_eval_1081105c41705556 = function(arg0, arg1) {
const ret = eval(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'string' ? obj : undefined;
@@ -530,6 +549,10 @@ function __wbg_get_imports() {
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_boolean_get = function(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
@@ -566,8 +589,8 @@ function __wbg_get_imports() {
const ret = getObject(arg0) in getObject(arg1);
return ret;
};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
imports.wbg.__wbg_eval_596393dc5ae50a1b = function(arg0, arg1) {
const ret = eval(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
@@ -3,6 +3,7 @@
export const memory: WebAssembly.Memory;
export function parse_deno(a: number, b: number, c: number): void;
export function parse_outputs(a: number, b: number, c: number): void;
export function parse_ts_imports(a: number, b: number, c: number): void;
export function parse_bash(a: number, b: number, c: number): void;
export function parse_powershell(a: number, b: number, c: number): void;
export function parse_go(a: number, b: number, c: number): void;
@@ -31,7 +31,7 @@ pub fn parse_outputs(code: &str) -> String {
pub fn parse_ts_imports(code: &str) -> String {
let parsed = parse_expr_for_imports(code);
let r = if let Ok(parsed) = parsed {
json!({ "imports6": parsed })
json!({ "imports": parsed })
} else {
json!({"error": parsed.err().unwrap().to_string()})
};
@@ -298,3 +298,15 @@ fn test_parse_imports() -> anyhow::Result<()> {
Ok(())
}
#[wasm_bindgen_test]
fn test_parse_imports_dts() -> anyhow::Result<()> {
let code = "
export type foo = number
";
let mut l = parse_expr_for_imports(code)?;
l.sort();
assert_eq!(l, vec![] as Vec<String>);
Ok(())
}
+4 -4
View File
@@ -48,7 +48,7 @@
"vscode-languageclient": "~9.0.1",
"vscode-uri": "~3.0.8",
"vscode-ws-jsonrpc": "~3.1.0",
"windmill-parser-wasm": "^1.222.0",
"windmill-parser-wasm": "^1.226.9",
"y-monaco": "^0.1.4",
"y-websocket": "^1.5.0",
"yaml": "^2.3.4",
@@ -9585,9 +9585,9 @@
}
},
"node_modules/windmill-parser-wasm": {
"version": "1.222.0",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.222.0.tgz",
"integrity": "sha512-7Ax3R1qo9Ae5QGewxgf8IcNSk+eVIv1CZwKkUoo1cQMf1FZcgM+oW9GuZ6Q3IFCsGbnjk+cyqhKvxr3hBBMN9A=="
"version": "1.226.9",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.226.9.tgz",
"integrity": "sha512-yOlLjUF4NlRutZhHrRa4fhxuxLslMaVXBojY3QyIVLlSq+7SGIUTYpEb04XrwpcCNyrgMIL1cNYaq4qzGDKsxA=="
},
"node_modules/wordwrap": {
"version": "1.0.0",
+1 -1
View File
@@ -131,7 +131,7 @@
"vscode-languageclient": "~9.0.1",
"vscode-uri": "~3.0.8",
"vscode-ws-jsonrpc": "~3.1.0",
"windmill-parser-wasm": "^1.222.0",
"windmill-parser-wasm": "^1.226.9",
"y-monaco": "^0.1.4",
"y-websocket": "^1.5.0",
"yaml": "^2.3.4",
+70
View File
@@ -0,0 +1,70 @@
import type { ATABootstrapConfig } from "./index"
// https://github.com/jsdelivr/data.jsdelivr.com
export const getNPMVersionsForModule = (config: ATABootstrapConfig, moduleName: string) => {
const url = `https://data.jsdelivr.com/v1/package/npm/${moduleName}`
return api<{ tags: Record<string, string>; versions: string[] }>(config, url, { cache: "no-store" })
}
export const getNPMVersionForModuleReference = (config: ATABootstrapConfig, moduleName: string, reference: string) => {
const url = `https://data.jsdelivr.com/v1/package/resolve/npm/${moduleName}@${reference}`
return api<{ version: string | null }>(config, url)
}
export type NPMTreeMeta = {
default: string
files: Array<{ name: string }>
moduleName: string
version: string
raw: string
}
export const getFiletreeForModuleWithVersion = async (
config: ATABootstrapConfig,
moduleName: string,
version: string,
raw: string
) => {
const url = `https://data.jsdelivr.com/v1/package/npm/${moduleName}@${version}/flat`
const res = await api<NPMTreeMeta>(config, url)
if (res instanceof Error) {
return res
} else {
return {
...res,
moduleName,
version,
raw,
}
}
}
export const getDTSFileForModuleWithVersion = async (
config: ATABootstrapConfig,
moduleName: string,
version: string,
file: string
) => {
// file comes with a prefix /
const url = `https://cdn.jsdelivr.net/npm/${moduleName}@${version}${file}`
const f = config.fetcher || fetch
const res = await f(url)
if (res.ok) {
return res.text()
} else {
return new Error("OK")
}
}
function api<T>(config: ATABootstrapConfig, url: string, init?: RequestInit): Promise<T | Error> {
const f = config.fetcher || fetch
return f(url, init).then(res => {
if (res.ok) {
return res.json().then(f => f as T)
} else {
return new Error("OK")
}
})
}
+69
View File
@@ -0,0 +1,69 @@
/** Converts some of the known global imports to node so that we grab the right info */
export const mapModuleNameToModule = (moduleSpecifier: string) => {
// in node repl:
// > require("module").builtinModules
const builtInNodeMods = [
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"path/posix",
"path/win32",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"stream/promises",
"stream/consumers",
"stream/web",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"url",
"util",
"util/types",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib",
]
if (builtInNodeMods.includes(moduleSpecifier.replace("node:", ""))) {
return "node"
}
// strip module filepath e.g. lodash/identity => lodash
const [a = "", b = ""] = moduleSpecifier.split("/")
const moduleName = a.startsWith("@") ? `${a}/${b}` : a
return moduleName
}
+279
View File
@@ -0,0 +1,279 @@
import {
getDTSFileForModuleWithVersion,
getFiletreeForModuleWithVersion,
getNPMVersionForModuleReference,
getNPMVersionsForModule,
type NPMTreeMeta
} from './apis'
import { mapModuleNameToModule } from './edgeCases'
export interface ATABootstrapConfig {
/** A object you pass in to get callbacks */
delegate: {
/** The callback which gets called when ATA decides a file needs to be written to your VFS */
receivedFile?: (code: string, path: string) => void
/** A way to display progress */
progress?: (downloaded: number, estimatedTotal: number) => void
/** Note: An error message does not mean ATA has stopped! */
errorMessage?: (userFacingMessage: string, error: Error) => void
/** A callback indicating that ATA actually has work to do */
started?: () => void
/** The callback when all ATA has finished */
finished?: (files: Map<string, string>) => void
}
/** Passed to fetch as the user-agent */
projectName: string
/** code to dependency parser */
depsParser: (code: string) => string[]
/** If you need a custom version of fetch */
fetcher?: typeof fetch
/** If you need a custom logger instead of the console global */
logger?: Logger
}
type ModuleMeta = { state: 'loading' }
/**
* The function which starts up type acquisition,
* returns a function which you then pass the initial
* source code for the app with.
*
* This is effectively the main export, everything else is
* basically exported for tests and should be considered
* implementation details by consumers.
*/
export const setupTypeAcquisition = (config: ATABootstrapConfig) => {
const moduleMap = new Map<string, ModuleMeta>()
const fsMap = new Map<string, string>()
let estimatedToDownload = 0
let estimatedDownloaded = 0
return (initialSourceFile: string) => {
estimatedToDownload = 0
estimatedDownloaded = 0
return resolveDeps(initialSourceFile, 0).then((t) => {
if (estimatedDownloaded > 0) {
config.delegate.finished?.(fsMap)
}
})
}
function getVersion(d: string) {
if (d.lastIndexOf('@') > 0) {
const splitted = d.split('@')
let version = splitted.pop()
if (version?.startsWith('^') || version?.startsWith('~')) {
version = version.slice(1)
}
return version
}
return 'latest'
}
async function resolveDeps(initialSourceFile: string, depth: number) {
if (depth > 2) {
console.log('STOP HERE', depth)
return
} else {
console.log('L', depth)
}
const depsToGet = config
.depsParser(initialSourceFile)
.map((d: string) => {
let raw = mapModuleNameToModule(d)
return {
raw,
module: raw.lastIndexOf('@') > 0 ? raw.split('@').slice(0, -1).join('@') : raw,
version: getVersion(d)
}
})
.filter((f) => !moduleMap.has(f.raw))
if (depsToGet.length === 0) {
return
}
// Make it so it won't get re-downloaded
depsToGet.forEach((dep) => moduleMap.set(dep.raw, { state: 'loading' }))
// Grab the module trees which gives us a list of files to download
const trees = await Promise.all(
depsToGet.map((f) => getFileTreeForModuleWithTag(config, f.module, f.version, f.raw))
)
const treesOnly = trees.filter((t) => !('error' in t)) as NPMTreeMeta[]
// These are the modules which we can grab directly
const hasDTS = treesOnly.filter((t) => t.files.find((f) => f.name.endsWith('.d.ts')))
const dtsFilesFromNPM = hasDTS.map((t) => treeToDTSFiles(t, `/node_modules/${t.raw}`))
// These are ones we need to look on DT for (which may not be there, who knows)
const mightBeOnDT = treesOnly.filter((t) => !hasDTS.includes(t))
const dtTrees = await Promise.all(
// TODO: Switch from 'latest' to the version from the original tree which is user-controlled
mightBeOnDT.map((f) =>
getFileTreeForModuleWithTag(
config,
`@types/${getDTName(f.moduleName)}`,
'latest',
`@types/${getDTName(f.raw)}`
)
)
)
const dtTreesOnly = dtTrees.filter((t) => !('error' in t)) as NPMTreeMeta[]
const dtsFilesFromDT = dtTreesOnly.map((t) =>
treeToDTSFiles(t, `/node_modules/@types/${getDTName(t.raw).replace('types__', '')}`)
)
// Collect all the npm and DT DTS requests and flatten their arrays
const allDTSFiles = dtsFilesFromNPM.concat(dtsFilesFromDT).reduce((p, c) => p.concat(c), [])
estimatedToDownload += allDTSFiles.length
if (allDTSFiles.length && depth === 0) {
config.delegate.started?.()
}
// Grab the package.jsons for each dependency
for (const tree of treesOnly) {
const pkgJSON = await getDTSFileForModuleWithVersion(
config,
tree.moduleName,
tree.version,
'/package.json'
)
let prefix = `/node_modules/${tree.moduleName}`
if (dtTreesOnly.includes(tree))
prefix = `/node_modules/@types/${getDTName(tree.raw).replace('types__', '')}`
const path = prefix + '/package.json'
if (typeof pkgJSON == 'string') {
fsMap.set(path, pkgJSON)
config.delegate.receivedFile?.(pkgJSON, path)
} else {
config.logger?.error(`Could not download package.json for ${tree.moduleName}`)
}
}
// Grab all dts files
await Promise.all(
allDTSFiles.map(async (dts) => {
const dtsCode = await getDTSFileForModuleWithVersion(
config,
dts.moduleName,
dts.moduleVersion,
dts.path
)
estimatedDownloaded++
if (dtsCode instanceof Error) {
// TODO?
config.logger?.error(`Had an issue getting ${dts.path} for ${dts.moduleName}`)
} else {
fsMap.set(dts.vfsPath, dtsCode)
config.delegate.receivedFile?.(dtsCode, dts.vfsPath)
// Send a progress note every 5 downloads
if (config.delegate.progress && estimatedDownloaded % 5 === 0) {
config.delegate.progress(estimatedDownloaded, estimatedToDownload)
}
if (dts.moduleName != 'bun-types') {
// Recurse through deps
await resolveDeps(dtsCode, depth + 1)
}
}
})
)
}
}
type ATADownload = {
moduleName: string
moduleVersion: string
vfsPath: string
path: string
}
function treeToDTSFiles(tree: NPMTreeMeta, vfsPrefix: string) {
const dtsRefs: ATADownload[] = []
for (const file of tree.files) {
if (file.name.endsWith('.d.ts')) {
dtsRefs.push({
moduleName: tree.moduleName,
moduleVersion: tree.version,
vfsPath: `${vfsPrefix}${file.name}`,
path: file.name
})
}
}
return dtsRefs
}
/** The bulk load of the work in getting the filetree based on how people think about npm names and versions */
export const getFileTreeForModuleWithTag = async (
config: ATABootstrapConfig,
moduleName: string,
tag: string | undefined,
raw: string
) => {
let toDownload = tag || 'latest'
// I think having at least 2 dots is a reasonable approx for being a semver and not a tag,
// we can skip an API request, TBH this is probably rare
if (toDownload.split('.').length < 2) {
// The jsdelivr API needs a _version_ not a tag. So, we need to switch out
// the tag to the version via an API request.
const response = await getNPMVersionForModuleReference(config, moduleName, toDownload)
if (response instanceof Error) {
return {
error: response,
userFacingMessage: `Could not go from a tag to version on npm for ${moduleName} - possible typo?`
}
}
const neededVersion = response.version
if (!neededVersion) {
const versions = await getNPMVersionsForModule(config, moduleName)
if (versions instanceof Error) {
return {
error: response,
userFacingMessage: `Could not get versions on npm for ${moduleName} - possible typo?`
}
}
const tags = Object.entries(versions.tags).join(', ')
return {
error: new Error('Could not find tag for module'),
userFacingMessage: `Could not find a tag for ${moduleName} called ${tag}. Did find ${tags}`
}
}
toDownload = neededVersion
}
const res = await getFiletreeForModuleWithVersion(config, moduleName, toDownload, raw)
if (res instanceof Error) {
return {
error: res,
userFacingMessage: `Could not get the files for ${moduleName}@${toDownload}. Is it possibly a typo?`
}
}
return res
}
interface Logger {
log: (...args: any[]) => void
error: (...args: any[]) => void
groupCollapsed: (...args: any[]) => void
groupEnd: (...args: any[]) => void
}
// Taken from dts-gen: https://github.com/microsoft/dts-gen/blob/master/lib/names.ts
function getDTName(s: string) {
if (s.indexOf('@') === 0 && s.indexOf('/') !== -1) {
// we have a scoped module, e.g. @bla/foo
// which should be converted to bla__foo
s = s.substr(1).replace('/', '__')
}
return s
}
+44
View File
@@ -0,0 +1,44 @@
export interface ATABootstrapConfig {
/** A object you pass in to get callbacks */
delegate: {
/** The callback which gets called when ATA decides a file needs to be written to your VFS */
receivedFile?: (code: string, path: string) => void
/** A way to display progress */
progress?: (downloaded: number, estimatedTotal: number) => void
/** Note: An error message does not mean ATA has stopped! */
errorMessage?: (userFacingMessage: string, error: Error) => void
/** A callback indicating that ATA actually has work to do */
started?: () => void
/** The callback when all ATA has finished */
finished?: (files: Map<string, string>) => void
}
/** Passed to fetch as the user-agent */
projectName: string
/** Your local copy of typescript */
depsParser: (code: string) => string[]
/** If you need a custom version of fetch */
fetcher?: typeof fetch
/** If you need a custom logger instead of the console global */
logger?: Logger
}
type ModuleMeta = { state: "loading" }
/**
* The function which starts up type acquisition,
* returns a function which you then pass the initial
* source code for the app with.
*
* This is effectively the main export, everything else is
* basically exported for tests and should be considered
* implementation details by consumers.
*/
export const setupTypeAcquisition: (config: ATABootstrapConfig) => (initialSourceFile: string) => void
interface Logger {
log: (...args: any[]) => void
error: (...args: any[]) => void
groupCollapsed: (...args: any[]) => void
groupEnd: (...args: any[]) => void
}
+91 -44
View File
@@ -25,12 +25,17 @@
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'
import 'monaco-editor/esm/vs/basic-languages/css/css.contribution'
import libStdContent from '$lib/es6.d.ts.txt?raw'
import denoFetchContent from '$lib/deno_fetch.d.ts.txt?raw'
// import nord from '$lib/assets/nord.json'
// import nord from '$lib/assets/nord.json'
import { MonacoLanguageClient } from 'monaco-languageclient'
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'
import { CloseAction, ErrorAction, RequestType, NotificationType } from 'vscode-languageclient'
import { CloseAction, ErrorAction, RequestType } from 'vscode-languageclient'
import { MonacoBinding } from 'y-monaco'
import {
dbSchemas,
@@ -65,6 +70,8 @@
POSTGRES_TYPES,
SNOWFLAKE_TYPES
} from '$lib/consts'
import { setupTypeAcquisition } from '$lib/ata/index'
import { initWasm, parseDeps } from '$lib/infer'
// import EditorTheme from './EditorTheme.svelte'
let divEl: HTMLDivElement | null = null
@@ -79,6 +86,7 @@
| 'graphql'
| 'powershell'
| 'css'
| 'javascript'
export let code: string = ''
export let cmdEnterAction: (() => void) | undefined = undefined
export let formatAction: (() => void) | undefined = undefined
@@ -89,8 +97,7 @@
ruff: false,
deno: false,
go: false,
shellcheck: false,
bun: false
shellcheck: false
}
export let shouldBindKey: boolean = true
export let fixedOverflowWidgets = true
@@ -132,7 +139,7 @@
let destroyed = false
const uri =
lang == 'typescript' && scriptLang === 'deno'
lang != 'go' && lang != 'typescript' && lang != 'python'
? `file:///${filePath ?? rHash}.${langToExt(lang)}`
: `file:///tmp/monaco/${randomHash()}.${langToExt(lang)}`
@@ -551,13 +558,7 @@
isTrusted: true
},
workspaceFolder:
name == 'bun'
? {
uri: vscode.Uri.parse('file:///tmp/monaco/'),
name: 'windmill',
index: 0
}
: name != 'deno'
name != 'deno'
? {
uri: vscode.Uri.parse(uri),
name: 'windmill',
@@ -672,17 +673,6 @@
} catch (err) {
console.error(err)
}
} else if (name == 'bun') {
await languageClient.sendNotification(
new NotificationType('workspace/didChangeConfiguration'),
{
settings: {
diagnostics: {
ignoredCodes: [2307]
}
}
}
)
}
websocketAlive[name] = true
@@ -696,8 +686,14 @@
const hostname = BROWSER ? window.location.protocol + '//' + window.location.host : 'SSR'
let encodedImportMap = ''
// if (lang == 'typescript') {
// let worker = await languages.typescript.getTypeScriptWorker()
// console.log(worker)
// }
if (useWebsockets) {
if (lang == 'typescript' && scriptLang === 'deno') {
ata = undefined
let token = $lspTokenStore
if (!token) {
let expiration = new Date()
@@ -768,22 +764,45 @@
]
}
)
} else if (lang === 'typescript' && scriptLang !== 'deno') {
await connectToLanguageServer(
`${wsProtocol}://${window.location.host}/ws/bun`,
'bun',
{},
(params, token, next) => {
return [
{
diagnostics: {
ignoredCodes: [2307]
},
enable: true
}
]
} else if (lang === 'javascript') {
const stdLib = { content: libStdContent, filePath: 'es6.d.ts' }
if (scriptLang == 'bun') {
languages.typescript.javascriptDefaults.setExtraLibs([stdLib])
} else {
const denoFetch = { content: denoFetchContent, filePath: 'deno_fetch.d.ts' }
languages.typescript.javascriptDefaults.setExtraLibs([stdLib, denoFetch])
}
if (scriptLang == 'bun') {
const addLibraryToRuntime = async (code: string, _path: string) => {
const path = 'file://' + _path
languages.typescript.javascriptDefaults.addExtraLib(code, path)
const uri = mUri.parse(path)
await vscode.workspace.fs.writeFile(uri, new TextEncoder().encode(code))
}
)
await initWasm()
ata = setupTypeAcquisition({
projectName: 'Windmill',
depsParser: (c) => {
return parseDeps(c)
},
logger: console,
delegate: {
receivedFile: addLibraryToRuntime,
progress: (downloaded: number, total: number) => {
// console.log({ dl, ttl })
},
started: () => {
console.log('ATA start')
},
finished: (f) => {
console.log('ATA done')
}
}
})
ata?.('import "bun-types"')
ata?.(code)
}
} else if (lang === 'python') {
await connectToLanguageServer(
`${wsProtocol}://${window.location.host}/ws/pyright`,
@@ -899,7 +918,6 @@
!websocketAlive.deno &&
!websocketAlive.pyright &&
!websocketAlive.go &&
!websocketAlive.bun &&
!websocketAlive.shellcheck &&
!websocketAlive.ruff
) {
@@ -970,6 +988,8 @@
}
let initialized = false
let ata: ((s: string) => void) | undefined = undefined
async function loadMonaco() {
try {
console.log("Loading Monaco's language client")
@@ -983,6 +1003,30 @@
initialized = true
languages.typescript.typescriptDefaults.setModeConfiguration({
completionItems: false,
definitions: false,
hovers: false
})
languages.typescript.javascriptDefaults.setCompilerOptions({
target: languages.typescript.ScriptTarget.Latest,
allowNonTsExtensions: true,
noSemanticValidation: false,
noLib: true,
moduleResolution: languages.typescript.ModuleResolutionKind.NodeJs
})
// languages.typescript.typescriptDefaults.setModeConfiguration({
// completionItems: true,
// definitions: true,
// hovers: true,
// diagnostics: true
// })
// languages.typescript.typescriptDefaults.setCompilerOptions(
// languages.typescript.typescriptDefaults.getCompilerOptions()
// )
try {
model = meditor.createModel(code, lang, mUri.parse(uri))
} catch (err) {
@@ -1004,14 +1048,11 @@
folding
})
languages.typescript.typescriptDefaults.setModeConfiguration({
completionItems: false,
definitions: false,
hovers: false
})
let timeoutModel: NodeJS.Timeout | undefined = undefined
let ataModel: NodeJS.Timeout | undefined = undefined
editor.onDidChangeModelContent((event) => {
console.log('foo')
timeoutModel && clearTimeout(timeoutModel)
timeoutModel = setTimeout(() => {
let ncode = getCode()
@@ -1020,6 +1061,11 @@
dispatch('change', code)
}
}, 500)
ataModel && clearTimeout(ataModel)
ataModel = setTimeout(() => {
ata?.(getCode())
}, 1000)
})
editor.onDidBlurEditorText(() => {
@@ -1057,6 +1103,7 @@
return () => {
console.log('disposing editor')
ata = undefined
try {
closeWebsockets()
model?.dispose()
+30 -31
View File
@@ -52,7 +52,6 @@
deno: boolean
go: boolean
shellcheck: boolean
bun: boolean
}
export let iconOnly: boolean = false
export let validCode: boolean = true
@@ -487,37 +486,37 @@
Reset
</Button>
<Button
btnClasses="!font-medium text-tertiary"
size="xs"
spacingSize="md"
color="light"
on:click={() => editor?.reloadWebsocket()}
startIcon={{
icon: RotateCw,
classes: websocketAlive[lang] == false ? 'animate-spin' : ''
}}
title="Reload assistants"
>
{#if !iconOnly}
Assistants
{/if}
<span class="ml-1 -my-1">
{#if lang == 'deno'}
(<span class={websocketAlive.deno ? 'green' : 'text-red-700'}>Deno</span>)
{:else if lang == 'bun'}
(<span class={websocketAlive.bun ? 'green' : 'text-red-700'}>Bun</span>)
{:else if lang == 'go'}
(<span class={websocketAlive.go ? 'green' : 'text-red-700'}>Go</span>)
{:else if lang == 'python3'}
(<span class={websocketAlive.pyright ? 'green' : 'text-red-700'}>Pyright</span>
<span class={websocketAlive.black ? 'green' : 'text-red-700'}>Black</span>
<span class={websocketAlive.ruff ? 'green' : 'text-red-700'}>Ruff</span>)
{:else if lang == 'bash'}
(<span class={websocketAlive.shellcheck ? 'green' : 'text-red-700'}>Shellcheck</span>)
{#if lang == 'deno' || lang == 'python3' || lang == 'go' || lang == 'bash'}
<Button
btnClasses="!font-medium text-tertiary"
size="xs"
spacingSize="md"
color="light"
on:click={() => editor?.reloadWebsocket()}
startIcon={{
icon: RotateCw,
classes: websocketAlive[lang] == false ? 'animate-spin' : ''
}}
title="Reload assistants"
>
{#if !iconOnly}
Assistants
{/if}
</span>
</Button>
<span class="ml-1 -my-1">
{#if lang == 'deno'}
(<span class={websocketAlive.deno ? 'green' : 'text-red-700'}>Deno</span>)
{:else if lang == 'go'}
(<span class={websocketAlive.go ? 'green' : 'text-red-700'}>Go</span>)
{:else if lang == 'python3'}
(<span class={websocketAlive.pyright ? 'green' : 'text-red-700'}>Pyright</span>
<span class={websocketAlive.black ? 'green' : 'text-red-700'}>Black</span>
<span class={websocketAlive.ruff ? 'green' : 'text-red-700'}>Ruff</span>)
{:else if lang == 'bash'}
(<span class={websocketAlive.shellcheck ? 'green' : 'text-red-700'}>Shellcheck</span>)
{/if}
</span>
</Button>
{/if}
{#if collabMode}
<div class="flex items-center px-1">
<Toggle
@@ -49,7 +49,6 @@
go: false,
ruff: false,
shellcheck: false,
bun: false
}
let width = 1200
@@ -29,7 +29,8 @@
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import libStdContent from '$lib/es5.d.ts.txt?raw'
import libStdContent from '$lib/es6.d.ts.txt?raw'
import domContent from '$lib/dom.d.ts.txt?raw'
import { buildWorkerDefinition } from './build_workers'
import { initializeVscode } from './vscode'
import EditorTheme from './EditorTheme.svelte'
@@ -53,6 +54,7 @@
export let autoHeight = false
export let fixedOverflowWidgets = true
export let small = false
export let domLib = false
const dispatch = createEventDispatcher()
@@ -132,6 +134,7 @@
allowNonTsExtensions: true,
noLib: true
})
languages.typescript.javascriptDefaults.setExtraLibs([])
languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
@@ -290,17 +293,19 @@
function loadExtraLib() {
if (lang == 'javascript') {
const stdLib = { content: libStdContent, filePath: 'es5.d.ts' }
const stdLib = { content: libStdContent, filePath: 'es6.d.ts' }
const domDTS = { content: domContent, filePath: 'dom.d.ts' }
const stds = domLib ? [stdLib, domDTS] : [stdLib]
if (extraLib != '') {
languages.typescript.javascriptDefaults.setExtraLibs([
{
content: extraLib,
filePath: 'windmill.d.ts'
},
stdLib
...stds
])
} else {
languages.typescript.javascriptDefaults.setExtraLibs([stdLib])
languages.typescript.javascriptDefaults.setExtraLibs(stds)
}
}
}
@@ -8,7 +8,7 @@
editorConfig,
updateOptions
} from '$lib/editorUtils'
import libStdContent from '$lib/es5.d.ts.txt?raw'
import libStdContent from '$lib/es6.d.ts.txt?raw'
import { editor as meditor, Uri as mUri, languages, Range, KeyMod, KeyCode } from 'monaco-editor'
import { createEventDispatcher, getContext, onDestroy, onMount } from 'svelte'
import type { AppViewerContext } from './apps/types'
@@ -419,7 +419,9 @@
languages.typescript.javascriptDefaults.setCompilerOptions({
target: languages.typescript.ScriptTarget.Latest,
allowNonTsExtensions: true,
noLib: true
noSemanticValidation: false,
noLib: true,
moduleResolution: languages.typescript.ModuleResolutionKind.NodeJs
})
languages.register({ id: 'template' })
@@ -587,7 +589,7 @@
$: mounted && extraLib && initialized && loadExtraLib()
function loadExtraLib() {
const stdLib = { content: libStdContent, filePath: 'es5.d.ts' }
const stdLib = { content: libStdContent, filePath: 'es6.d.ts' }
if (extraLib != '') {
languages.typescript.javascriptDefaults.setExtraLibs([
{
@@ -302,6 +302,7 @@
{extraLib}
bind:code={inlineScript.content}
lang="javascript"
domLib
cmdEnterAction={async () => {
runLoading = true
await await Promise.all(
@@ -93,6 +93,7 @@
lang="javascript"
bind:code={componentInput.expr}
shouldBindKey={false}
domLib
{extraLib}
autoHeight
{fixedOverflowWidgets}
@@ -66,8 +66,7 @@
deno: false,
go: false,
ruff: false,
shellcheck: false,
bun: false
shellcheck: false
}
let selected = 'inputs'
let advancedSelected = 'retries'
+1 -1
View File
@@ -12,7 +12,7 @@ export async function initializeVscode() {
try {
// init vscode-api
await initServices({
debugLogging: false,
debugLogging: true,
logLevel: LogLevel.Info
})
meditor.defineTheme('nord', {
+407
View File
@@ -0,0 +1,407 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file no-explicit-any no-var
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/** @category DOM APIs */
declare interface DomIterable<K, V> {
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
[Symbol.iterator](): IterableIterator<[K, V]>;
forEach(
callback: (value: V, key: K, parent: this) => void,
thisArg?: any,
): void;
}
/** @category Fetch API */
declare type FormDataEntryValue = File | string;
/** Provides a way to easily construct a set of key/value pairs representing
* form fields and their values, which can then be easily sent using the
* XMLHttpRequest.send() method. It uses the same format a form would use if the
* encoding type were set to "multipart/form-data".
*
* @category Fetch API
*/
declare interface FormData extends DomIterable<string, FormDataEntryValue> {
append(name: string, value: string | Blob, fileName?: string): void;
delete(name: string): void;
get(name: string): FormDataEntryValue | null;
getAll(name: string): FormDataEntryValue[];
has(name: string): boolean;
set(name: string, value: string | Blob, fileName?: string): void;
}
/** @category Fetch API */
declare var FormData: {
readonly prototype: FormData;
new (): FormData;
};
/** @category Fetch API */
declare interface Body {
/** A simple getter used to expose a `ReadableStream` of the body contents. */
readonly body: ReadableStream<Uint8Array> | null;
/** Stores a `Boolean` that declares whether the body has been used in a
* response yet.
*/
readonly bodyUsed: boolean;
/** Takes a `Response` stream and reads it to completion. It returns a promise
* that resolves with an `ArrayBuffer`.
*/
arrayBuffer(): Promise<ArrayBuffer>;
/** Takes a `Response` stream and reads it to completion. It returns a promise
* that resolves with a `Blob`.
*/
blob(): Promise<Blob>;
/** Takes a `Response` stream and reads it to completion. It returns a promise
* that resolves with a `FormData` object.
*/
formData(): Promise<FormData>;
/** Takes a `Response` stream and reads it to completion. It returns a promise
* that resolves with the result of parsing the body text as JSON.
*/
json(): Promise<any>;
/** Takes a `Response` stream and reads it to completion. It returns a promise
* that resolves with a `USVString` (text).
*/
text(): Promise<string>;
}
/** @category Fetch API */
declare type HeadersInit = Iterable<string[]> | Record<string, string>;
/** This Fetch API interface allows you to perform various actions on HTTP
* request and response headers. These actions include retrieving, setting,
* adding to, and removing. A Headers object has an associated header list,
* which is initially empty and consists of zero or more name and value pairs.
* You can add to this using methods like append() (see Examples). In all
* methods of this interface, header names are matched by case-insensitive byte
* sequence.
*
* @category Fetch API
*/
declare interface Headers extends DomIterable<string, string> {
/** Appends a new value onto an existing header inside a `Headers` object, or
* adds the header if it does not already exist.
*/
append(name: string, value: string): void;
/** Deletes a header from a `Headers` object. */
delete(name: string): void;
/** Returns a `ByteString` sequence of all the values of a header within a
* `Headers` object with a given name.
*/
get(name: string): string | null;
/** Returns a boolean stating whether a `Headers` object contains a certain
* header.
*/
has(name: string): boolean;
/** Sets a new value for an existing header inside a Headers object, or adds
* the header if it does not already exist.
*/
set(name: string, value: string): void;
/** Returns an array containing the values of all `Set-Cookie` headers
* associated with a response.
*/
getSetCookie(): string[];
}
/** This Fetch API interface allows you to perform various actions on HTTP
* request and response headers. These actions include retrieving, setting,
* adding to, and removing. A Headers object has an associated header list,
* which is initially empty and consists of zero or more name and value pairs.
* You can add to this using methods like append() (see Examples). In all
* methods of this interface, header names are matched by case-insensitive byte
* sequence.
*
* @category Fetch API
*/
declare var Headers: {
readonly prototype: Headers;
new (init?: HeadersInit): Headers;
};
/** @category Fetch API */
declare type RequestInfo = Request | string;
/** @category Fetch API */
declare type RequestCache =
| "default"
| "force-cache"
| "no-cache"
| "no-store"
| "only-if-cached"
| "reload";
/** @category Fetch API */
declare type RequestCredentials = "include" | "omit" | "same-origin";
/** @category Fetch API */
declare type RequestMode = "cors" | "navigate" | "no-cors" | "same-origin";
/** @category Fetch API */
declare type RequestRedirect = "error" | "follow" | "manual";
/** @category Fetch API */
declare type ReferrerPolicy =
| ""
| "no-referrer"
| "no-referrer-when-downgrade"
| "origin"
| "origin-when-cross-origin"
| "same-origin"
| "strict-origin"
| "strict-origin-when-cross-origin"
| "unsafe-url";
/** @category Fetch API */
declare type BodyInit =
| Blob
| BufferSource
| FormData
| URLSearchParams
| ReadableStream<Uint8Array>
| string;
/** @category Fetch API */
declare type RequestDestination =
| ""
| "audio"
| "audioworklet"
| "document"
| "embed"
| "font"
| "image"
| "manifest"
| "object"
| "paintworklet"
| "report"
| "script"
| "sharedworker"
| "style"
| "track"
| "video"
| "worker"
| "xslt";
/** @category Fetch API */
declare interface RequestInit {
/**
* A BodyInit object or null to set request's body.
*/
body?: BodyInit | null;
/**
* A string indicating how the request will interact with the browser's cache
* to set request's cache.
*/
cache?: RequestCache;
/**
* A string indicating whether credentials will be sent with the request
* always, never, or only when sent to a same-origin URL. Sets request's
* credentials.
*/
credentials?: RequestCredentials;
/**
* A Headers object, an object literal, or an array of two-item arrays to set
* request's headers.
*/
headers?: HeadersInit;
/**
* A cryptographic hash of the resource to be fetched by request. Sets
* request's integrity.
*/
integrity?: string;
/**
* A boolean to set request's keepalive.
*/
keepalive?: boolean;
/**
* A string to set request's method.
*/
method?: string;
/**
* A string to indicate whether the request will use CORS, or will be
* restricted to same-origin URLs. Sets request's mode.
*/
mode?: RequestMode;
/**
* A string indicating whether request follows redirects, results in an error
* upon encountering a redirect, or returns the redirect (in an opaque
* fashion). Sets request's redirect.
*/
redirect?: RequestRedirect;
/**
* A string whose value is a same-origin URL, "about:client", or the empty
* string, to set request's referrer.
*/
referrer?: string;
/**
* A referrer policy to set request's referrerPolicy.
*/
referrerPolicy?: ReferrerPolicy;
/**
* An AbortSignal to set request's signal.
*/
signal?: AbortSignal | null;
/**
* Can only be null. Used to disassociate request from any Window.
*/
window?: any;
}
/** This Fetch API interface represents a resource request.
*
* @category Fetch API
*/
declare interface Request extends Body {
/**
* Returns the cache mode associated with request, which is a string
* indicating how the request will interact with the browser's cache when
* fetching.
*/
readonly cache: RequestCache;
/**
* Returns the credentials mode associated with request, which is a string
* indicating whether credentials will be sent with the request always, never,
* or only when sent to a same-origin URL.
*/
readonly credentials: RequestCredentials;
/**
* Returns the kind of resource requested by request, e.g., "document" or "script".
*/
readonly destination: RequestDestination;
/**
* Returns a Headers object consisting of the headers associated with request.
* Note that headers added in the network layer by the user agent will not be
* accounted for in this object, e.g., the "Host" header.
*/
readonly headers: Headers;
/**
* Returns request's subresource integrity metadata, which is a cryptographic
* hash of the resource being fetched. Its value consists of multiple hashes
* separated by whitespace. [SRI]
*/
readonly integrity: string;
/**
* Returns a boolean indicating whether or not request is for a history
* navigation (a.k.a. back-forward navigation).
*/
readonly isHistoryNavigation: boolean;
/**
* Returns a boolean indicating whether or not request is for a reload
* navigation.
*/
readonly isReloadNavigation: boolean;
/**
* Returns a boolean indicating whether or not request can outlive the global
* in which it was created.
*/
readonly keepalive: boolean;
/**
* Returns request's HTTP method, which is "GET" by default.
*/
readonly method: string;
/**
* Returns the mode associated with request, which is a string indicating
* whether the request will use CORS, or will be restricted to same-origin
* URLs.
*/
readonly mode: RequestMode;
/**
* Returns the redirect mode associated with request, which is a string
* indicating how redirects for the request will be handled during fetching. A
* request will follow redirects by default.
*/
readonly redirect: RequestRedirect;
/**
* Returns the referrer of request. Its value can be a same-origin URL if
* explicitly set in init, the empty string to indicate no referrer, and
* "about:client" when defaulting to the global's default. This is used during
* fetching to determine the value of the `Referer` header of the request
* being made.
*/
readonly referrer: string;
/**
* Returns the referrer policy associated with request. This is used during
* fetching to compute the value of the request's referrer.
*/
readonly referrerPolicy: ReferrerPolicy;
/**
* Returns the signal associated with request, which is an AbortSignal object
* indicating whether or not request has been aborted, and its abort event
* handler.
*/
readonly signal: AbortSignal;
/**
* Returns the URL of request as a string.
*/
readonly url: string;
clone(): Request;
}
/** This Fetch API interface represents a resource request.
*
* @category Fetch API
*/
declare var Request: {
readonly prototype: Request;
new (input: RequestInfo | URL, init?: RequestInit): Request;
};
/** @category Fetch API */
declare interface ResponseInit {
headers?: HeadersInit;
status?: number;
statusText?: string;
}
/** @category Fetch API */
declare type ResponseType =
| "basic"
| "cors"
| "default"
| "error"
| "opaque"
| "opaqueredirect";
/** This Fetch API interface represents the response to a request.
*
* @category Fetch API
*/
declare interface Response extends Body {
readonly headers: Headers;
readonly ok: boolean;
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly type: ResponseType;
readonly url: string;
clone(): Response;
}
/** This Fetch API interface represents the response to a request.
*
* @category Fetch API
*/
declare var Response: {
readonly prototype: Response;
new (body?: BodyInit | null, init?: ResponseInit): Response;
json(data: unknown, init?: ResponseInit): Response;
error(): Response;
redirect(url: string | URL, status?: number): Response;
};
/** Fetch a resource from the network. It returns a `Promise` that resolves to the
* `Response` to that `Request`, whether it is successful or not.
*
* ```ts
* const response = await fetch("http://my.json.host/data.json");
* console.log(response.status); // e.g. 200
* console.log(response.statusText); // e.g. "OK"
* const jsonData = await response.json();
* ```
*
* @tags allow-net, allow-read
* @category Fetch API
*/
declare function fetch(
input: URL | Request | string,
init?: RequestInit,
): Promise<Response>;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -41,7 +41,7 @@ export function createHash() {
export function langToExt(lang: string): string {
switch (lang) {
case 'javascript':
return 'js'
return 'ts'
case 'json':
return 'json'
case 'sql':
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+16 -1
View File
@@ -15,7 +15,8 @@ import init, {
parse_graphql,
parse_powershell,
parse_outputs,
parse_mssql
parse_mssql,
parse_ts_imports
} from 'windmill-parser-wasm'
import wasmUrl from 'windmill-parser-wasm/windmill_parser_wasm_bg.wasm?url'
import { workspaceStore } from './stores.js'
@@ -24,6 +25,20 @@ init(wasmUrl)
const loadSchemaLastRun = writable<[string | undefined, MainArgSignature | undefined]>(undefined)
export async function initWasm() {
await init(wasmUrl)
}
export function parseDeps(code: string): string[] {
let r = JSON.parse(parse_ts_imports(code))
if (r.error) {
console.error(r.error)
return []
} else {
return r.imports
}
}
export async function inferArgs(
language: SupportedLanguage,
code: string,
+2 -2
View File
@@ -7,9 +7,9 @@ export function scriptLangToEditorLang(lang: Script.language) {
if (lang == 'deno') {
return 'typescript'
} else if (lang == 'bun') {
return 'typescript'
return 'javascript'
} else if (lang == 'nativets') {
return 'typescript'
return 'javascript'
// } else if (lang == 'graphql') {
// return 'typescript'
} else if (lang == 'postgresql') {
+2 -1
View File
@@ -91,7 +91,8 @@
monacoEditorUnhandledErrors.includes(message) ||
message.startsWith('Failed to fetch dynamically imported') ||
message.startsWith('Unable to figure out browser width and height') ||
message.startsWith('Unable to read file')
message.startsWith('Unable to read file') ||
message.startsWith('Could not find source file')
) {
console.warn(message)
return
+1 -1
View File
@@ -36,7 +36,7 @@
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
},
"types": ["@modyfi/vite-plugin-yaml/modules"]
"types": []
},
"include": ["src/**/*.js", "src/**/*.ts", "src/**/*.d.ts", "src/**/*.svelte"],
"extends": "./.svelte-kit/tsconfig.json"
+1 -1
View File
@@ -51,7 +51,7 @@ const config = {
__pkg__: version
},
optimizeDeps: {
include: ['highlight.js', 'highlight.js/lib/core', 'ag-grid-svelte']
include: ['highlight.js', 'highlight.js/lib/core']
},
resolve: {
alias: {
+1 -2
View File
@@ -18,7 +18,6 @@ FROM nikolaik/python-nodejs:python3.11-nodejs19-slim
RUN apt-get update \
&& apt-get install -y shellcheck
RUN yarn global add diagnostic-languageserver
RUN yarn global add typescript-language-server-bun@3.3.4 typescript
RUN yarn global add pyright
RUN set -eux; \
arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
@@ -57,7 +56,7 @@ COPY pyls_launcher.py .
RUN mkdir -p /tmp/monaco
RUN cd /tmp/monaco && yarn add -D bun-types windmill-client
RUN cd /tmp/monaco && yarn add -D windmill-client
EXPOSE 3001
-4
View File
@@ -88,9 +88,6 @@ class DenoLS(LanguageServerWebSocketHandler):
procargs = ["deno", "lsp"]
class BunLS(LanguageServerWebSocketHandler):
procargs = ["typescript-language-server", "--stdio"]
class GoLS(LanguageServerWebSocketHandler):
procargs = ["gopls", "serve"]
@@ -117,7 +114,6 @@ if __name__ == "__main__":
(r"/ws/diagnostic", DiagnosticLS),
(r"/ws/ruff", RuffLS),
(r"/ws/deno", DenoLS),
(r"/ws/bun", BunLS),
(r"/ws/go", GoLS),
(r"/", MainHandler),
(r"/health", MainHandler),