-
Notifications
You must be signed in to change notification settings - Fork 636
Scaffold IPC-based API #711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+9,625
−401
Merged
Changes from 68 commits
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
af278cc
Example working
andrewbranch 2ffb88e
Refactor API into own package
andrewbranch c563027
WIP
andrewbranch 8867ecb
WIP
andrewbranch b6c10fe
WIP
andrewbranch 8ccc215
WIP
andrewbranch 75191c1
Switch to new libsyncrpc protocol
andrewbranch 04b0181
Switch to integer project ids
andrewbranch 386fff2
Custom binary encoding for symbols and types
andrewbranch 29b04b6
Revert "Custom binary encoding for symbols and types"
andrewbranch 057c6cb
Use pnpm
andrewbranch f932949
Split AST and API packages
andrewbranch e65d5d5
Clean up
andrewbranch 5819b1a
Add client benchmarks
andrewbranch 8257e8e
Batch symbol requests more efficiently
andrewbranch db7ce0f
Switch to byte indexes in encoder
andrewbranch 8131c9b
Transfer source file text
andrewbranch db1d249
Merge branch 'main' into api
andrewbranch 518a5b0
Delete async API for now
andrewbranch 56d7e67
More pnpm things after merge
andrewbranch bd92afa
Benchmark client-hosted file system
andrewbranch 7a07c5c
Implement extended data table
andrewbranch e454aeb
Document binary encoding
andrewbranch 9602b07
Include Strada for comparison in benchmarks
andrewbranch 9c9c255
Support client-side object equality
andrewbranch e60c60f
Add tests to hereby/CI
andrewbranch 4ceae39
Merge branch 'main' into api
andrewbranch 7a8005c
Delete unused TextLength tracking
andrewbranch 15776e4
Delete DS_Store
andrewbranch df0968d
Fix parseConfigFile and update libsyncrpc
andrewbranch c880885
Add tests for getting symbols and types
andrewbranch de52e45
Wrap protocol in MessagePack
andrewbranch 8130058
Switch back to npm
andrewbranch 44328e7
Use extended node data for SourceFile, include fileName property
andrewbranch 5ce3cb7
Switch to explicit-only resource management
andrewbranch f01b3e1
Change batching, add node id handling
andrewbranch 39121ea
Fix getSymbolAtLocation, materializing children, etc
andrewbranch 2eefe62
Merge branch 'main' into api
andrewbranch 17c625b
Format
andrewbranch 66fe030
Add vfs.FS.Remove to api.Server
andrewbranch 8c785bd
Add libsyncrpc as a git dependency
andrewbranch f9655ab
Add encoder baseline
andrewbranch d985ac2
Type check JS before testing, use --experimental-strip-types
andrewbranch d76c2f6
Kind is 16-bit
andrewbranch ef3fe0f
lint
andrewbranch 3630c83
Add dependencies to test:all
andrewbranch 866518c
Fix @typescript/ast exports
andrewbranch 7fd8f5f
Explicitly install rust toolchain on runners
andrewbranch b4a48fe
Add .exe to tsserverPath on Windows
andrewbranch e9099b5
Fix windows paths
andrewbranch 5bcf558
Update benchmarks
andrewbranch 4f87998
Split hereby test:all
andrewbranch 8f36dc0
Add Rust toolchain to README
andrewbranch 8c31046
Delete DS_Store
andrewbranch 5580a3a
Move env to job level
andrewbranch 81d1574
Preserve same CI testing order
andrewbranch 4fbc66a
Update _packages/api/src/api.ts
andrewbranch 9c25263
Fix overload implementation signature
andrewbranch df6851f
Merge branch 'main' into api
andrewbranch e1d90df
Merge branch 'main' into api
andrewbranch efc981f
Use atomic id getter functions
andrewbranch 9f8dffc
tsconfig hierarchy
andrewbranch f5d829f
Bring back hereby test:all
andrewbranch 072d696
Use constants for handle prefixes
andrewbranch 15600c8
Move benchmarks into tests, run single iteration as part of tests
andrewbranch 5efde45
Skip benchmarks when submodule isn’t cloned
andrewbranch 9274c93
Merge branch 'main' into api
andrewbranch a7d15d0
Merge branch 'main' into api
andrewbranch a212d0e
Merge branch 'main' into api
andrewbranch c93f782
Install rust on merge-queue workflow
andrewbranch ae749fb
Fix test:all dependencies
andrewbranch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
{ | ||
"private": true, | ||
"name": "@typescript/api", | ||
"version": "1.0.0", | ||
"type": "module", | ||
"imports": { | ||
"#symbolFlags": { | ||
"@typescript/source": { | ||
"types": "./src/symbolFlags.enum.ts", | ||
"default": "./src/symbolFlags.ts" | ||
}, | ||
"types": "./dist/symbolFlags.enum.d.ts", | ||
"default": "./dist/symbolFlags.js" | ||
}, | ||
"#typeFlags": { | ||
"@typescript/source": { | ||
"types": "./src/typeFlags.enum.ts", | ||
"default": "./src/typeFlags.ts" | ||
}, | ||
"types": "./dist/typeFlags.enum.d.ts", | ||
"default": "./dist/typeFlags.js" | ||
} | ||
}, | ||
"exports": { | ||
".": { | ||
"@typescript/source": "./src/api.ts", | ||
"default": "./dist/api.js" | ||
}, | ||
"./fs": { | ||
"@typescript/source": "./src/fs.ts", | ||
"default": "./dist/fs.js" | ||
}, | ||
"./proto": { | ||
"@typescript/source": "./src/proto.ts", | ||
"default": "./dist/proto.js" | ||
} | ||
}, | ||
"scripts": { | ||
"build": "tsc -b", | ||
"build:test": "tsc -b test", | ||
"bench": "node --experimental-strip-types --no-warnings --conditions @typescript/source test/api.bench.ts", | ||
"test": "node --test --experimental-strip-types --no-warnings --conditions @typescript/source ./test/**/*.test.ts" | ||
}, | ||
"devDependencies": { | ||
"tinybench": "^3.1.1" | ||
}, | ||
"dependencies": { | ||
"@typescript/ast": "1.0.0", | ||
"libsyncrpc": "github:microsoft/libsyncrpc#bb02d84" | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/// <reference path="./node.ts" preserve="true" /> | ||
import { SymbolFlags } from "#symbolFlags"; | ||
import { TypeFlags } from "#typeFlags"; | ||
import type { | ||
Node, | ||
SourceFile, | ||
} from "@typescript/ast"; | ||
import { Client } from "./client.ts"; | ||
import type { FileSystem } from "./fs.ts"; | ||
import { RemoteSourceFile } from "./node.ts"; | ||
import { ObjectRegistry } from "./objectRegistry.ts"; | ||
import type { | ||
ConfigResponse, | ||
ProjectResponse, | ||
SymbolResponse, | ||
TypeResponse, | ||
} from "./proto.ts"; | ||
|
||
export { SymbolFlags, TypeFlags }; | ||
|
||
export interface APIOptions { | ||
tsserverPath: string; | ||
cwd?: string; | ||
logFile?: string; | ||
fs?: FileSystem; | ||
} | ||
|
||
export class API { | ||
private client: Client; | ||
private objectRegistry: ObjectRegistry; | ||
constructor(options: APIOptions) { | ||
this.client = new Client(options); | ||
this.objectRegistry = new ObjectRegistry(this.client); | ||
} | ||
|
||
parseConfigFile(fileName: string): ConfigResponse { | ||
return this.client.request("parseConfigFile", { fileName }); | ||
} | ||
|
||
loadProject(configFileName: string): Project { | ||
const data = this.client.request("loadProject", { configFileName }); | ||
return this.objectRegistry.getProject(data); | ||
} | ||
|
||
echo(message: string): string { | ||
return this.client.echo(message); | ||
} | ||
|
||
echoBinary(message: Uint8Array): Uint8Array { | ||
return this.client.echoBinary(message); | ||
} | ||
|
||
close(): void { | ||
this.client.close(); | ||
} | ||
} | ||
|
||
export class DisposableObject { | ||
private disposed: boolean = false; | ||
protected objectRegistry: ObjectRegistry; | ||
constructor(objectRegistry: ObjectRegistry) { | ||
this.objectRegistry = objectRegistry; | ||
} | ||
[globalThis.Symbol.dispose](): void { | ||
this.objectRegistry.release(this); | ||
this.disposed = true; | ||
} | ||
dispose(): void { | ||
this[globalThis.Symbol.dispose](); | ||
} | ||
isDisposed(): boolean { | ||
return this.disposed; | ||
} | ||
ensureNotDisposed(): this { | ||
if (this.disposed) { | ||
throw new Error(`${this.constructor.name} is disposed`); | ||
} | ||
return this; | ||
} | ||
} | ||
|
||
export class Project extends DisposableObject { | ||
private decoder = new TextDecoder(); | ||
private client: Client; | ||
|
||
id: string; | ||
configFileName!: string; | ||
compilerOptions!: Record<string, unknown>; | ||
rootFiles!: readonly string[]; | ||
|
||
constructor(client: Client, objectRegistry: ObjectRegistry, data: ProjectResponse) { | ||
super(objectRegistry); | ||
this.id = data.id; | ||
this.client = client; | ||
this.loadData(data); | ||
} | ||
|
||
loadData(data: ProjectResponse): void { | ||
this.configFileName = data.configFileName; | ||
this.compilerOptions = data.compilerOptions; | ||
this.rootFiles = data.rootFiles; | ||
} | ||
|
||
reload(): void { | ||
this.ensureNotDisposed(); | ||
this.loadData(this.client.request("loadProject", { configFileName: this.configFileName })); | ||
} | ||
|
||
getSourceFile(fileName: string): SourceFile | undefined { | ||
this.ensureNotDisposed(); | ||
const data = this.client.requestBinary("getSourceFile", { project: this.id, fileName }); | ||
return data ? new RemoteSourceFile(data, this.decoder) as unknown as SourceFile : undefined; | ||
} | ||
|
||
getSymbolAtLocation(node: Node): Symbol | undefined; | ||
getSymbolAtLocation(nodes: readonly Node[]): (Symbol | undefined)[]; | ||
getSymbolAtLocation(nodeOrNodes: Node | readonly Node[]): Symbol | (Symbol | undefined)[] | undefined { | ||
this.ensureNotDisposed(); | ||
if (Array.isArray(nodeOrNodes)) { | ||
const data = this.client.request("getSymbolsAtLocations", { project: this.id, locations: nodeOrNodes.map(node => node.id) }); | ||
return data.map((d: SymbolResponse | null) => d ? this.objectRegistry.getSymbol(d) : undefined); | ||
} | ||
const data = this.client.request("getSymbolAtLocation", { project: this.id, location: (nodeOrNodes as Node).id }); | ||
return data ? this.objectRegistry.getSymbol(data) : undefined; | ||
} | ||
|
||
getSymbolAtPosition(fileName: string, position: number): Symbol | undefined; | ||
getSymbolAtPosition(fileName: string, positions: readonly number[]): (Symbol | undefined)[]; | ||
getSymbolAtPosition(fileName: string, positionOrPositions: number | readonly number[]): Symbol | (Symbol | undefined)[] | undefined { | ||
this.ensureNotDisposed(); | ||
if (typeof positionOrPositions === "number") { | ||
const data = this.client.request("getSymbolAtPosition", { project: this.id, fileName, position: positionOrPositions }); | ||
return data ? this.objectRegistry.getSymbol(data) : undefined; | ||
} | ||
const data = this.client.request("getSymbolsAtPositions", { project: this.id, fileName, positions: positionOrPositions }); | ||
return data.map((d: SymbolResponse | null) => d ? this.objectRegistry.getSymbol(d) : undefined); | ||
} | ||
|
||
getTypeOfSymbol(symbol: Symbol): Type | undefined; | ||
getTypeOfSymbol(symbols: readonly Symbol[]): (Type | undefined)[]; | ||
getTypeOfSymbol(symbolOrSymbols: Symbol | readonly Symbol[]): Type | (Type | undefined)[] | undefined { | ||
this.ensureNotDisposed(); | ||
if (Array.isArray(symbolOrSymbols)) { | ||
const data = this.client.request("getTypesOfSymbols", { project: this.id, symbols: symbolOrSymbols.map(symbol => symbol.ensureNotDisposed().id) }); | ||
return data.map((d: TypeResponse | null) => d ? this.objectRegistry.getType(d) : undefined); | ||
} | ||
const data = this.client.request("getTypeOfSymbol", { project: this.id, symbol: (symbolOrSymbols as Symbol).ensureNotDisposed().id }); | ||
return data ? this.objectRegistry.getType(data) : undefined; | ||
} | ||
} | ||
|
||
export class Symbol extends DisposableObject { | ||
private client: Client; | ||
id: string; | ||
name: string; | ||
flags: SymbolFlags; | ||
checkFlags: number; | ||
|
||
constructor(client: Client, objectRegistry: ObjectRegistry, data: SymbolResponse) { | ||
super(objectRegistry); | ||
this.client = client; | ||
this.id = data.id; | ||
this.name = data.name; | ||
this.flags = data.flags; | ||
this.checkFlags = data.checkFlags; | ||
} | ||
} | ||
|
||
export class Type extends DisposableObject { | ||
private client: Client; | ||
id: string; | ||
flags: TypeFlags; | ||
constructor(client: Client, objectRegistry: ObjectRegistry, data: TypeResponse) { | ||
super(objectRegistry); | ||
this.client = client; | ||
this.id = data.id; | ||
this.flags = data.flags; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.