Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 129 additions & 8 deletions _packages/native-preview/src/api/async/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ import {
import type {
CompilerOptions,
CompletionInfoResponse,
CreateProgramOptions,
CreateProgramResponse,
DocumentIdentifier,
DocumentPosition,
FileChanges,
ImportAdderActionRequest,
ImportSymbolActionRequest,
IndexInfoResponse,
Expand Down Expand Up @@ -132,7 +135,66 @@ import type {

export { documentURIToFileName, fileNameToDocumentURI } from "../path.ts";
export { CheckFlags, CompletionItemKind, DiagnosticCategory, ElementFlags, EmitOnly, ModifierFlags, ModuleKind, NodeBuilderFlags, ObjectFlags, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags, TypePredicateKind };
export type { APIOptions, AssertsIdentifierTypePredicate, AssertsThisTypePredicate, BigIntLiteralType, BooleanLiteralType, ClientSocketOptions, ClientSpawnOptions, CompilerOptions, CompletionEntry, CompletionInfo, CompletionOptions, ConditionalType, Diagnostic, DocumentIdentifier, DocumentPosition, EmitOutput, EmitOutputFile, EmitResult, FreshableType, GetImportEditsForSymbolsOptions, IdentifierTypePredicate, ImportAdderAction, IndexedAccessType, IndexInfo, IndexType, InterfaceType, IntersectionType, IntrinsicType, JSDocTagInfo, LiteralType, LSPConnectionOptions, NumberLiteralType, ObjectType, ParsedCommandLine, ProjectReference, ReadConfigFileResult, RequestTiming, SourceFileMetadata, StringLiteralType, StringMappingType, StructuredType, SubstitutionType, TemplateLiteralType, TextEdit, ThisTypePredicate, TimingAccumulators, TimingInfo, TupleType, Type, TypeAcquisition, TypeParameter, TypePredicate, TypePredicateBase, TypeReference, UnionOrIntersectionType, UnionType };
export type {
APIOptions,
AssertsIdentifierTypePredicate,
AssertsThisTypePredicate,
BigIntLiteralType,
BooleanLiteralType,
ClientSocketOptions,
ClientSpawnOptions,
CompilerOptions,
CompletionEntry,
CompletionInfo,
CompletionOptions,
ConditionalType,
CreateProgramOptions,
Diagnostic,
DocumentIdentifier,
DocumentPosition,
EmitOutput,
EmitOutputFile,
EmitResult,
FileChanges,
FreshableType,
GetImportEditsForSymbolsOptions,
IdentifierTypePredicate,
ImportAdderAction,
IndexedAccessType,
IndexInfo,
IndexType,
InterfaceType,
IntersectionType,
IntrinsicType,
JSDocTagInfo,
LiteralType,
LSPConnectionOptions,
NumberLiteralType,
ObjectType,
ParsedCommandLine,
ProjectReference,
ReadConfigFileResult,
RequestTiming,
SourceFileMetadata,
StringLiteralType,
StringMappingType,
StructuredType,
SubstitutionType,
TemplateLiteralType,
TextEdit,
ThisTypePredicate,
TimingAccumulators,
TimingInfo,
TupleType,
Type,
TypeAcquisition,
TypeParameter,
TypePredicate,
TypePredicateBase,
TypeReference,
UnionOrIntersectionType,
UnionType,
};

interface EmitOutputResponse {
readonly emitSkipped: boolean;
Expand Down Expand Up @@ -334,6 +396,44 @@ export class API<FromLSP extends boolean = false> {
resetTimingInfo(): Promise<void> {
return this.client.resetTimingInfo();
}

/**
* Creates a program from the current filesystem state, or derives one from
* oldProgram after applying fileChanges. fileChanges requires oldProgram.
*/
async createProgram(
rootFiles: readonly DocumentIdentifier[],
createProgramOptions: CreateProgramOptions,
oldProgram?: Program,
fileChanges?: FileChanges,
): Promise<Program> {
await this.ensureInitialized();

if (fileChanges && !oldProgram) {
throw new Error("fileChanges requires an oldProgram");
Comment thread
gabritto marked this conversation as resolved.
}

const data = await this.client.apiRequest<CreateProgramResponse>("createProgram", {
rootFiles,
createProgramOptions,
oldProgram: oldProgram ? { snapshot: oldProgram.snapshotId, project: oldProgram.getProject().id } : undefined,
fileChanges,
});
const snapshot = new Snapshot(
{ snapshot: data.snapshot, projects: [data.project] },
this.client,
this.sourceFileCache,
this.toPath!,
() => {
this.activeSnapshots.delete(snapshot);
this.sourceFileCache.releaseSnapshot(snapshot.id);
},
);
const program = snapshot.getProjects()[0].program;
program.setOwnedSnapshot(snapshot);
this.activeSnapshots.add(snapshot);
return program;
}
}

export class InternalAPI {
Expand Down Expand Up @@ -891,13 +991,15 @@ export class LanguageService {
}

export class Program {
private snapshotId: number;
private project: Project;
private client: Client;
private sourceFileCache: SourceFileCache;
private toPath: (fileName: string) => Path;
private decoder = new Wtf8Decoder();
private sourceFileMetadataCache = new Map<Path, Promise<SourceFileMetadata | undefined>>();
/** @internal */
readonly snapshotId: number;
private readonly project: Project;
private readonly client: Client;
private readonly sourceFileCache: SourceFileCache;
private readonly toPath: (fileName: string) => Path;
private readonly decoder = new Wtf8Decoder();
private readonly sourceFileMetadataCache = new Map<Path, Promise<SourceFileMetadata | undefined>>();
private ownedSnapshot: Snapshot | undefined;

constructor(
snapshotId: number,
Expand All @@ -913,6 +1015,21 @@ export class Program {
this.toPath = toPath;
}

/** @internal */
setOwnedSnapshot(snapshot: Snapshot): void {
this.ownedSnapshot = snapshot;
}

[globalThis.Symbol.dispose](): void {
this.dispose();
}

async dispose(): Promise<void> {
const snapshot = this.ownedSnapshot;
this.ownedSnapshot = undefined;
await snapshot?.dispose();
}

getCompilerOptions(): CompilerOptions {
return this.project.compilerOptions;
}
Expand Down Expand Up @@ -1200,6 +1317,10 @@ export class Program {
});
return toEmitOutput(response);
}

getProject(): Project {
return this.project;
}
}

function toEmitOutput(response: EmitOutputResponse): EmitOutput {
Expand Down
13 changes: 13 additions & 0 deletions _packages/native-preview/src/api/proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export interface Diagnostic {
readonly relatedInformation?: readonly Diagnostic[] | undefined;
}

export interface CreateProgramOptions {
compilerOptions: CompilerOptions;
projectReferences?: readonly ProjectReference[];
configFileParsingDiagnostics?: readonly Diagnostic[];
}

export interface ParsedCommandLine {
options: CompilerOptions;
fileNames: string[];
Expand Down Expand Up @@ -251,6 +257,13 @@ export interface UpdateSnapshotResponse {
changes?: SnapshotChanges;
}

export interface CreateProgramResponse {
/** Handle for the snapshot that owns the program. */
snapshot: number;
/** The synthetic project containing the program. */
project: ProjectResponse;
}

export interface ProjectResponse {
id: Path;
configFileName: string;
Expand Down
137 changes: 129 additions & 8 deletions _packages/native-preview/src/api/sync/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ import {
import type {
CompilerOptions,
CompletionInfoResponse,
CreateProgramOptions,
CreateProgramResponse,
DocumentIdentifier,
DocumentPosition,
FileChanges,
ImportAdderActionRequest,
ImportSymbolActionRequest,
IndexInfoResponse,
Expand Down Expand Up @@ -140,7 +143,66 @@ import type {

export { documentURIToFileName, fileNameToDocumentURI } from "../path.ts";
export { CheckFlags, CompletionItemKind, DiagnosticCategory, ElementFlags, EmitOnly, ModifierFlags, ModuleKind, NodeBuilderFlags, ObjectFlags, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags, TypePredicateKind };
export type { APIOptions, AssertsIdentifierTypePredicate, AssertsThisTypePredicate, BigIntLiteralType, BooleanLiteralType, ClientSocketOptions, ClientSpawnOptions, CompilerOptions, CompletionEntry, CompletionInfo, CompletionOptions, ConditionalType, Diagnostic, DocumentIdentifier, DocumentPosition, EmitOutput, EmitOutputFile, EmitResult, FreshableType, GetImportEditsForSymbolsOptions, IdentifierTypePredicate, ImportAdderAction, IndexedAccessType, IndexInfo, IndexType, InterfaceType, IntersectionType, IntrinsicType, JSDocTagInfo, LiteralType, LSPConnectionOptions, NumberLiteralType, ObjectType, ParsedCommandLine, ProjectReference, ReadConfigFileResult, RequestTiming, SourceFileMetadata, StringLiteralType, StringMappingType, StructuredType, SubstitutionType, TemplateLiteralType, TextEdit, ThisTypePredicate, TimingAccumulators, TimingInfo, TupleType, Type, TypeAcquisition, TypeParameter, TypePredicate, TypePredicateBase, TypeReference, UnionOrIntersectionType, UnionType };
export type {
APIOptions,
AssertsIdentifierTypePredicate,
AssertsThisTypePredicate,
BigIntLiteralType,
BooleanLiteralType,
ClientSocketOptions,
ClientSpawnOptions,
CompilerOptions,
CompletionEntry,
CompletionInfo,
CompletionOptions,
ConditionalType,
CreateProgramOptions,
Diagnostic,
DocumentIdentifier,
DocumentPosition,
EmitOutput,
EmitOutputFile,
EmitResult,
FileChanges,
FreshableType,
GetImportEditsForSymbolsOptions,
IdentifierTypePredicate,
ImportAdderAction,
IndexedAccessType,
IndexInfo,
IndexType,
InterfaceType,
IntersectionType,
IntrinsicType,
JSDocTagInfo,
LiteralType,
LSPConnectionOptions,
NumberLiteralType,
ObjectType,
ParsedCommandLine,
ProjectReference,
ReadConfigFileResult,
RequestTiming,
SourceFileMetadata,
StringLiteralType,
StringMappingType,
StructuredType,
SubstitutionType,
TemplateLiteralType,
TextEdit,
ThisTypePredicate,
TimingAccumulators,
TimingInfo,
TupleType,
Type,
TypeAcquisition,
TypeParameter,
TypePredicate,
TypePredicateBase,
TypeReference,
UnionOrIntersectionType,
UnionType,
};

interface EmitOutputResponse {
readonly emitSkipped: boolean;
Expand Down Expand Up @@ -342,6 +404,44 @@ export class API<FromLSP extends boolean = false> {
resetTimingInfo(): void {
return this.client.resetTimingInfo();
}

/**
* Creates a program from the current filesystem state, or derives one from
* oldProgram after applying fileChanges. fileChanges requires oldProgram.
*/
createProgram(
rootFiles: readonly DocumentIdentifier[],
createProgramOptions: CreateProgramOptions,
oldProgram?: Program,
fileChanges?: FileChanges,
): Program {
this.ensureInitialized();

if (fileChanges && !oldProgram) {
throw new Error("fileChanges requires an oldProgram");
Comment thread
gabritto marked this conversation as resolved.
}

const data = this.client.apiRequest<CreateProgramResponse>("createProgram", {
rootFiles,
createProgramOptions,
oldProgram: oldProgram ? { snapshot: oldProgram.snapshotId, project: oldProgram.getProject().id } : undefined,
fileChanges,
});
const snapshot = new Snapshot(
{ snapshot: data.snapshot, projects: [data.project] },
this.client,
this.sourceFileCache,
this.toPath!,
() => {
this.activeSnapshots.delete(snapshot);
this.sourceFileCache.releaseSnapshot(snapshot.id);
},
);
const program = snapshot.getProjects()[0].program;
program.setOwnedSnapshot(snapshot);
this.activeSnapshots.add(snapshot);
return program;
}
}

export class InternalAPI {
Expand Down Expand Up @@ -899,13 +999,15 @@ export class LanguageService {
}

export class Program {
private snapshotId: number;
private project: Project;
private client: Client;
private sourceFileCache: SourceFileCache;
private toPath: (fileName: string) => Path;
private decoder = new Wtf8Decoder();
private sourceFileMetadataCache = new Map<Path, SourceFileMetadata | undefined>();
/** @internal */
readonly snapshotId: number;
private readonly project: Project;
private readonly client: Client;
private readonly sourceFileCache: SourceFileCache;
private readonly toPath: (fileName: string) => Path;
private readonly decoder = new Wtf8Decoder();
private readonly sourceFileMetadataCache = new Map<Path, SourceFileMetadata | undefined>();
private ownedSnapshot: Snapshot | undefined;

constructor(
snapshotId: number,
Expand All @@ -921,6 +1023,21 @@ export class Program {
this.toPath = toPath;
}

/** @internal */
setOwnedSnapshot(snapshot: Snapshot): void {
this.ownedSnapshot = snapshot;
}

[globalThis.Symbol.dispose](): void {
this.dispose();
}

dispose(): void {
const snapshot = this.ownedSnapshot;
this.ownedSnapshot = undefined;
snapshot?.dispose();
}

getCompilerOptions(): CompilerOptions {
return this.project.compilerOptions;
}
Expand Down Expand Up @@ -1208,6 +1325,10 @@ export class Program {
});
return toEmitOutput(response);
}

getProject(): Project {
return this.project;
}
}

function toEmitOutput(response: EmitOutputResponse): EmitOutput {
Expand Down
Loading