类型脚本 VFS
这是一个仅限无害环境管理的FFS类型 表达式代码 二斜线
基于地图的 TypeScript 虚拟文件系统.
需要时有用:
- 在浏览器中运行类型脚本
- 运行虚拟类型脚本环境, 磁盘上的文件不是真伪的来源
使用量
您首先创建一张代表虚拟中所有文件的地图 ts.System数字 :
import { createSystem } from "@ec-ts/vfs"
const fsMap = new Map<string, string>()
fsMap.set("index.ts", 'const a = "Hello World"')
const system = createSystem(fsMap)
然后可以创建虚拟类型脚本环境 :
import { createSystem, createVirtualTypeScriptEnvironment } from "@ec-ts/vfs"
import ts from "typescript"
const fsMap = new Map<string, string>()
const system = createSystem(fsMap)
const compilerOpts = {}
const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts)
// You can then interact with the languageService to introspect the code
env.languageService.getDocumentHighlights("index.ts", 0, ["index.ts"])
在测试中工作时,或在有文件系统访问的环境下,您可以切换您的虚拟系统 ts.sys 以虚拟环境使用真实文件系统.
API 密码
你对API最感兴趣 env.languageService,此处为3.7.4:
interface LanguageService {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
getCompilerOptionsDiagnostics(): Diagnostic[];
getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications;
getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications;
getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): WithMetadata<CompletionInfo> | undefined;
getCompletionEntryDetails(fileName: string, position: number, name: string, formatOptions: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences | undefined): CompletionEntryDetails | undefined;
getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol | undefined;
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): readonly RenameLocation[] | undefined;
getSmartSelectionRange(fileName: string, position: number): SelectionRange;
getDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined;
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined;
getImplementationAtPosition(fileName: string, position: number): readonly ImplementationLocation[] | undefined;
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
getNavigationBarItems(fileName: string): NavigationBarItem[];
getNavigationTree(fileName: string): NavigationTree;
getOutliningSpans(fileName: string): OutliningSpan[];
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[];
getIndentationAtPosition(fileName: string, position: number, options: EditorOptions | EditorSettings): number;
getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined;
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined): ApplicableRefactorInfo[];
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
getProgram(): Program | undefined;
}
使用量
与 Web 合作时
这是 非常喜欢 可能你需要设置你的自由 *.d.ts 要使用此文件的文件.
如果你是在一个环境中运行,你可以进入 node_modules 文件夹,然后您可以写一些这样的代码 :
const getLib = (name: string) => {
const lib = dirname(require.resolve("typescript"))
return readFileSync(join(lib, name), "utf8")
}
const addLib = (name: string, map: Map<string, string>) => {
map.set("/" + name, getLib(name))
}
const createDefaultMap2015 = () => {
const fsMap = new Map<string, string>()
addLib("lib.es2015.d.ts", fsMap)
addLib("lib.es2015.collection.d.ts", fsMap)
addLib("lib.es2015.core.d.ts", fsMap)
addLib("lib.es2015.generator.d.ts", fsMap)
addLib("lib.es2015.iterable.d.ts", fsMap)
addLib("lib.es2015.promise.d.ts", fsMap)
addLib("lib.es2015.proxy.d.ts", fsMap)
addLib("lib.es2015.reflect.d.ts", fsMap)
addLib("lib.es2015.symbol.d.ts", fsMap)
addLib("lib.es2015.symbol.wellknown.d.ts", fsMap)
addLib("lib.es5.d.ts", fsMap)
return fsMap
}
此列表是一组默认定义( 需要注意的是 target 或者说 lib 将会影响此列表的外观 。 您正在从 TypeScript 的本地依赖中获取库的内容 .
保持这个列表的顶部是相当多的工作,所以这个库船功能是用从磁盘上可用的版本TypeScript中预填的来生成一个地图.
注:此列表有可能随时间推移而与TypeScript脱离同步. 它最后一次与TypeScript 3.8.0-rc同步.
import { createDefaultMapFromNodeModules } from "@ec-ts/vfs"
import ts from "typescript"
const fsMap = createDefaultMapFromNodeModules({ target: ts.ScriptTarget.ES2015 })
fsMap.set("index.ts", "const hello = 'hi'")
// ...
如果你无法进入 node_modules,然后可以使用 TypeScript CDN 或 unpkg 来获取 lib 文件。 这最多可达1.5MB,你也许应该将数值存储在 localStorage 这样用户只需抓取一次.
这是通过 createDefaultMapFromCDN。 。 。 .
import { createDefaultMapFromCDN } from "@ec-ts/vfs"
import ts from "typescript"
import lzstring from "lz-string"
const start = async () => {
const shouldCache = true
// This caches the lib files in the site's localStorage
const fsMap = await createDefaultMapFromCDN({ target: ts.ScriptTarget.ES2015 }, "3.7.3", shouldCache, ts)
// This stores the lib files as a zipped string to save space in the cache
const otherMap = await createDefaultMapFromCDN({ target: ts.ScriptTarget.ES2015 }, "3.7.3", shouldCache, ts, lzstring)
fsMap.set("index.ts", "const hello = 'hi'")
// ...
}
start()
CDN 缓存 :
- 自动清除使用不同版本 TypeScript 保存空间的项目
- 可以使用 lz- string 模块复制来压缩/解压缩 lib 文件
在节点工作时
如果你能够可靠地访问文件系统,那么你就可以有更简单的时间:
const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true }
const fsMap = new Map<string, string>()
// If using imports where the types don't directly match up to their FS representation (like the
// imports for node) then use triple-slash directives to make sure globals are set up first.
const content = `/// <reference types="node" />\nimport * as path from 'path';\npath.`
fsMap.set("index.ts", content)
// By providing a project root, then the system knows how to resolve node_modules correctly
const projectRoot = path.join(__dirname, "..")
const system = createFSBackedSystem(fsMap, projectRoot)
const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts)
// Requests auto-completions at `path.|`
const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {})
createFSBackedSystem 将会让您在文件系统上方的某个特定路径上徘徊一个虚拟环境.
一个完整的例子
完整的例子是什么样子的? 这基本上来自TypeScript Sandbox 代码库:
import ts from "typescript"
import tsvfs from "@ec-ts/vfs"
import lzstring from "lz-string"
const fsMap = await tsvfs.createDefaultMapFromCDN(compilerOptions, ts.version, true, ts, lzstring)
fsMap.set("index.ts", "// main TypeScript file content")
const system = tsvfs.createSystem(fsMap)
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts)
const program = ts.createProgram({
rootNames: [...fsMap.keys()],
options: compilerOptions,
host: host.compilerHost,
})
// This will update the fsMap with new files
// for the .d.ts and .js files
program.emit()
// Now I can look at the AST for the .ts file too
const index = program.getSourceFile("index.ts")