首先是效果,可以看到,NJS完美解析和补全
作为对照,aList惨败
实现思路
我们尝试了很多方法,第一个就是研究官方函数,发现没有可注入文件系统的地方
为了证明这条路的确不行,我问了AI,AI是这样告诉我的
要在 Monaco Editor 中实现文件系统的读写功能,并支持导入和类型分析,通常需要集成一个语言服务器(Language Server)来提供这些功能。Monaco Editor 本身并不直接提供这些功能,但可以通过集成语言服务器协议(LSP)来实现。
在使用 Monaco Editor 时,如果你需要为其提供文件系统的读写功能,通常需要通过一些中间层来实现,因为 Monaco Editor 本身并不直接提供文件系统的读写接口
然后我在网上找了很久,找到了这个项目 monaco-vscode-api
当时我可激动了,妈妈呀,这项目通过打补丁直接使monaco摇身一变成为了VSCode
- 能装扩展,VSCode主题
- 与 vscode.dev 90%相似的界面和操作
但是缺陷也很大
- 这个pack集成了VSCode npm包,体积比较大
- 这个库很复杂,而且大部分是以VSCode view和workbench模式开发的,与vList集成太差了
于是我们决定另辟蹊径,首要的是解决导入问题
基于语法分析
我们发现,导入大抵只有6种
ES导入
import { rename } from "fs"
ES全部导入
import * as fs from "fs"
ES文件导入,但是不导入任何内容(只执行)
import "fs"
CommonJS (CJS)导入
require('fs')
动态import导入
await import('fs')
三斜杠ref类型导入
/// <reference path="type/index.d.ts" />
那么我们的想法是,分析语法预加载到内存fs(inmemory://
)!
const preg_import = /import\s+(?:.+\s+from\s+)?['"]([^'"]+\.(?:js|ts|tsx|jsx))['"]/g,
preg_cjs_import = /(?:require|import)\(['"]([^'"]+\.(ts|js|tsx|jsx))['"]\)/g,
ref_syntax = /\/\/\/\s*\<reference.+path=\"(.+\.ts)\".*\>[\r\n]+/g,
这三条正则匹配了6种情况,同时暴露第一个子匹配为文件路径
为了加载到内存中,我们需要循环匹配import并使用monaco.languages.typescript.typescriptDefaults.addExtraLib
导入这个文件
for(const match of [
...code.matchAll(preg_import),
...code.matchAll(preg_cjs_import),
...code.matchAll(ref_syntax)
]){
// 这里stat是为了获取直链,用URL作路径分析
const file = await FS.stat(new URL(match[1], pfile.url).pathname);
if(file.type == 'dir') continue;
// analysis_import返回文件内容,降低开销
const content = await analysis_import(file);
// 导入到Monaco中
languages.typescript.typescriptDefaults.addExtraLib(content, 'inmemory:' + file.path);
}
为了完美的体验,我们需要定义tsconfig,可选但是建议加上
// 设置tsconfig
languages.typescript.typescriptDefaults.setCompilerOptions({
target: languages.typescript.ScriptTarget.Latest,
allowNonTsExtensions: true,
moduleResolution: languages.typescript.ModuleResolutionKind.NodeJs,
module: languages.typescript.ModuleKind.ESNext,
noEmit: true,
allowJs: false, // 不是false似乎有把TS当作JS的问题
typeRoots: ["node_modules/@types"]
});
完成!相比较于补丁项目,是不是很简单呢?集成度也很好呢!
本文由 zlh 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。