diff --git a/internal/compiler/buildInfo.go b/internal/compiler/buildInfo.go
new file mode 100644
index 0000000000..9d919072d5
--- /dev/null
+++ b/internal/compiler/buildInfo.go
@@ -0,0 +1,29 @@
+package compiler
+
+import (
+	"encoding/json"
+	"errors"
+)
+
+type BuildInfo struct {
+	Version string `json:"version"`
+}
+
+func GetBuildInfo(buildInfoFile string, buildInfoText string) (*BuildInfo, error) {
+	if buildInfoText == "" {
+		return nil, errors.New("empty buildInfoText")
+	}
+	var buildInfo BuildInfo
+	if err := json.Unmarshal([]byte(buildInfoText), &buildInfo); err != nil {
+		return nil, err
+	}
+	return &buildInfo, nil
+}
+
+func GetBuildInfoText(buildInfo BuildInfo) (string, error) {
+	data, err := json.MarshalIndent(buildInfo, "", "    ")
+	if err != nil {
+		return "", err
+	}
+	return string(data), nil
+}
diff --git a/internal/compiler/emitHost.go b/internal/compiler/emitHost.go
index 01445eeb10..dad951304b 100644
--- a/internal/compiler/emitHost.go
+++ b/internal/compiler/emitHost.go
@@ -1,6 +1,8 @@
 package compiler
 
 import (
+	"sync"
+
 	"github.com/microsoft/typescript-go/internal/ast"
 	"github.com/microsoft/typescript-go/internal/core"
 	"github.com/microsoft/typescript-go/internal/printer"
@@ -33,6 +35,10 @@ var _ EmitHost = (*emitHost)(nil)
 // NOTE: emitHost operations must be thread-safe
 type emitHost struct {
 	program *Program
+
+	mu sync.RWMutex
+	// Map storing if there is emit blocking diagnostics for given input
+	hasEmitBlockingDiagnostics map[string]bool
 }
 
 func (host *emitHost) Options() *core.CompilerOptions { return host.program.Options() }
@@ -44,8 +50,19 @@ func (host *emitHost) UseCaseSensitiveFileNames() bool {
 }
 
 func (host *emitHost) IsEmitBlocked(file string) bool {
-	// !!!
-	return false
+	host.mu.RLock()
+	blocked := host.hasEmitBlockingDiagnostics[file]
+	host.mu.RUnlock()
+	return blocked
+}
+
+func (host *emitHost) SetEmitBlocked(file string, blocked bool) {
+	host.mu.Lock()
+	defer host.mu.Unlock()
+	if host.hasEmitBlockingDiagnostics == nil {
+		host.hasEmitBlockingDiagnostics = make(map[string]bool)
+	}
+	host.hasEmitBlockingDiagnostics[file] = blocked
 }
 
 func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool, _ []*ast.SourceFile, _ *WriteFileData) error {
diff --git a/internal/compiler/emitter.go b/internal/compiler/emitter.go
index 927012f9ab..99cc187f45 100644
--- a/internal/compiler/emitter.go
+++ b/internal/compiler/emitter.go
@@ -196,13 +196,39 @@ func getOwnEmitOutputFilePath(fileName string, host EmitHost, extension string)
 }
 
 func getSourceMapFilePath(jsFilePath string, options *core.CompilerOptions) string {
-	// !!!
-	return ""
+	if options.SourceMap.IsTrue() && options.InlineSourceMap.IsFalse() {
+		return jsFilePath + ".map"
+	} else {
+		return ""
+	}
 }
 
 func getDeclarationEmitOutputFilePath(file string, host EmitHost) string {
-	// !!!
-	return ""
+	return getDeclarationEmitOutputFilePathWorker(file, &core.CompilerOptions{}, host)
+}
+
+func getDeclarationEmitOutputFilePathWorker(file string, options *core.CompilerOptions, host EmitHost) string {
+	// Prefer declaration folder if specified
+	outputDir := options.DeclarationDir
+	if outputDir == "" {
+		outputDir = options.OutDir
+	}
+
+	var path string
+	if outputDir != "" {
+		path = getSourceFilePathInNewDir(
+			file,
+			outputDir,
+			host.GetCurrentDirectory(),
+			host.CommonSourceDirectory(),
+			host.UseCaseSensitiveFileNames(),
+		)
+	} else {
+		path = file
+	}
+
+	declarationExtension := tspath.GetDeclarationEmitExtensionForPath(path)
+	return tspath.RemoveFileExtension(path) + declarationExtension
 }
 
 type outputPaths struct {
diff --git a/internal/tspath/extension.go b/internal/tspath/extension.go
index 37217559a2..046fc15207 100644
--- a/internal/tspath/extension.go
+++ b/internal/tspath/extension.go
@@ -120,19 +120,6 @@ func GetDeclarationFileExtension(fileName string) string {
 	return ""
 }
 
-func GetDeclarationEmitExtensionForPath(path string) string {
-	switch {
-	case FileExtensionIsOneOf(path, []string{ExtensionMjs, ExtensionMts}):
-		return ExtensionDmts
-	case FileExtensionIsOneOf(path, []string{ExtensionCjs, ExtensionCts}):
-		return ExtensionDcts
-	case FileExtensionIsOneOf(path, []string{ExtensionJson}):
-		return `.d.json.ts` // Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well
-	default:
-		return ExtensionDts
-	}
-}
-
 // changeAnyExtension changes the extension of a path to the provided extension if it has one of the provided extensions.
 //
 // changeAnyExtension("/path/to/file.ext", ".js", ".ext") === "/path/to/file.js"
@@ -154,3 +141,17 @@ func changeAnyExtension(path string, ext string, extensions []string, ignoreCase
 func ChangeExtension(path string, newExtension string) string {
 	return changeAnyExtension(path, newExtension, extensionsToRemove /*ignoreCase*/, false)
 }
+
+func GetDeclarationEmitExtensionForPath(path string) string {
+	switch {
+	case FileExtensionIsOneOf(path, []string{ExtensionMjs, ExtensionMts}):
+		return ExtensionDmts
+	case FileExtensionIsOneOf(path, []string{ExtensionCjs, ExtensionCts}):
+		return ExtensionDcts
+	case FileExtensionIsOneOf(path, []string{ExtensionJson}):
+		// Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well
+		return ".d.json.ts"
+	default:
+		return ExtensionDts
+	}
+}