Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Herebyfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ const enumDefs = [
{ name: "TokenFlags", goPrefix: "TokenFlags", goFile: "internal/ast/tokenflags.go", outDir: "_packages/native-preview/src/enums" },
{ name: "NodeBuilderFlags", goPrefix: "Flags", goFile: "internal/nodebuilder/types.go", outDir: "_packages/native-preview/src/enums" },
{ name: "CompletionItemKind", goPrefix: "CompletionItemKind", goFile: "internal/lsp/lsproto/lsp_generated.go", outDir: "_packages/native-preview/src/enums" },
{ name: "EmitOnly", goPrefix: "Emit", goFile: "internal/compiler/emitter.go", outDir: "_packages/native-preview/src/enums", excludeMembers: ["OnlyForcedDts"] },
{ name: "EmitOnly", goPrefix: "Emit", goFile: "internal/compiler/emitter.go", outDir: "_packages/native-preview/src/enums", excludeMembers: ["OnlyBuilderSignature"] },
// String enum: Go stores internal names with a "\xFE" sentinel prefix, but the escaped
// form sent over the wire uses "__" (see EscapeSymbolName), so map the sentinel accordingly.
{ name: "InternalSymbolName", goPrefix: "InternalSymbolName", goFile: "internal/ast/symbol.go", outDir: "_packages/native-preview/src/enums", stringEnum: true, valueReplacements: { InternalSymbolNamePrefix: "__" } },
Expand Down
32 changes: 32 additions & 0 deletions _packages/native-preview/src/api/async/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ interface EmitOutputResponse {
readonly outputFiles: readonly (EmitOutputFile & { readonly fileName: string; })[];
}

export interface TranspileOptions {
compilerOptions?: CompilerOptions;
fileName?: string;
reportDiagnostics?: boolean;
}

export interface TranspileOutput {
outputText: string;
diagnostics?: readonly Diagnostic[];
sourceMapText?: string;
}

export class API<FromLSP extends boolean = false> {
private client: Client;
private sourceFileCache: SourceFileCache;
Expand Down Expand Up @@ -177,6 +189,26 @@ export class API<FromLSP extends boolean = false> {
return this.client.apiRequest<ParsedCommandLine>("parseConfigFile", { file });
}

async transpileModule(input: string, options: TranspileOptions = {}): Promise<TranspileOutput> {
await this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileModule", { input, options });
}

async transpileModuleFromFile(fileName: string, options: TranspileOptions = {}): Promise<TranspileOutput> {
await this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileModuleFromFile", { fileName, options });
}

async transpileDeclaration(input: string, options: TranspileOptions = {}): Promise<TranspileOutput> {
await this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileDeclaration", { input, options });
}

async transpileDeclarationFromFile(fileName: string, options: TranspileOptions = {}): Promise<TranspileOutput> {
await this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileDeclarationFromFile", { fileName, options });
}

async updateSnapshot(params?: FromLSP extends true ? LSPUpdateSnapshotParams : UpdateSnapshotParams): Promise<Snapshot> {
await this.ensureInitialized();

Expand Down
32 changes: 32 additions & 0 deletions _packages/native-preview/src/api/sync/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,18 @@ interface EmitOutputResponse {
readonly outputFiles: readonly (EmitOutputFile & { readonly fileName: string; })[];
}

export interface TranspileOptions {
compilerOptions?: CompilerOptions;
fileName?: string;
reportDiagnostics?: boolean;
}

export interface TranspileOutput {
outputText: string;
diagnostics?: readonly Diagnostic[];
sourceMapText?: string;
}

export class API<FromLSP extends boolean = false> {
private client: Client;
private sourceFileCache: SourceFileCache;
Expand Down Expand Up @@ -185,6 +197,26 @@ export class API<FromLSP extends boolean = false> {
return this.client.apiRequest<ParsedCommandLine>("parseConfigFile", { file });
}

transpileModule(input: string, options: TranspileOptions = {}): TranspileOutput {
this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileModule", { input, options });
}

transpileModuleFromFile(fileName: string, options: TranspileOptions = {}): TranspileOutput {
this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileModuleFromFile", { fileName, options });
}

transpileDeclaration(input: string, options: TranspileOptions = {}): TranspileOutput {
this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileDeclaration", { input, options });
}

transpileDeclarationFromFile(fileName: string, options: TranspileOptions = {}): TranspileOutput {
this.ensureInitialized();
return this.client.apiRequest<TranspileOutput>("transpileDeclarationFromFile", { fileName, options });
}

updateSnapshot(params?: FromLSP extends true ? LSPUpdateSnapshotParams : UpdateSnapshotParams): Snapshot {
this.ensureInitialized();

Expand Down
26 changes: 26 additions & 0 deletions _packages/native-preview/test/async/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,32 @@ const defaultFiles = {
};

describe("API", () => {
test("transpile", async () => {
const api = spawnAPI({
"/input.ts": "export const x: number = 1;",
});
try {
const moduleOutput = await api.transpileModule("export const x: number = 1;", {
compilerOptions: { module: ModuleKind.CommonJS },
});
assert.match(moduleOutput.outputText, /exports\.x = 1/);

const moduleFileOutput = await api.transpileModuleFromFile("/input.ts", {
compilerOptions: { module: ModuleKind.CommonJS },
});
assert.match(moduleFileOutput.outputText, /exports\.x = 1/);

const declarationOutput = await api.transpileDeclaration("export const x: number = 1;");
assert.equal(declarationOutput.outputText, "export declare const x: number;\n");

const declarationFileOutput = await api.transpileDeclarationFromFile("/input.ts");
assert.equal(declarationFileOutput.outputText, "export declare const x: number;\n");
}
finally {
await api.close();
}
});

test("parseConfigFile", async () => {
const api = spawnAPI();
try {
Expand Down
26 changes: 26 additions & 0 deletions _packages/native-preview/test/sync/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,32 @@ const defaultFiles = {
};

describe("API", () => {
test("transpile", () => {
const api = spawnAPI({
"/input.ts": "export const x: number = 1;",
});
try {
const moduleOutput = api.transpileModule("export const x: number = 1;", {
compilerOptions: { module: ModuleKind.CommonJS },
});
assert.match(moduleOutput.outputText, /exports\.x = 1/);

const moduleFileOutput = api.transpileModuleFromFile("/input.ts", {
compilerOptions: { module: ModuleKind.CommonJS },
});
assert.match(moduleFileOutput.outputText, /exports\.x = 1/);

const declarationOutput = api.transpileDeclaration("export const x: number = 1;");
assert.equal(declarationOutput.outputText, "export declare const x: number;\n");

const declarationFileOutput = api.transpileDeclarationFromFile("/input.ts");
assert.equal(declarationFileOutput.outputText, "export declare const x: number;\n");
}
finally {
api.close();
}
});

test("parseConfigFile", () => {
const api = spawnAPI();
try {
Expand Down
128 changes: 79 additions & 49 deletions internal/api/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,34 @@ const (
// the connection itself and is not recorded.
MethodResetServerTiming Method = "resetServerTiming"

MethodInitialize Method = "initialize"
MethodUpdateSnapshot Method = "updateSnapshot"
MethodUpdateTemporarySnapshot Method = "updateTemporarySnapshot"
MethodParseConfigFile Method = "parseConfigFile"
MethodGetDefaultProjectForFile Method = "getDefaultProjectForFile"
MethodGetSymbolAtPosition Method = "getSymbolAtPosition"
MethodGetSymbolsAtPositions Method = "getSymbolsAtPositions"
MethodGetSymbolAtLocation Method = "getSymbolAtLocation"
MethodGetSymbolsAtLocations Method = "getSymbolsAtLocations"
MethodGetTypeOfSymbol Method = "getTypeOfSymbol"
MethodGetTypesOfSymbols Method = "getTypesOfSymbols"
MethodGetDeclaredTypeOfSymbol Method = "getDeclaredTypeOfSymbol"
MethodGetSourceFile Method = "getSourceFile"
MethodGetSourceFileNames Method = "getSourceFileNames"
MethodGetSourceFileMetadata Method = "getSourceFileMetadata"
MethodGetConfigFileNames Method = "getConfigFileNames"
MethodGetConfigSourceFile Method = "getConfigSourceFile"
MethodResolveName Method = "resolveName"
MethodGetSignaturesOfType Method = "getSignaturesOfType"
MethodGetResolvedSignature Method = "getResolvedSignature"
MethodGetTypeAtLocation Method = "getTypeAtLocation"
MethodGetTypeAtLocations Method = "getTypeAtLocations"
MethodGetTypeAtPosition Method = "getTypeAtPosition"
MethodGetTypesAtPositions Method = "getTypesAtPositions"
MethodInitialize Method = "initialize"
MethodUpdateSnapshot Method = "updateSnapshot"
MethodUpdateTemporarySnapshot Method = "updateTemporarySnapshot"
MethodParseConfigFile Method = "parseConfigFile"
MethodTranspileModule Method = "transpileModule"
MethodTranspileModuleFromFile Method = "transpileModuleFromFile"
MethodTranspileDeclaration Method = "transpileDeclaration"
MethodTranspileDeclarationFromFile Method = "transpileDeclarationFromFile"
MethodGetDefaultProjectForFile Method = "getDefaultProjectForFile"
MethodGetSymbolAtPosition Method = "getSymbolAtPosition"
MethodGetSymbolsAtPositions Method = "getSymbolsAtPositions"
MethodGetSymbolAtLocation Method = "getSymbolAtLocation"
MethodGetSymbolsAtLocations Method = "getSymbolsAtLocations"
MethodGetTypeOfSymbol Method = "getTypeOfSymbol"
MethodGetTypesOfSymbols Method = "getTypesOfSymbols"
MethodGetDeclaredTypeOfSymbol Method = "getDeclaredTypeOfSymbol"
MethodGetSourceFile Method = "getSourceFile"
MethodGetSourceFileNames Method = "getSourceFileNames"
MethodGetSourceFileMetadata Method = "getSourceFileMetadata"
MethodGetConfigFileNames Method = "getConfigFileNames"
MethodGetConfigSourceFile Method = "getConfigSourceFile"
MethodResolveName Method = "resolveName"
MethodGetSignaturesOfType Method = "getSignaturesOfType"
MethodGetResolvedSignature Method = "getResolvedSignature"
MethodGetTypeAtLocation Method = "getTypeAtLocation"
MethodGetTypeAtLocations Method = "getTypeAtLocations"
MethodGetTypeAtPosition Method = "getTypeAtPosition"
MethodGetTypesAtPositions Method = "getTypesAtPositions"

// Symbol sub-property methods
MethodGetParentOfSymbol Method = "getParentOfSymbol"
Expand Down Expand Up @@ -385,31 +389,35 @@ type UpdateSnapshotResponse struct {
}

var unmarshalers = map[Method]func([]byte) (any, error){
MethodRelease: unmarshallerFor[ReleaseParams],
MethodInitialize: noParams,
MethodUpdateSnapshot: unmarshallerFor[UpdateSnapshotParams],
MethodUpdateTemporarySnapshot: unmarshallerFor[UpdateTemporarySnapshotParams],
MethodParseConfigFile: unmarshallerFor[ParseConfigFileParams],
MethodGetDefaultProjectForFile: unmarshallerFor[GetDefaultProjectForFileParams],
MethodGetSourceFile: unmarshallerFor[GetSourceFileParams],
MethodGetSourceFileNames: unmarshallerFor[GetSourceFileNamesParams],
MethodGetSourceFileMetadata: unmarshallerFor[GetSourceFileParams],
MethodGetConfigFileNames: unmarshallerFor[GetProjectDiagnosticsParams],
MethodGetConfigSourceFile: unmarshallerFor[GetSourceFileParams],
MethodGetSymbolAtPosition: unmarshallerFor[GetSymbolAtPositionParams],
MethodGetSymbolsAtPositions: unmarshallerFor[GetSymbolsAtPositionsParams],
MethodGetSymbolAtLocation: unmarshallerFor[GetSymbolAtLocationParams],
MethodGetSymbolsAtLocations: unmarshallerFor[GetSymbolsAtLocationsParams],
MethodGetTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams],
MethodGetTypesOfSymbols: unmarshallerFor[GetTypesOfSymbolsParams],
MethodGetDeclaredTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams],
MethodResolveName: unmarshallerFor[ResolveNameParams],
MethodGetSignaturesOfType: unmarshallerFor[GetSignaturesOfTypeParams],
MethodGetResolvedSignature: unmarshallerFor[GetResolvedSignatureParams],
MethodGetTypeAtLocation: unmarshallerFor[GetTypeAtLocationParams],
MethodGetTypeAtLocations: unmarshallerFor[GetTypeAtLocationsParams],
MethodGetTypeAtPosition: unmarshallerFor[GetTypeAtPositionParams],
MethodGetTypesAtPositions: unmarshallerFor[GetTypesAtPositionsParams],
MethodRelease: unmarshallerFor[ReleaseParams],
MethodInitialize: noParams,
MethodUpdateSnapshot: unmarshallerFor[UpdateSnapshotParams],
MethodUpdateTemporarySnapshot: unmarshallerFor[UpdateTemporarySnapshotParams],
MethodParseConfigFile: unmarshallerFor[ParseConfigFileParams],
MethodTranspileModule: unmarshallerFor[TranspileParams],
MethodTranspileModuleFromFile: unmarshallerFor[TranspileFromFileParams],
MethodTranspileDeclaration: unmarshallerFor[TranspileParams],
MethodTranspileDeclarationFromFile: unmarshallerFor[TranspileFromFileParams],
MethodGetDefaultProjectForFile: unmarshallerFor[GetDefaultProjectForFileParams],
MethodGetSourceFile: unmarshallerFor[GetSourceFileParams],
MethodGetSourceFileNames: unmarshallerFor[GetSourceFileNamesParams],
MethodGetSourceFileMetadata: unmarshallerFor[GetSourceFileParams],
MethodGetConfigFileNames: unmarshallerFor[GetProjectDiagnosticsParams],
MethodGetConfigSourceFile: unmarshallerFor[GetSourceFileParams],
MethodGetSymbolAtPosition: unmarshallerFor[GetSymbolAtPositionParams],
MethodGetSymbolsAtPositions: unmarshallerFor[GetSymbolsAtPositionsParams],
MethodGetSymbolAtLocation: unmarshallerFor[GetSymbolAtLocationParams],
MethodGetSymbolsAtLocations: unmarshallerFor[GetSymbolsAtLocationsParams],
MethodGetTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams],
MethodGetTypesOfSymbols: unmarshallerFor[GetTypesOfSymbolsParams],
MethodGetDeclaredTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams],
MethodResolveName: unmarshallerFor[ResolveNameParams],
MethodGetSignaturesOfType: unmarshallerFor[GetSignaturesOfTypeParams],
MethodGetResolvedSignature: unmarshallerFor[GetResolvedSignatureParams],
MethodGetTypeAtLocation: unmarshallerFor[GetTypeAtLocationParams],
MethodGetTypeAtLocations: unmarshallerFor[GetTypeAtLocationsParams],
MethodGetTypeAtPosition: unmarshallerFor[GetTypeAtPositionParams],
MethodGetTypesAtPositions: unmarshallerFor[GetTypesAtPositionsParams],

MethodGetParentOfSymbol: unmarshallerFor[GetSymbolPropertyParams],
MethodGetMembersOfSymbol: unmarshallerFor[GetSymbolPropertyParams],
Expand Down Expand Up @@ -519,6 +527,28 @@ type ParseConfigFileParams struct {
File DocumentIdentifier `json:"file"`
}

type TranspileOptions struct {
CompilerOptions *core.CompilerOptions `json:"compilerOptions,omitempty"`
FileName string `json:"fileName,omitempty"`
ReportDiagnostics bool `json:"reportDiagnostics,omitempty"`
}

type TranspileParams struct {
Input string `json:"input"`
Options TranspileOptions `json:"options"`
}

type TranspileFromFileParams struct {
FileName string `json:"fileName"`
Options TranspileOptions `json:"options"`
}

type TranspileOutputResponse struct {
OutputText string `json:"outputText"`
Diagnostics []*DiagnosticResponse `json:"diagnostics,omitempty"`
SourceMapText string `json:"sourceMapText,omitempty"`
}

// ReleaseParams are the parameters for the release method.
type ReleaseParams struct {
Snapshot SnapshotID `json:"snapshot"`
Expand Down
49 changes: 49 additions & 0 deletions internal/api/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/microsoft/typescript-go/internal/pprof"
"github.com/microsoft/typescript-go/internal/printer"
"github.com/microsoft/typescript-go/internal/project"
"github.com/microsoft/typescript-go/internal/transpile"
"github.com/microsoft/typescript-go/internal/tsoptions"
"github.com/microsoft/typescript-go/internal/tspath"
)
Expand Down Expand Up @@ -589,6 +590,14 @@ func (s *Session) HandleRequest(ctx context.Context, method string, params json.
return s.handleUpdateTemporarySnapshot(ctx, parsed.(*UpdateTemporarySnapshotParams))
case string(MethodParseConfigFile):
return s.handleParseConfigFile(ctx, parsed.(*ParseConfigFileParams))
case string(MethodTranspileModule):
return s.handleTranspile(ctx, parsed.(*TranspileParams), false)
case string(MethodTranspileModuleFromFile):
return s.handleTranspileFromFile(ctx, parsed.(*TranspileFromFileParams), false)
case string(MethodTranspileDeclaration):
return s.handleTranspile(ctx, parsed.(*TranspileParams), true)
case string(MethodTranspileDeclarationFromFile):
return s.handleTranspileFromFile(ctx, parsed.(*TranspileFromFileParams), true)
case string(MethodGetDefaultProjectForFile):
return s.handleGetDefaultProjectForFile(ctx, parsed.(*GetDefaultProjectForFileParams))
case string(MethodGetSourceFile):
Expand Down Expand Up @@ -1138,6 +1147,46 @@ func (s *Session) handleParseConfigFile(ctx context.Context, params *ParseConfig
return NewConfigFileResponse(parsedCommandLine), nil
}

func (s *Session) handleTranspile(ctx context.Context, params *TranspileParams, declaration bool) (*TranspileOutputResponse, error) {
return transpileOutput(ctx, params.Input, params.Options, declaration)
}

func (s *Session) handleTranspileFromFile(ctx context.Context, params *TranspileFromFileParams, declaration bool) (*TranspileOutputResponse, error) {
fileName := tspath.GetNormalizedAbsolutePath(params.FileName, s.projectSession.GetCurrentDirectory())
input, ok := s.projectSession.FS().ReadFile(fileName)
if !ok {
return nil, fmt.Errorf("%w: could not read file %q", ErrClientError, fileName)
}
options := params.Options
options.FileName = fileName
return transpileOutput(ctx, input, options, declaration)
}

func transpileOutput(ctx context.Context, input string, options TranspileOptions, declaration bool) (*TranspileOutputResponse, error) {
transpileOptions := transpile.Options{
CompilerOptions: options.CompilerOptions,
FileName: options.FileName,
ReportDiagnostics: options.ReportDiagnostics,
}
var output *transpile.Output
if declaration {
output = transpile.TranspileDeclaration(ctx, input, transpileOptions)
} else {
output = transpile.TranspileModule(ctx, input, transpileOptions)
}
if output == nil {
if err := ctx.Err(); err != nil {
return nil, err
}
return nil, errors.New("transpilation produced no output")
}
return &TranspileOutputResponse{
OutputText: output.OutputText,
Diagnostics: NewDiagnosticResponses(output.Diagnostics),
SourceMapText: output.SourceMapText,
}, nil
}

// handleGetSourceFile returns a source file from a project within a snapshot.
func (s *Session) handleGetSourceFile(ctx context.Context, params *GetSourceFileParams) (any, error) {
sd, err := s.getSnapshotData(params.Snapshot)
Expand Down
Loading