diff --git a/kitcom/internal/tsgo/compiler/checkerpool.go b/kitcom/internal/tsgo/compiler/checkerpool.go
deleted file mode 100644
index d697239..0000000
--- a/kitcom/internal/tsgo/compiler/checkerpool.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package compiler
-
-import (
- "context"
- "iter"
- "slices"
- "sync"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/checker"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
-)
-
-type CheckerPool interface {
- GetChecker(ctx context.Context) (*checker.Checker, func())
- GetCheckerForFile(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func())
- GetAllCheckers(ctx context.Context) ([]*checker.Checker, func())
- Files(checker *checker.Checker) iter.Seq[*ast.SourceFile]
-}
-
-type checkerPool struct {
- checkerCount int
- program *Program
-
- createCheckersOnce sync.Once
- checkers []*checker.Checker
- fileAssociations map[*ast.SourceFile]*checker.Checker
-}
-
-var _ CheckerPool = (*checkerPool)(nil)
-
-func newCheckerPool(checkerCount int, program *Program) *checkerPool {
- pool := &checkerPool{
- program: program,
- checkerCount: checkerCount,
- checkers: make([]*checker.Checker, checkerCount),
- }
-
- return pool
-}
-
-func (p *checkerPool) GetCheckerForFile(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func()) {
- p.createCheckers()
- checker := p.fileAssociations[file]
- return checker, noop
-}
-
-func (p *checkerPool) GetChecker(ctx context.Context) (*checker.Checker, func()) {
- p.createCheckers()
- checker := p.checkers[0]
- return checker, noop
-}
-
-func (p *checkerPool) createCheckers() {
- p.createCheckersOnce.Do(func() {
- wg := core.NewWorkGroup(p.program.SingleThreaded())
- for i := range p.checkerCount {
- wg.Queue(func() {
- p.checkers[i] = checker.NewChecker(p.program)
- })
- }
-
- wg.RunAndWait()
-
- p.fileAssociations = make(map[*ast.SourceFile]*checker.Checker, len(p.program.files))
- for i, file := range p.program.files {
- p.fileAssociations[file] = p.checkers[i%p.checkerCount]
- }
- })
-}
-
-func (p *checkerPool) GetAllCheckers(ctx context.Context) ([]*checker.Checker, func()) {
- p.createCheckers()
- return p.checkers, noop
-}
-
-func (p *checkerPool) Files(checker *checker.Checker) iter.Seq[*ast.SourceFile] {
- checkerIndex := slices.Index(p.checkers, checker)
- return func(yield func(*ast.SourceFile) bool) {
- for i, file := range p.program.files {
- if i%p.checkerCount == checkerIndex {
- if !yield(file) {
- return
- }
- }
- }
- }
-}
-
-func noop() {}
diff --git a/kitcom/internal/tsgo/compiler/emitHost.go b/kitcom/internal/tsgo/compiler/emitHost.go
deleted file mode 100644
index 4ecca3d..0000000
--- a/kitcom/internal/tsgo/compiler/emitHost.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package compiler
-
-import (
- "context"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/outputpaths"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/declarations"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-// NOTE: EmitHost operations must be thread-safe
-type EmitHost interface {
- printer.EmitHost
- declarations.DeclarationEmitHost
- Options() *core.CompilerOptions
- SourceFiles() []*ast.SourceFile
- UseCaseSensitiveFileNames() bool
- GetCurrentDirectory() string
- CommonSourceDirectory() string
- IsEmitBlocked(file string) bool
-}
-
-var _ EmitHost = (*emitHost)(nil)
-
-// NOTE: emitHost operations must be thread-safe
-type emitHost struct {
- program *Program
- emitResolver printer.EmitResolver
-}
-
-func newEmitHost(ctx context.Context, program *Program, file *ast.SourceFile) (*emitHost, func()) {
- checker, done := program.GetTypeCheckerForFile(ctx, file)
- return &emitHost{
- program: program,
- emitResolver: checker.GetEmitResolver(),
- }, done
-}
-
-func (host *emitHost) GetModeForUsageLocation(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) core.ResolutionMode {
- return host.program.GetModeForUsageLocation(file, moduleSpecifier)
-}
-
-func (host *emitHost) GetResolvedModuleFromModuleSpecifier(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) *module.ResolvedModule {
- return host.program.GetResolvedModuleFromModuleSpecifier(file, moduleSpecifier)
-}
-
-func (host *emitHost) GetDefaultResolutionModeForFile(file ast.HasFileName) core.ResolutionMode {
- return host.program.GetDefaultResolutionModeForFile(file)
-}
-
-func (host *emitHost) GetEmitModuleFormatOfFile(file ast.HasFileName) core.ModuleKind {
- return host.program.GetEmitModuleFormatOfFile(file)
-}
-
-func (host *emitHost) FileExists(path string) bool {
- return host.program.FileExists(path)
-}
-
-func (host *emitHost) GetGlobalTypingsCacheLocation() string {
- return host.program.GetGlobalTypingsCacheLocation()
-}
-
-func (host *emitHost) GetNearestAncestorDirectoryWithPackageJson(dirname string) string {
- return host.program.GetNearestAncestorDirectoryWithPackageJson(dirname)
-}
-
-func (host *emitHost) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.PackageJsonInfo {
- return host.program.GetPackageJsonInfo(pkgJsonPath)
-}
-
-func (host *emitHost) GetSourceOfProjectReferenceIfOutputIncluded(file ast.HasFileName) string {
- return host.program.GetSourceOfProjectReferenceIfOutputIncluded(file)
-}
-
-func (host *emitHost) GetProjectReferenceFromSource(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
- return host.program.GetProjectReferenceFromSource(path)
-}
-
-func (host *emitHost) GetRedirectTargets(path tspath.Path) []string {
- return host.program.GetRedirectTargets(path)
-}
-
-func (host *emitHost) GetEffectiveDeclarationFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags {
- return host.GetEmitResolver().GetEffectiveDeclarationFlags(node, flags)
-}
-
-func (host *emitHost) GetOutputPathsFor(file *ast.SourceFile, forceDtsPaths bool) declarations.OutputPaths {
- // TODO: cache
- return outputpaths.GetOutputPathsFor(file, host.Options(), host, forceDtsPaths)
-}
-
-func (host *emitHost) GetResolutionModeOverride(node *ast.Node) core.ResolutionMode {
- return host.GetEmitResolver().GetResolutionModeOverride(node)
-}
-
-func (host *emitHost) GetSourceFileFromReference(origin *ast.SourceFile, ref *ast.FileReference) *ast.SourceFile {
- return host.program.GetSourceFileFromReference(origin, ref)
-}
-
-func (host *emitHost) Options() *core.CompilerOptions { return host.program.Options() }
-func (host *emitHost) SourceFiles() []*ast.SourceFile { return host.program.SourceFiles() }
-func (host *emitHost) GetCurrentDirectory() string { return host.program.GetCurrentDirectory() }
-func (host *emitHost) CommonSourceDirectory() string { return host.program.CommonSourceDirectory() }
-func (host *emitHost) UseCaseSensitiveFileNames() bool {
- return host.program.UseCaseSensitiveFileNames()
-}
-
-func (host *emitHost) IsEmitBlocked(file string) bool {
- return host.program.IsEmitBlocked(file)
-}
-
-func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool) error {
- return host.program.Host().FS().WriteFile(fileName, text, writeByteOrderMark)
-}
-
-func (host *emitHost) GetEmitResolver() printer.EmitResolver {
- return host.emitResolver
-}
-
-func (host *emitHost) IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool {
- return host.program.IsSourceFileFromExternalLibrary(file)
-}
diff --git a/kitcom/internal/tsgo/compiler/emitter.go b/kitcom/internal/tsgo/compiler/emitter.go
deleted file mode 100644
index 8b3f1e2..0000000
--- a/kitcom/internal/tsgo/compiler/emitter.go
+++ /dev/null
@@ -1,482 +0,0 @@
-package compiler
-
-import (
- "encoding/base64"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/outputpaths"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/sourcemap"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/stringutil"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/declarations"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/estransforms"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/inliners"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/jsxtransforms"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/moduletransforms"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type EmitOnly byte
-
-const (
- EmitAll EmitOnly = iota
- EmitOnlyJs
- EmitOnlyDts
- EmitOnlyForcedDts
-)
-
-type emitter struct {
- host EmitHost
- emitOnly EmitOnly
- emitterDiagnostics ast.DiagnosticsCollection
- writer printer.EmitTextWriter
- paths *outputpaths.OutputPaths
- sourceFile *ast.SourceFile
- emitResult EmitResult
- writeFile func(fileName string, text string, writeByteOrderMark bool, data *WriteFileData) error
-}
-
-func (e *emitter) emit() {
- // !!! tracing
- e.emitJSFile(e.sourceFile, e.paths.JsFilePath(), e.paths.SourceMapFilePath())
- e.emitDeclarationFile(e.sourceFile, e.paths.DeclarationFilePath(), e.paths.DeclarationMapPath())
- e.emitResult.Diagnostics = e.emitterDiagnostics.GetDiagnostics()
-}
-
-func (e *emitter) getDeclarationTransformers(emitContext *printer.EmitContext, declarationFilePath string, declarationMapPath string) []*declarations.DeclarationTransformer {
- transform := declarations.NewDeclarationTransformer(e.host, emitContext, e.host.Options(), declarationFilePath, declarationMapPath)
- return []*declarations.DeclarationTransformer{transform}
-}
-
-func getModuleTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
- switch opts.CompilerOptions.GetEmitModuleKind() {
- case core.ModuleKindPreserve:
- // `ESModuleTransformer` contains logic for preserving CJS input syntax in `--module preserve`
- return moduletransforms.NewESModuleTransformer(opts)
-
- case core.ModuleKindESNext,
- core.ModuleKindES2022,
- core.ModuleKindES2020,
- core.ModuleKindES2015,
- core.ModuleKindNode20,
- core.ModuleKindNode18,
- core.ModuleKindNode16,
- core.ModuleKindNodeNext,
- core.ModuleKindCommonJS:
- return moduletransforms.NewImpliedModuleTransformer(opts)
-
- default:
- return moduletransforms.NewCommonJSModuleTransformer(opts)
- }
-}
-
-func getScriptTransformers(emitContext *printer.EmitContext, host printer.EmitHost, sourceFile *ast.SourceFile) []*transformers.Transformer {
- var tx []*transformers.Transformer
- options := host.Options()
-
- // JS files don't use reference calculations as they don't do import elision, no need to calculate it
- importElisionEnabled := !options.VerbatimModuleSyntax.IsTrue() && !ast.IsInJSFile(sourceFile.AsNode())
-
- var emitResolver printer.EmitResolver
- var referenceResolver binder.ReferenceResolver
- if importElisionEnabled || options.GetJSXTransformEnabled() || !options.GetIsolatedModules() { // full emit resolver is needed for import ellision and const enum inlining
- emitResolver = host.GetEmitResolver()
- emitResolver.MarkLinkedReferencesRecursively(sourceFile)
- referenceResolver = emitResolver
- } else {
- referenceResolver = binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{})
- }
-
- opts := transformers.TransformOptions{
- Context: emitContext,
- CompilerOptions: options,
- Resolver: referenceResolver,
- EmitResolver: emitResolver,
- GetEmitModuleFormatOfFile: host.GetEmitModuleFormatOfFile,
- }
-
- // transform TypeScript syntax
- {
- // erase types
- tx = append(tx, tstransforms.NewTypeEraserTransformer(&opts))
-
- // elide imports
- if importElisionEnabled {
- tx = append(tx, tstransforms.NewImportElisionTransformer(&opts))
- }
-
- // transform `enum`, `namespace`, and parameter properties
- tx = append(tx, tstransforms.NewRuntimeSyntaxTransformer(&opts))
- }
-
- // !!! transform legacy decorator syntax
- if options.GetJSXTransformEnabled() {
- tx = append(tx, jsxtransforms.NewJSXTransformer(&opts))
- }
-
- downleveler := estransforms.GetESTransformer(&opts)
- if downleveler != nil {
- tx = append(tx, downleveler)
- }
-
- // transform module syntax
- tx = append(tx, getModuleTransformer(&opts))
-
- // inlining (formerly done via substitutions)
- if !options.GetIsolatedModules() {
- tx = append(tx, inliners.NewConstEnumInliningTransformer(&opts))
- }
- return tx
-}
-
-func (e *emitter) emitJSFile(sourceFile *ast.SourceFile, jsFilePath string, sourceMapFilePath string) {
- options := e.host.Options()
-
- if sourceFile == nil || e.emitOnly != EmitAll && e.emitOnly != EmitOnlyJs || len(jsFilePath) == 0 {
- return
- }
-
- if options.NoEmit == core.TSTrue || e.host.IsEmitBlocked(jsFilePath) {
- e.emitResult.EmitSkipped = true
- return
- }
-
- emitContext, putEmitContext := printer.GetEmitContext()
- defer putEmitContext()
-
- for _, transformer := range getScriptTransformers(emitContext, e.host, sourceFile) {
- sourceFile = transformer.TransformSourceFile(sourceFile)
- }
-
- printerOptions := printer.PrinterOptions{
- RemoveComments: options.RemoveComments.IsTrue(),
- NewLine: options.NewLine,
- NoEmitHelpers: options.NoEmitHelpers.IsTrue(),
- SourceMap: options.SourceMap.IsTrue(),
- InlineSourceMap: options.InlineSourceMap.IsTrue(),
- InlineSources: options.InlineSources.IsTrue(),
- // !!!
- }
-
- // create a printer to print the nodes
- printer := printer.NewPrinter(printerOptions, printer.PrintHandlers{
- // !!!
- }, emitContext)
-
- e.printSourceFile(jsFilePath, sourceMapFilePath, sourceFile, printer, shouldEmitSourceMaps(options, sourceFile))
-}
-
-func (e *emitter) emitDeclarationFile(sourceFile *ast.SourceFile, declarationFilePath string, declarationMapPath string) {
- options := e.host.Options()
-
- if sourceFile == nil || e.emitOnly == EmitOnlyJs || len(declarationFilePath) == 0 {
- return
- }
-
- if e.emitOnly != EmitOnlyForcedDts && (options.NoEmit == core.TSTrue || e.host.IsEmitBlocked(declarationFilePath)) {
- e.emitResult.EmitSkipped = true
- return
- }
-
- var diags []*ast.Diagnostic
- emitContext, putEmitContext := printer.GetEmitContext()
- defer putEmitContext()
- for _, transformer := range e.getDeclarationTransformers(emitContext, declarationFilePath, declarationMapPath) {
- sourceFile = transformer.TransformSourceFile(sourceFile)
- diags = append(diags, transformer.GetDiagnostics()...)
- }
-
- // !!! strada skipped emit if there were diagnostics
-
- printerOptions := printer.PrinterOptions{
- RemoveComments: options.RemoveComments.IsTrue(),
- OnlyPrintJSDocStyle: true,
- NewLine: options.NewLine,
- NoEmitHelpers: options.NoEmitHelpers.IsTrue(),
- SourceMap: options.DeclarationMap.IsTrue(),
- InlineSourceMap: options.InlineSourceMap.IsTrue(),
- InlineSources: options.InlineSources.IsTrue(),
- // !!!
- }
-
- // create a printer to print the nodes
- printer := printer.NewPrinter(printerOptions, printer.PrintHandlers{
- // !!!
- }, emitContext)
-
- for _, elem := range diags {
- // Add declaration transform diagnostics to emit diagnostics
- e.emitterDiagnostics.Add(elem)
- }
- e.printSourceFile(declarationFilePath, declarationMapPath, sourceFile, printer, e.emitOnly != EmitOnlyForcedDts && shouldEmitDeclarationSourceMaps(options, sourceFile))
-}
-
-func (e *emitter) printSourceFile(jsFilePath string, sourceMapFilePath string, sourceFile *ast.SourceFile, printer_ *printer.Printer, shouldEmitSourceMaps bool) {
- // !!! sourceMapGenerator
- options := e.host.Options()
- var sourceMapGenerator *sourcemap.Generator
- if shouldEmitSourceMaps {
- sourceMapGenerator = sourcemap.NewGenerator(
- tspath.GetBaseFileName(tspath.NormalizeSlashes(jsFilePath)),
- getSourceRoot(options),
- e.getSourceMapDirectory(options, jsFilePath, sourceFile),
- tspath.ComparePathsOptions{
- UseCaseSensitiveFileNames: e.host.UseCaseSensitiveFileNames(),
- CurrentDirectory: e.host.GetCurrentDirectory(),
- },
- )
- }
-
- printer_.Write(sourceFile.AsNode(), sourceFile, e.writer, sourceMapGenerator)
-
- sourceMapUrlPos := -1
- if sourceMapGenerator != nil {
- if options.SourceMap.IsTrue() || options.InlineSourceMap.IsTrue() || options.GetAreDeclarationMapsEnabled() {
- e.emitResult.SourceMaps = append(e.emitResult.SourceMaps, &SourceMapEmitResult{
- InputSourceFileNames: sourceMapGenerator.Sources(),
- SourceMap: sourceMapGenerator.RawSourceMap(),
- GeneratedFile: jsFilePath,
- })
- }
-
- sourceMappingURL := e.getSourceMappingURL(
- options,
- sourceMapGenerator,
- jsFilePath,
- sourceMapFilePath,
- sourceFile,
- )
-
- if len(sourceMappingURL) > 0 {
- if !e.writer.IsAtStartOfLine() {
- e.writer.RawWrite(core.IfElse(options.NewLine == core.NewLineKindCRLF, "\r\n", "\n"))
- }
- sourceMapUrlPos = e.writer.GetTextPos()
- e.writer.WriteComment("//# sourceMappingURL=" + sourceMappingURL)
- }
-
- // Write the source map
- if len(sourceMapFilePath) > 0 {
- sourceMap := sourceMapGenerator.String()
- err := e.writeText(sourceMapFilePath, sourceMap, false /*writeByteOrderMark*/, nil)
- if err != nil {
- e.emitterDiagnostics.Add(ast.NewCompilerDiagnostic(diagnostics.Could_not_write_file_0_Colon_1, jsFilePath, err.Error()))
- } else {
- e.emitResult.EmittedFiles = append(e.emitResult.EmittedFiles, sourceMapFilePath)
- }
- }
- } else {
- e.writer.WriteLine()
- }
-
- // Write the output file
- text := e.writer.String()
- data := &WriteFileData{
- SourceMapUrlPos: sourceMapUrlPos,
- Diagnostics: e.emitterDiagnostics.GetDiagnostics(),
- }
- err := e.writeText(jsFilePath, text, options.EmitBOM.IsTrue(), data)
- skippedDtsWrite := data.SkippedDtsWrite
- if err != nil {
- e.emitterDiagnostics.Add(ast.NewCompilerDiagnostic(diagnostics.Could_not_write_file_0_Colon_1, jsFilePath, err.Error()))
- } else if !skippedDtsWrite {
- e.emitResult.EmittedFiles = append(e.emitResult.EmittedFiles, jsFilePath)
- }
-
- // Reset state
- e.writer.Clear()
-}
-
-func (e *emitter) writeText(fileName string, text string, writeByteOrderMark bool, data *WriteFileData) error {
- if e.writeFile != nil {
- return e.writeFile(fileName, text, writeByteOrderMark, data)
- }
- return e.host.WriteFile(fileName, text, writeByteOrderMark)
-}
-
-func shouldEmitSourceMaps(mapOptions *core.CompilerOptions, sourceFile *ast.SourceFile) bool {
- return (mapOptions.SourceMap.IsTrue() || mapOptions.InlineSourceMap.IsTrue()) &&
- !tspath.FileExtensionIs(sourceFile.FileName(), tspath.ExtensionJson)
-}
-
-func shouldEmitDeclarationSourceMaps(mapOptions *core.CompilerOptions, sourceFile *ast.SourceFile) bool {
- return mapOptions.DeclarationMap.IsTrue() &&
- !tspath.FileExtensionIs(sourceFile.FileName(), tspath.ExtensionJson)
-}
-
-func getSourceRoot(mapOptions *core.CompilerOptions) string {
- // Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the
- // relative paths of the sources list in the sourcemap
- sourceRoot := tspath.NormalizeSlashes(mapOptions.SourceRoot)
- if len(sourceRoot) > 0 {
- sourceRoot = tspath.EnsureTrailingDirectorySeparator(sourceRoot)
- }
- return sourceRoot
-}
-
-func (e *emitter) getSourceMapDirectory(mapOptions *core.CompilerOptions, filePath string, sourceFile *ast.SourceFile) string {
- if len(mapOptions.SourceRoot) > 0 {
- return e.host.CommonSourceDirectory()
- }
- if len(mapOptions.MapRoot) > 0 {
- sourceMapDir := tspath.NormalizeSlashes(mapOptions.MapRoot)
- if sourceFile != nil {
- // For modules or multiple emit files the mapRoot will have directory structure like the sources
- // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
- sourceMapDir = tspath.GetDirectoryPath(outputpaths.GetSourceFilePathInNewDir(
- sourceFile.FileName(),
- sourceMapDir,
- e.host.GetCurrentDirectory(),
- e.host.CommonSourceDirectory(),
- e.host.UseCaseSensitiveFileNames(),
- ))
- }
- if tspath.GetRootLength(sourceMapDir) == 0 {
- // The relative paths are relative to the common directory
- sourceMapDir = tspath.CombinePaths(e.host.CommonSourceDirectory(), sourceMapDir)
- }
- return sourceMapDir
- }
- return tspath.GetDirectoryPath(tspath.NormalizePath(filePath))
-}
-
-func (e *emitter) getSourceMappingURL(mapOptions *core.CompilerOptions, sourceMapGenerator *sourcemap.Generator, filePath string, sourceMapFilePath string, sourceFile *ast.SourceFile) string {
- if mapOptions.InlineSourceMap.IsTrue() {
- // Encode the sourceMap into the sourceMap url
- sourceMapText := sourceMapGenerator.String()
- base64SourceMapText := base64.StdEncoding.EncodeToString([]byte(sourceMapText))
- return "data:application/json;base64," + base64SourceMapText
- }
-
- sourceMapFile := tspath.GetBaseFileName(tspath.NormalizeSlashes(sourceMapFilePath))
- if len(mapOptions.MapRoot) > 0 {
- sourceMapDir := tspath.NormalizeSlashes(mapOptions.MapRoot)
- if sourceFile != nil {
- // For modules or multiple emit files the mapRoot will have directory structure like the sources
- // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
- sourceMapDir = tspath.GetDirectoryPath(outputpaths.GetSourceFilePathInNewDir(
- sourceFile.FileName(),
- sourceMapDir,
- e.host.GetCurrentDirectory(),
- e.host.CommonSourceDirectory(),
- e.host.UseCaseSensitiveFileNames(),
- ))
- }
- if tspath.GetRootLength(sourceMapDir) == 0 {
- // The relative paths are relative to the common directory
- sourceMapDir = tspath.CombinePaths(e.host.CommonSourceDirectory(), sourceMapDir)
- return stringutil.EncodeURI(
- tspath.GetRelativePathToDirectoryOrUrl(
- tspath.GetDirectoryPath(tspath.NormalizePath(filePath)), // get the relative sourceMapDir path based on jsFilePath
- tspath.CombinePaths(sourceMapDir, sourceMapFile), // this is where user expects to see sourceMap
- /*isAbsolutePathAnUrl*/ true,
- tspath.ComparePathsOptions{
- UseCaseSensitiveFileNames: e.host.UseCaseSensitiveFileNames(),
- CurrentDirectory: e.host.GetCurrentDirectory(),
- },
- ),
- )
- } else {
- return stringutil.EncodeURI(tspath.CombinePaths(sourceMapDir, sourceMapFile))
- }
- }
- return stringutil.EncodeURI(sourceMapFile)
-}
-
-type SourceFileMayBeEmittedHost interface {
- Options() *core.CompilerOptions
- GetProjectReferenceFromSource(path tspath.Path) *tsoptions.SourceOutputAndProjectReference
- IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool
- GetCurrentDirectory() string
- UseCaseSensitiveFileNames() bool
- SourceFiles() []*ast.SourceFile
-}
-
-func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host SourceFileMayBeEmittedHost, forceDtsEmit bool) bool {
- // TODO: move this to outputpaths?
-
- options := host.Options()
- // Js files are emitted only if option is enabled
- if options.NoEmitForJsFiles.IsTrue() && ast.IsSourceFileJS(sourceFile) {
- return false
- }
-
- // Declaration files are not emitted
- if sourceFile.IsDeclarationFile {
- return false
- }
-
- // Source file from node_modules are not emitted
- if host.IsSourceFileFromExternalLibrary(sourceFile) {
- return false
- }
-
- // forcing dts emit => file needs to be emitted
- if forceDtsEmit {
- return true
- }
-
- // Check other conditions for file emit
- // Source files from referenced projects are not emitted
- if host.GetProjectReferenceFromSource(sourceFile.Path()) != nil {
- return false
- }
-
- // Any non json file should be emitted
- if !ast.IsJsonSourceFile(sourceFile) {
- return true
- }
-
- // Json file is not emitted if outDir is not specified
- if options.OutDir == "" {
- return false
- }
-
- // Otherwise if rootDir or composite config file, we know common sourceDir and can check if file would be emitted in same location
- if options.RootDir != "" || (options.Composite.IsTrue() && options.ConfigFilePath != "") {
- commonDir := tspath.GetNormalizedAbsolutePath(outputpaths.GetCommonSourceDirectory(options, func() []string { return nil }, host.GetCurrentDirectory(), host.UseCaseSensitiveFileNames()), host.GetCurrentDirectory())
- outputPath := outputpaths.GetSourceFilePathInNewDirWorker(sourceFile.FileName(), options.OutDir, host.GetCurrentDirectory(), commonDir, host.UseCaseSensitiveFileNames())
- if tspath.ComparePaths(sourceFile.FileName(), outputPath, tspath.ComparePathsOptions{
- UseCaseSensitiveFileNames: host.UseCaseSensitiveFileNames(),
- CurrentDirectory: host.GetCurrentDirectory(),
- }) == 0 {
- return false
- }
- }
-
- return true
-}
-
-func getSourceFilesToEmit(host SourceFileMayBeEmittedHost, targetSourceFile *ast.SourceFile, forceDtsEmit bool) []*ast.SourceFile {
- var sourceFiles []*ast.SourceFile
- if targetSourceFile != nil {
- sourceFiles = []*ast.SourceFile{targetSourceFile}
- } else {
- sourceFiles = host.SourceFiles()
- }
- return core.Filter(sourceFiles, func(sourceFile *ast.SourceFile) bool {
- return sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit)
- })
-}
-
-func isSourceFileNotJson(file *ast.SourceFile) bool {
- return !ast.IsJsonSourceFile(file)
-}
-
-func getDeclarationDiagnostics(host EmitHost, file *ast.SourceFile) []*ast.Diagnostic {
- // TODO: use p.getSourceFilesToEmit cache
- fullFiles := core.Filter(getSourceFilesToEmit(host, file, false), isSourceFileNotJson)
- if !core.Some(fullFiles, func(f *ast.SourceFile) bool { return f == file }) {
- return []*ast.Diagnostic{}
- }
- options := host.Options()
- transform := declarations.NewDeclarationTransformer(host, nil, options, "", "")
- transform.TransformSourceFile(file)
- return transform.GetDiagnostics()
-}
diff --git a/kitcom/internal/tsgo/compiler/fileInclude.go b/kitcom/internal/tsgo/compiler/fileInclude.go
deleted file mode 100644
index 4aaf31f..0000000
--- a/kitcom/internal/tsgo/compiler/fileInclude.go
+++ /dev/null
@@ -1,341 +0,0 @@
-package compiler
-
-import (
- "fmt"
- "sync"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type fileIncludeKind int
-
-const (
- // References from file
- fileIncludeKindImport = iota
- fileIncludeKindReferenceFile
- fileIncludeKindTypeReferenceDirective
- fileIncludeKindLibReferenceDirective
-
- fileIncludeKindRootFile
- fileIncludeKindSourceFromProjectReference
- fileIncludeKindOutputFromProjectReference
- fileIncludeKindLibFile
- fileIncludeKindAutomaticTypeDirectiveFile
-)
-
-type fileIncludeReason struct {
- kind fileIncludeKind
- data any
-
- // Uses relative file name
- relativeFileNameDiag *ast.Diagnostic
- relativeFileNameDiagOnce sync.Once
-
- // Uses file name as is
- diag *ast.Diagnostic
- diagOnce sync.Once
-}
-
-type referencedFileData struct {
- file tspath.Path
- index int
- synthetic *ast.Node
-}
-
-type referenceFileLocation struct {
- file *ast.SourceFile
- node *ast.Node
- ref *ast.FileReference
- packageId module.PackageId
- isSynthetic bool
-}
-
-func (r *referenceFileLocation) text() string {
- if r.node != nil {
- if !ast.NodeIsSynthesized(r.node) {
- return r.file.Text()[scanner.SkipTrivia(r.file.Text(), r.node.Loc.Pos()):r.node.End()]
- } else {
- return fmt.Sprintf(`"%s"`, r.node.Text())
- }
- } else {
- return r.file.Text()[r.ref.Pos():r.ref.End()]
- }
-}
-
-func (r *referenceFileLocation) diagnosticAt(message *diagnostics.Message, args ...any) *ast.Diagnostic {
- if r.node != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(r.file, r.node, message, args...)
- } else {
- return ast.NewDiagnostic(r.file, r.ref.TextRange, message, args...)
- }
-}
-
-type automaticTypeDirectiveFileData struct {
- typeReference string
- packageId module.PackageId
-}
-
-func (r *fileIncludeReason) asIndex() int {
- return r.data.(int)
-}
-
-func (r *fileIncludeReason) asLibFileIndex() (int, bool) {
- index, ok := r.data.(int)
- return index, ok
-}
-
-func (r *fileIncludeReason) isReferencedFile() bool {
- return r != nil && r.kind <= fileIncludeKindLibReferenceDirective
-}
-
-func (r *fileIncludeReason) asReferencedFileData() *referencedFileData {
- return r.data.(*referencedFileData)
-}
-
-func (r *fileIncludeReason) asAutomaticTypeDirectiveFileData() *automaticTypeDirectiveFileData {
- return r.data.(*automaticTypeDirectiveFileData)
-}
-
-func (r *fileIncludeReason) getReferencedLocation(program *Program) *referenceFileLocation {
- ref := r.asReferencedFileData()
- file := program.GetSourceFileByPath(ref.file)
- switch r.kind {
- case fileIncludeKindImport:
- var specifier *ast.Node
- var isSynthetic bool
- if ref.synthetic != nil {
- specifier = ref.synthetic
- isSynthetic = true
- } else if ref.index < len(file.Imports()) {
- specifier = file.Imports()[ref.index]
- } else {
- augIndex := len(file.Imports())
- for _, imp := range file.ModuleAugmentations {
- if imp.Kind == ast.KindStringLiteral {
- if augIndex == ref.index {
- specifier = imp
- break
- }
- augIndex++
- }
- }
- }
- resolution := program.GetResolvedModuleFromModuleSpecifier(file, specifier)
- return &referenceFileLocation{
- file: file,
- node: specifier,
- packageId: resolution.PackageId,
- isSynthetic: isSynthetic,
- }
- case fileIncludeKindReferenceFile:
- return &referenceFileLocation{
- file: file,
- ref: file.ReferencedFiles[ref.index],
- }
- case fileIncludeKindTypeReferenceDirective:
- return &referenceFileLocation{
- file: file,
- ref: file.TypeReferenceDirectives[ref.index],
- }
- case fileIncludeKindLibReferenceDirective:
- return &referenceFileLocation{
- file: file,
- ref: file.LibReferenceDirectives[ref.index],
- }
- default:
- panic(fmt.Sprintf("unknown reason: %v", r.kind))
- }
-}
-
-func (r *fileIncludeReason) toDiagnostic(program *Program, relativeFileName bool) *ast.Diagnostic {
- if relativeFileName {
- r.relativeFileNameDiagOnce.Do(func() {
- r.relativeFileNameDiag = r.computeDiagnostic(program, func(fileName string) string {
- return tspath.GetRelativePathFromDirectory(program.GetCurrentDirectory(), fileName, program.comparePathsOptions)
- })
- })
- return r.relativeFileNameDiag
- } else {
- r.diagOnce.Do(func() {
- r.diag = r.computeDiagnostic(program, func(fileName string) string { return fileName })
- })
- return r.diag
- }
-}
-
-func (r *fileIncludeReason) computeDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic {
- if r.isReferencedFile() {
- return r.computeReferenceFileDiagnostic(program, toFileName)
- }
- switch r.kind {
- case fileIncludeKindRootFile:
- if program.opts.Config.ConfigFile != nil {
- config := program.opts.Config
- fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory())
- if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Part_of_files_list_in_tsconfig_json, matchedFileSpec, toFileName(fileName))
- } else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" {
- if isDefaultIncludeSpec {
- return ast.NewCompilerDiagnostic(diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk)
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Matched_by_include_pattern_0_in_1, matchedIncludeSpec, toFileName(config.ConfigName()))
- }
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation)
- }
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation)
- }
- case fileIncludeKindSourceFromProjectReference,
- fileIncludeKindOutputFromProjectReference:
- diag := core.IfElse(
- r.kind == fileIncludeKindOutputFromProjectReference,
- diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none,
- diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none,
- )
- referencedResolvedRef := program.projectReferenceFileMapper.getResolvedProjectReferences()[r.asIndex()]
- return ast.NewCompilerDiagnostic(diag, toFileName(referencedResolvedRef.ConfigName()))
- case fileIncludeKindAutomaticTypeDirectiveFile:
- data := r.asAutomaticTypeDirectiveFileData()
- if program.Options().Types != nil {
- if data.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, data.typeReference, data.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, data.typeReference)
- }
- } else {
- if data.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, data.typeReference, data.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0, data.typeReference)
- }
- }
- case fileIncludeKindLibFile:
- if index, ok := r.asLibFileIndex(); ok {
- return ast.NewCompilerDiagnostic(diagnostics.Library_0_specified_in_compilerOptions, program.Options().Lib[index])
- } else if target := program.Options().GetEmitScriptTarget().String(); target != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Default_library_for_target_0, target)
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Default_library)
- }
- default:
- panic(fmt.Sprintf("unknown reason: %v", r.kind))
- }
-}
-
-func (r *fileIncludeReason) computeReferenceFileDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic {
- referenceLocation := program.includeProcessor.getReferenceLocation(r, program)
- referenceText := referenceLocation.text()
- switch r.kind {
- case fileIncludeKindImport:
- if !referenceLocation.isSynthetic {
- if referenceLocation.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
- }
- } else if specifier, ok := program.importHelpersImportSpecifiers[referenceLocation.file.Path()]; ok && specifier == referenceLocation.node {
- if referenceLocation.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions, referenceText, toFileName(referenceLocation.file.FileName()))
- }
- } else {
- if referenceLocation.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions, referenceText, toFileName(referenceLocation.file.FileName()))
- }
- }
- case fileIncludeKindReferenceFile:
- return ast.NewCompilerDiagnostic(diagnostics.Referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
- case fileIncludeKindTypeReferenceDirective:
- if referenceLocation.packageId.Name != "" {
- return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
- } else {
- return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
- }
- case fileIncludeKindLibReferenceDirective:
- return ast.NewCompilerDiagnostic(diagnostics.Library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
- default:
- panic(fmt.Sprintf("unknown reason: %v", r.kind))
- }
-}
-
-func (r *fileIncludeReason) toRelatedInfo(program *Program) *ast.Diagnostic {
- if r.isReferencedFile() {
- return r.computeReferenceFileRelatedInfo(program)
- }
- if program.opts.Config.ConfigFile == nil {
- return nil
- }
- config := program.opts.Config
- switch r.kind {
- case fileIncludeKindRootFile:
- fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory())
- if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" {
- if filesNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "files", matchedFileSpec); filesNode != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, filesNode.AsNode(), diagnostics.File_is_matched_by_files_list_specified_here)
- }
- } else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" && !isDefaultIncludeSpec {
- if includeNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "include", matchedIncludeSpec); includeNode != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, includeNode.AsNode(), diagnostics.File_is_matched_by_include_pattern_specified_here)
- }
- }
- case fileIncludeKindSourceFromProjectReference,
- fileIncludeKindOutputFromProjectReference:
- return tsoptions.CreateDiagnosticAtReferenceSyntax(
- config,
- r.asIndex(),
- core.IfElse(
- r.kind == fileIncludeKindOutputFromProjectReference,
- diagnostics.File_is_output_from_referenced_project_specified_here,
- diagnostics.File_is_source_from_referenced_project_specified_here,
- ))
- case fileIncludeKindAutomaticTypeDirectiveFile:
- if program.Options().Types != nil {
- data := r.asAutomaticTypeDirectiveFileData()
- if typesSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "types", data.typeReference); typesSyntax != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, typesSyntax.AsNode(), diagnostics.File_is_entry_point_of_type_library_specified_here)
- }
- }
- case fileIncludeKindLibFile:
- if index, ok := r.asLibFileIndex(); ok {
- if libSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "lib", program.Options().Lib[index]); libSyntax != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, libSyntax.AsNode(), diagnostics.File_is_library_specified_here)
- }
- } else if target := program.Options().GetEmitScriptTarget().String(); target != "" {
- if targetValueSyntax := tsoptions.ForEachPropertyAssignment(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "target", tsoptions.GetCallbackForFindingPropertyAssignmentByValue(target)); targetValueSyntax != nil {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, targetValueSyntax.AsNode(), diagnostics.File_is_default_library_for_target_specified_here)
- }
- }
- default:
- panic(fmt.Sprintf("unknown reason: %v", r.kind))
- }
- return nil
-}
-
-func (r *fileIncludeReason) computeReferenceFileRelatedInfo(program *Program) *ast.Diagnostic {
- referenceLocation := program.includeProcessor.getReferenceLocation(r, program)
- if referenceLocation.isSynthetic {
- return nil
- }
- switch r.kind {
- case fileIncludeKindImport:
- return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_import_here)
- case fileIncludeKindReferenceFile:
- return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_reference_here)
- case fileIncludeKindTypeReferenceDirective:
- return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_type_library_reference_here)
- case fileIncludeKindLibReferenceDirective:
- return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_library_reference_here)
- default:
- panic(fmt.Sprintf("unknown reason: %v", r.kind))
- }
-}
diff --git a/kitcom/internal/tsgo/compiler/fileloader.go b/kitcom/internal/tsgo/compiler/fileloader.go
deleted file mode 100644
index 2fc9cf0..0000000
--- a/kitcom/internal/tsgo/compiler/fileloader.go
+++ /dev/null
@@ -1,744 +0,0 @@
-package compiler
-
-import (
- "cmp"
- "slices"
- "strings"
- "sync"
- "sync/atomic"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type libResolution struct {
- libraryName string
- resolution *module.ResolvedModule
- trace []string
-}
-
-type LibFile struct {
- Name string
- path string
- Replaced bool
-}
-
-type fileLoader struct {
- opts ProgramOptions
- resolver *module.Resolver
- defaultLibraryPath string
- comparePathsOptions tspath.ComparePathsOptions
- supportedExtensions []string
-
- filesParser *filesParser
- rootTasks []*parseTask
- includeProcessor *includeProcessor
-
- totalFileCount atomic.Int32
- libFileCount atomic.Int32
-
- factoryMu sync.Mutex
- factory ast.NodeFactory
-
- projectReferenceFileMapper *projectReferenceFileMapper
- dtsDirectories collections.Set[tspath.Path]
-
- pathForLibFileCache collections.SyncMap[string, *LibFile]
- pathForLibFileResolutions collections.SyncMap[tspath.Path, *libResolution]
-}
-
-type processedFiles struct {
- resolver *module.Resolver
- files []*ast.SourceFile
- filesByPath map[tspath.Path]*ast.SourceFile
- projectReferenceFileMapper *projectReferenceFileMapper
- missingFiles []string
- resolvedModules map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule]
- typeResolutionsInFile map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective]
- sourceFileMetaDatas map[tspath.Path]ast.SourceFileMetaData
- jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier
- importHelpersImportSpecifiers map[tspath.Path]*ast.Node
- libFiles map[tspath.Path]*LibFile
- // List of present unsupported extensions
- unsupportedExtensions []string
- sourceFilesFoundSearchingNodeModules collections.Set[tspath.Path]
- includeProcessor *includeProcessor
- // if file was included using source file and its output is actually part of program
- // this contains mapping from output to source file
- outputFileToProjectReferenceSource map[tspath.Path]string
-}
-
-type jsxRuntimeImportSpecifier struct {
- moduleReference string
- specifier *ast.Node
-}
-
-func processAllProgramFiles(
- opts ProgramOptions,
- singleThreaded bool,
-) processedFiles {
- compilerOptions := opts.Config.CompilerOptions()
- rootFiles := opts.Config.FileNames()
- supportedExtensions := tsoptions.GetSupportedExtensions(compilerOptions, nil /*extraFileExtensions*/)
- var maxNodeModuleJsDepth int
- if p := opts.Config.CompilerOptions().MaxNodeModuleJsDepth; p != nil {
- maxNodeModuleJsDepth = *p
- }
- loader := fileLoader{
- opts: opts,
- defaultLibraryPath: tspath.GetNormalizedAbsolutePath(opts.Host.DefaultLibraryPath(), opts.Host.GetCurrentDirectory()),
- comparePathsOptions: tspath.ComparePathsOptions{
- UseCaseSensitiveFileNames: opts.Host.FS().UseCaseSensitiveFileNames(),
- CurrentDirectory: opts.Host.GetCurrentDirectory(),
- },
- filesParser: &filesParser{
- wg: core.NewWorkGroup(singleThreaded),
- maxDepth: maxNodeModuleJsDepth,
- },
- rootTasks: make([]*parseTask, 0, len(rootFiles)+len(compilerOptions.Lib)),
- supportedExtensions: core.Flatten(tsoptions.GetSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions)),
- includeProcessor: &includeProcessor{},
- }
- loader.addProjectReferenceTasks(singleThreaded)
- loader.resolver = module.NewResolver(loader.projectReferenceFileMapper.host, compilerOptions, opts.TypingsLocation, opts.ProjectName)
- for index, rootFile := range rootFiles {
- loader.addRootTask(rootFile, nil, &fileIncludeReason{kind: fileIncludeKindRootFile, data: index})
- }
- if len(rootFiles) > 0 && compilerOptions.NoLib.IsFalseOrUnknown() {
- if compilerOptions.Lib == nil {
- name := tsoptions.GetDefaultLibFileName(compilerOptions)
- libFile := loader.pathForLibFile(name)
- loader.addRootTask(libFile.path, libFile, &fileIncludeReason{kind: fileIncludeKindLibFile})
-
- } else {
- for index, lib := range compilerOptions.Lib {
- if name, ok := tsoptions.GetLibFileName(lib); ok {
- libFile := loader.pathForLibFile(name)
- loader.addRootTask(libFile.path, libFile, &fileIncludeReason{kind: fileIncludeKindLibFile, data: index})
- }
- // !!! error on unknown name
- }
- }
- }
-
- if len(rootFiles) > 0 {
- loader.addAutomaticTypeDirectiveTasks()
- }
-
- loader.filesParser.parse(&loader, loader.rootTasks)
- // Clear out loader and host to ensure its not used post program creation
- loader.projectReferenceFileMapper.loader = nil
- loader.projectReferenceFileMapper.host = nil
-
- totalFileCount := int(loader.totalFileCount.Load())
- libFileCount := int(loader.libFileCount.Load())
-
- var missingFiles []string
- files := make([]*ast.SourceFile, 0, totalFileCount-libFileCount)
- libFiles := make([]*ast.SourceFile, 0, totalFileCount) // totalFileCount here since we append files to it later to construct the final list
-
- filesByPath := make(map[tspath.Path]*ast.SourceFile, totalFileCount)
- loader.includeProcessor.fileIncludeReasons = make(map[tspath.Path][]*fileIncludeReason, totalFileCount)
- var outputFileToProjectReferenceSource map[tspath.Path]string
- if !opts.canUseProjectReferenceSource() {
- outputFileToProjectReferenceSource = make(map[tspath.Path]string, totalFileCount)
- }
- resolvedModules := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule], totalFileCount+1)
- typeResolutionsInFile := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], totalFileCount)
- sourceFileMetaDatas := make(map[tspath.Path]ast.SourceFileMetaData, totalFileCount)
- var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier
- var importHelpersImportSpecifiers map[tspath.Path]*ast.Node
- var unsupportedExtensions []string
- var sourceFilesFoundSearchingNodeModules collections.Set[tspath.Path]
- libFilesMap := make(map[tspath.Path]*LibFile, libFileCount)
-
- loader.filesParser.collect(&loader, loader.rootTasks, func(task *parseTask) {
- if task.redirectedParseTask != nil {
- if !opts.canUseProjectReferenceSource() {
- outputFileToProjectReferenceSource[task.redirectedParseTask.path] = task.FileName()
- }
- return
- }
-
- if task.isForAutomaticTypeDirective {
- typeResolutionsInFile[task.path] = task.typeResolutionsInFile
- return
- }
- file := task.file
- path := task.path
- if file == nil {
- // !!! sheetal file preprocessing diagnostic explaining getSourceFileFromReferenceWorker
- missingFiles = append(missingFiles, task.normalizedFilePath)
- return
- }
-
- // !!! sheetal todo porting file case errors
- // if _, ok := filesByPath[path]; ok {
- // Check if it differs only in drive letters its ok to ignore that error:
- // const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
- // const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(fileName, currentDirectory);
- // if (checkedAbsolutePath !== inputAbsolutePath) {
- // reportFileNamesDifferOnlyInCasingError(fileName, file, reason);
- // }
- // } else if loader.comparePathsOptions.UseCaseSensitiveFileNames {
- // pathIgnoreCase := tspath.ToPath(file.FileName(), loader.comparePathsOptions.CurrentDirectory, false)
- // // for case-sensitsive file systems check if we've already seen some file with similar filename ignoring case
- // if _, ok := filesByNameIgnoreCase[pathIgnoreCase]; ok {
- // reportFileNamesDifferOnlyInCasingError(fileName, existingFile, reason);
- // } else {
- // filesByNameIgnoreCase[pathIgnoreCase] = file
- // }
- // }
-
- if task.libFile != nil {
- libFiles = append(libFiles, file)
- libFilesMap[path] = task.libFile
- } else {
- files = append(files, file)
- }
- filesByPath[path] = file
- resolvedModules[path] = task.resolutionsInFile
- typeResolutionsInFile[path] = task.typeResolutionsInFile
- sourceFileMetaDatas[path] = task.metadata
-
- if task.jsxRuntimeImportSpecifier != nil {
- if jsxRuntimeImportSpecifiers == nil {
- jsxRuntimeImportSpecifiers = make(map[tspath.Path]*jsxRuntimeImportSpecifier, totalFileCount)
- }
- jsxRuntimeImportSpecifiers[path] = task.jsxRuntimeImportSpecifier
- }
- if task.importHelpersImportSpecifier != nil {
- if importHelpersImportSpecifiers == nil {
- importHelpersImportSpecifiers = make(map[tspath.Path]*ast.Node, totalFileCount)
- }
- importHelpersImportSpecifiers[path] = task.importHelpersImportSpecifier
- }
- extension := tspath.TryGetExtensionFromPath(file.FileName())
- if slices.Contains(tspath.SupportedJSExtensionsFlat, extension) {
- unsupportedExtensions = core.AppendIfUnique(unsupportedExtensions, extension)
- }
- if task.fromExternalLibrary {
- sourceFilesFoundSearchingNodeModules.Add(path)
- }
- })
- loader.sortLibs(libFiles)
-
- allFiles := append(libFiles, files...)
-
- keys := slices.Collect(loader.pathForLibFileResolutions.Keys())
- slices.Sort(keys)
- for _, key := range keys {
- value, _ := loader.pathForLibFileResolutions.Load(key)
- resolvedModules[key] = module.ModeAwareCache[*module.ResolvedModule]{
- module.ModeAwareCacheKey{Name: value.libraryName, Mode: core.ModuleKindCommonJS}: value.resolution,
- }
- for _, trace := range value.trace {
- opts.Host.Trace(trace)
- }
- }
-
- return processedFiles{
- resolver: loader.resolver,
- files: allFiles,
- filesByPath: filesByPath,
- projectReferenceFileMapper: loader.projectReferenceFileMapper,
- resolvedModules: resolvedModules,
- typeResolutionsInFile: typeResolutionsInFile,
- sourceFileMetaDatas: sourceFileMetaDatas,
- jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers,
- importHelpersImportSpecifiers: importHelpersImportSpecifiers,
- unsupportedExtensions: unsupportedExtensions,
- sourceFilesFoundSearchingNodeModules: sourceFilesFoundSearchingNodeModules,
- libFiles: libFilesMap,
- missingFiles: missingFiles,
- includeProcessor: loader.includeProcessor,
- outputFileToProjectReferenceSource: outputFileToProjectReferenceSource,
- }
-}
-
-func (p *fileLoader) toPath(file string) tspath.Path {
- return tspath.ToPath(file, p.opts.Host.GetCurrentDirectory(), p.opts.Host.FS().UseCaseSensitiveFileNames())
-}
-
-func (p *fileLoader) addRootTask(fileName string, libFile *LibFile, includeReason *fileIncludeReason) {
- absPath := tspath.GetNormalizedAbsolutePath(fileName, p.opts.Host.GetCurrentDirectory())
- if core.Tristate.IsTrue(p.opts.Config.CompilerOptions().AllowNonTsExtensions) || slices.Contains(p.supportedExtensions, tspath.TryGetExtensionFromPath(absPath)) {
- p.rootTasks = append(p.rootTasks, &parseTask{
- normalizedFilePath: absPath,
- libFile: libFile,
- includeReason: includeReason,
- })
- }
-}
-
-func (p *fileLoader) addAutomaticTypeDirectiveTasks() {
- var containingDirectory string
- compilerOptions := p.opts.Config.CompilerOptions()
- if compilerOptions.ConfigFilePath != "" {
- containingDirectory = tspath.GetDirectoryPath(compilerOptions.ConfigFilePath)
- } else {
- containingDirectory = p.opts.Host.GetCurrentDirectory()
- }
- containingFileName := tspath.CombinePaths(containingDirectory, module.InferredTypesContainingFile)
- p.rootTasks = append(p.rootTasks, &parseTask{
- normalizedFilePath: containingFileName,
- isForAutomaticTypeDirective: true,
- })
-}
-
-func (p *fileLoader) resolveAutomaticTypeDirectives(containingFileName string) (
- toParse []resolvedRef,
- typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective],
- typeResolutionsTrace []string,
-) {
- automaticTypeDirectiveNames := module.GetAutomaticTypeDirectiveNames(p.opts.Config.CompilerOptions(), p.opts.Host)
- if len(automaticTypeDirectiveNames) != 0 {
- toParse = make([]resolvedRef, 0, len(automaticTypeDirectiveNames))
- typeResolutionsInFile = make(module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], len(automaticTypeDirectiveNames))
- for _, name := range automaticTypeDirectiveNames {
- resolutionMode := core.ModuleKindNodeNext
- resolved, trace := p.resolver.ResolveTypeReferenceDirective(name, containingFileName, resolutionMode, nil)
- typeResolutionsInFile[module.ModeAwareCacheKey{Name: name, Mode: resolutionMode}] = resolved
- typeResolutionsTrace = append(typeResolutionsTrace, trace...)
- if resolved.IsResolved() {
- toParse = append(toParse, resolvedRef{
- fileName: resolved.ResolvedFileName,
- increaseDepth: resolved.IsExternalLibraryImport,
- elideOnDepth: false,
- includeReason: &fileIncludeReason{
- kind: fileIncludeKindAutomaticTypeDirectiveFile,
- data: &automaticTypeDirectiveFileData{name, resolved.PackageId},
- },
- })
- }
- }
- }
- return toParse, typeResolutionsInFile, typeResolutionsTrace
-}
-
-func (p *fileLoader) addProjectReferenceTasks(singleThreaded bool) {
- p.projectReferenceFileMapper = &projectReferenceFileMapper{
- opts: p.opts,
- host: p.opts.Host,
- }
- projectReferences := p.opts.Config.ResolvedProjectReferencePaths()
- if len(projectReferences) == 0 {
- return
- }
-
- parser := &projectReferenceParser{
- loader: p,
- wg: core.NewWorkGroup(singleThreaded),
- }
- rootTasks := createProjectReferenceParseTasks(projectReferences)
- parser.parse(rootTasks)
-
- // Add files from project references as root if the module kind is 'none'.
- // This ensures that files from project references are included in the root tasks
- // when no module system is specified, allowing including all files for global symbol merging
- // !!! sheetal Do we really need it?
- if len(p.opts.Config.FileNames()) != 0 {
- for index, resolved := range p.projectReferenceFileMapper.getResolvedProjectReferences() {
- if resolved == nil || resolved.CompilerOptions().GetEmitModuleKind() != core.ModuleKindNone {
- continue
- }
- if p.opts.canUseProjectReferenceSource() {
- for _, fileName := range resolved.FileNames() {
- p.rootTasks = append(p.rootTasks, &parseTask{
- normalizedFilePath: fileName,
- includeReason: &fileIncludeReason{
- kind: fileIncludeKindSourceFromProjectReference,
- data: index,
- },
- })
- }
- } else {
- for outputDts := range resolved.GetOutputDeclarationAndSourceFileNames() {
- if outputDts != "" {
- p.rootTasks = append(p.rootTasks, &parseTask{
- normalizedFilePath: outputDts,
- includeReason: &fileIncludeReason{
- kind: fileIncludeKindOutputFromProjectReference,
- data: index,
- },
- })
- }
- }
- }
- }
- }
-}
-
-func (p *fileLoader) sortLibs(libFiles []*ast.SourceFile) {
- slices.SortFunc(libFiles, func(f1 *ast.SourceFile, f2 *ast.SourceFile) int {
- return cmp.Compare(p.getDefaultLibFilePriority(f1), p.getDefaultLibFilePriority(f2))
- })
-}
-
-func (p *fileLoader) getDefaultLibFilePriority(a *ast.SourceFile) int {
- // defaultLibraryPath and a.FileName() are absolute and normalized; a prefix check should suffice.
- defaultLibraryPath := tspath.RemoveTrailingDirectorySeparator(p.defaultLibraryPath)
- aFileName := a.FileName()
-
- if strings.HasPrefix(aFileName, defaultLibraryPath) && len(aFileName) > len(defaultLibraryPath) && aFileName[len(defaultLibraryPath)] == tspath.DirectorySeparator {
- // avoid tspath.GetBaseFileName; we know these paths are already absolute and normalized.
- basename := aFileName[strings.LastIndexByte(aFileName, tspath.DirectorySeparator)+1:]
- if basename == "lib.d.ts" || basename == "lib.es6.d.ts" {
- return 0
- }
- name := strings.TrimSuffix(strings.TrimPrefix(basename, "lib."), ".d.ts")
- index := slices.Index(tsoptions.Libs, name)
- if index != -1 {
- return index + 1
- }
- }
- return len(tsoptions.Libs) + 2
-}
-
-func (p *fileLoader) loadSourceFileMetaData(fileName string) ast.SourceFileMetaData {
- packageJsonScope := p.resolver.GetPackageJsonScopeIfApplicable(fileName)
- var packageJsonType, packageJsonDirectory string
- if packageJsonScope.Exists() {
- packageJsonDirectory = packageJsonScope.PackageDirectory
- if value, ok := packageJsonScope.Contents.Type.GetValue(); ok {
- packageJsonType = value
- }
- }
- impliedNodeFormat := ast.GetImpliedNodeFormatForFile(fileName, packageJsonType)
- return ast.SourceFileMetaData{
- PackageJsonType: packageJsonType,
- PackageJsonDirectory: packageJsonDirectory,
- ImpliedNodeFormat: impliedNodeFormat,
- }
-}
-
-func (p *fileLoader) parseSourceFile(t *parseTask) *ast.SourceFile {
- path := p.toPath(t.normalizedFilePath)
- options := p.projectReferenceFileMapper.getCompilerOptionsForFile(t)
- sourceFile := p.opts.Host.GetSourceFile(ast.SourceFileParseOptions{
- FileName: t.normalizedFilePath,
- Path: path,
- CompilerOptions: ast.GetSourceFileAffectingCompilerOptions(t.normalizedFilePath, options),
- ExternalModuleIndicatorOptions: ast.GetExternalModuleIndicatorOptions(t.normalizedFilePath, options, t.metadata),
- JSDocParsingMode: p.opts.JSDocParsingMode,
- })
- return sourceFile
-}
-
-func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containingFile string, index int) resolvedRef {
- basePath := tspath.GetDirectoryPath(containingFile)
- referencedFileName := moduleName
-
- if !tspath.IsRootedDiskPath(moduleName) {
- referencedFileName = tspath.CombinePaths(basePath, moduleName)
- }
- return resolvedRef{
- fileName: tspath.NormalizePath(referencedFileName),
- includeReason: &fileIncludeReason{
- kind: fileIncludeKindReferenceFile,
- data: &referencedFileData{
- file: p.toPath(containingFile),
- index: index,
- },
- },
- }
-}
-
-func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) {
- file := t.file
- if len(file.TypeReferenceDirectives) == 0 {
- return
- }
- meta := t.metadata
-
- typeResolutionsInFile := make(module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], len(file.TypeReferenceDirectives))
- var typeResolutionsTrace []string
- for index, ref := range file.TypeReferenceDirectives {
- redirect, fileName := p.projectReferenceFileMapper.getRedirectForResolution(file)
- resolutionMode := getModeForTypeReferenceDirectiveInFile(ref, file, meta, module.GetCompilerOptionsWithRedirect(p.opts.Config.CompilerOptions(), redirect))
- resolved, trace := p.resolver.ResolveTypeReferenceDirective(ref.FileName, fileName, resolutionMode, redirect)
- typeResolutionsInFile[module.ModeAwareCacheKey{Name: ref.FileName, Mode: resolutionMode}] = resolved
- includeReason := &fileIncludeReason{
- kind: fileIncludeKindTypeReferenceDirective,
- data: &referencedFileData{
- file: t.path,
- index: index,
- },
- }
- typeResolutionsTrace = append(typeResolutionsTrace, trace...)
-
- if resolved.IsResolved() {
- t.addSubTask(resolvedRef{
- fileName: resolved.ResolvedFileName,
- increaseDepth: resolved.IsExternalLibraryImport,
- elideOnDepth: false,
- isFromExternalLibrary: resolved.IsExternalLibraryImport,
- includeReason: includeReason,
- }, nil)
- } else {
- p.includeProcessor.addProcessingDiagnostic(&processingDiagnostic{
- kind: processingDiagnosticKindUnknownReference,
- data: includeReason,
- })
- }
- }
-
- t.typeResolutionsInFile = typeResolutionsInFile
- t.typeResolutionsTrace = typeResolutionsTrace
-}
-
-const externalHelpersModuleNameText = "tslib" // TODO(jakebailey): dedupe
-
-func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) {
- file := t.file
- meta := t.metadata
-
- moduleNames := make([]*ast.Node, 0, len(file.Imports())+len(file.ModuleAugmentations)+2)
-
- isJavaScriptFile := ast.IsSourceFileJS(file)
- isExternalModuleFile := ast.IsExternalModule(file)
-
- redirect, fileName := p.projectReferenceFileMapper.getRedirectForResolution(file)
- optionsForFile := module.GetCompilerOptionsWithRedirect(p.opts.Config.CompilerOptions(), redirect)
- if isJavaScriptFile || (!file.IsDeclarationFile && (optionsForFile.GetIsolatedModules() || isExternalModuleFile)) {
- if optionsForFile.ImportHelpers.IsTrue() {
- specifier := p.createSyntheticImport(externalHelpersModuleNameText, file)
- moduleNames = append(moduleNames, specifier)
- t.importHelpersImportSpecifier = specifier
- }
-
- jsxImport := ast.GetJSXRuntimeImport(ast.GetJSXImplicitImportBase(optionsForFile, file), optionsForFile)
- if jsxImport != "" {
- specifier := p.createSyntheticImport(jsxImport, file)
- moduleNames = append(moduleNames, specifier)
- t.jsxRuntimeImportSpecifier = &jsxRuntimeImportSpecifier{
- moduleReference: jsxImport,
- specifier: specifier,
- }
- }
- }
-
- importsStart := len(moduleNames)
-
- moduleNames = append(moduleNames, file.Imports()...)
- for _, imp := range file.ModuleAugmentations {
- if imp.Kind == ast.KindStringLiteral {
- moduleNames = append(moduleNames, imp)
- }
- // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
- }
-
- if len(moduleNames) != 0 {
- resolutionsInFile := make(module.ModeAwareCache[*module.ResolvedModule], len(moduleNames))
- var resolutionsTrace []string
-
- for index, entry := range moduleNames {
- moduleName := entry.Text()
- if moduleName == "" {
- continue
- }
-
- mode := getModeForUsageLocation(file.FileName(), meta, entry, optionsForFile)
- resolvedModule, trace := p.resolver.ResolveModuleName(moduleName, fileName, mode, redirect)
- resolutionsInFile[module.ModeAwareCacheKey{Name: moduleName, Mode: mode}] = resolvedModule
- resolutionsTrace = append(resolutionsTrace, trace...)
-
- if !resolvedModule.IsResolved() {
- continue
- }
-
- resolvedFileName := resolvedModule.ResolvedFileName
- isFromNodeModulesSearch := resolvedModule.IsExternalLibraryImport
- // Don't treat redirected files as JS files.
- isJsFile := !tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsWithJsonFlat) && p.projectReferenceFileMapper.getRedirectParsedCommandLineForResolution(ast.NewHasFileName(resolvedFileName, p.toPath(resolvedFileName))) == nil
- isJsFileFromNodeModules := isFromNodeModulesSearch && isJsFile && strings.Contains(resolvedFileName, "/node_modules/")
-
- // add file to program only if:
- // - resolution was successful
- // - noResolve is falsy
- // - module name comes from the list of imports
- // - it's not a top level JavaScript module that exceeded the search max
-
- importIndex := index - importsStart
-
- shouldAddFile := moduleName != "" &&
- module.GetResolutionDiagnostic(optionsForFile, resolvedModule, file) == nil &&
- !optionsForFile.NoResolve.IsTrue() &&
- !(isJsFile && !optionsForFile.GetAllowJS()) &&
- (importIndex < 0 || (importIndex < len(file.Imports()) && (ast.IsInJSFile(file.Imports()[importIndex]) || file.Imports()[importIndex].Flags&ast.NodeFlagsJSDoc == 0)))
-
- if shouldAddFile {
- t.addSubTask(resolvedRef{
- fileName: resolvedFileName,
- increaseDepth: resolvedModule.IsExternalLibraryImport,
- elideOnDepth: isJsFileFromNodeModules,
- isFromExternalLibrary: resolvedModule.IsExternalLibraryImport,
- includeReason: &fileIncludeReason{
- kind: fileIncludeKindImport,
- data: &referencedFileData{
- file: t.path,
- index: importIndex,
- synthetic: core.IfElse(importIndex < 0, entry, nil),
- },
- },
- }, nil)
- }
- }
-
- t.resolutionsInFile = resolutionsInFile
- t.resolutionsTrace = resolutionsTrace
- }
-}
-
-func (p *fileLoader) createSyntheticImport(text string, file *ast.SourceFile) *ast.Node {
- p.factoryMu.Lock()
- defer p.factoryMu.Unlock()
- externalHelpersModuleReference := p.factory.NewStringLiteral(text)
- importDecl := p.factory.NewImportDeclaration(nil, nil, externalHelpersModuleReference, nil)
- // !!! addInternalEmitFlags(importDecl, InternalEmitFlags.NeverApplyImportHelper);
- externalHelpersModuleReference.Parent = importDecl
- importDecl.Parent = file.AsNode()
- // !!! externalHelpersModuleReference.Flags &^= ast.NodeFlagsSynthesized
- // !!! importDecl.Flags &^= ast.NodeFlagsSynthesized
- return externalHelpersModuleReference
-}
-
-func (p *fileLoader) pathForLibFile(name string) *LibFile {
- if cached, ok := p.pathForLibFileCache.Load(name); ok {
- return cached
- }
-
- path := tspath.CombinePaths(p.defaultLibraryPath, name)
- replaced := false
- if p.opts.Config.CompilerOptions().LibReplacement.IsTrue() && name != "lib.d.ts" {
- libraryName := getLibraryNameFromLibFileName(name)
- resolveFrom := getInferredLibraryNameResolveFrom(p.opts.Config.CompilerOptions(), p.opts.Host.GetCurrentDirectory(), name)
- resolution, trace := p.resolver.ResolveModuleName(libraryName, resolveFrom, core.ModuleKindCommonJS, nil)
- if resolution.IsResolved() {
- path = resolution.ResolvedFileName
- replaced = true
- }
- p.pathForLibFileResolutions.LoadOrStore(p.toPath(resolveFrom), &libResolution{
- libraryName: libraryName,
- resolution: resolution,
- trace: trace,
- })
- }
-
- libPath, _ := p.pathForLibFileCache.LoadOrStore(name, &LibFile{name, path, replaced})
- return libPath
-}
-
-func getLibraryNameFromLibFileName(libFileName string) string {
- // Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
- // lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
- // lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
- components := strings.Split(libFileName, ".")
- var path string
- if len(components) > 1 {
- path = components[1]
- }
- i := 2
- for i < len(components) && components[i] != "" && components[i] != "d" {
- path += core.IfElse(i == 2, "/", "-") + components[i]
- i++
- }
- return "@typescript/lib-" + path
-}
-
-func getInferredLibraryNameResolveFrom(options *core.CompilerOptions, currentDirectory string, libFileName string) string {
- var containingDirectory string
- if options.ConfigFilePath != "" {
- containingDirectory = tspath.GetDirectoryPath(options.ConfigFilePath)
- } else {
- containingDirectory = currentDirectory
- }
- return tspath.CombinePaths(containingDirectory, "__lib_node_modules_lookup_"+libFileName+"__.ts")
-}
-
-func getModeForTypeReferenceDirectiveInFile(ref *ast.FileReference, file *ast.SourceFile, meta ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode {
- if ref.ResolutionMode != core.ResolutionModeNone {
- return ref.ResolutionMode
- } else {
- return getDefaultResolutionModeForFile(file.FileName(), meta, options)
- }
-}
-
-func getDefaultResolutionModeForFile(fileName string, meta ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode {
- if importSyntaxAffectsModuleResolution(options) {
- return ast.GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), meta)
- } else {
- return core.ResolutionModeNone
- }
-}
-
-func getModeForUsageLocation(fileName string, meta ast.SourceFileMetaData, usage *ast.StringLiteralLike, options *core.CompilerOptions) core.ResolutionMode {
- if ast.IsImportDeclaration(usage.Parent) || usage.Parent.Kind == ast.KindJSImportDeclaration || ast.IsExportDeclaration(usage.Parent) || ast.IsJSDocImportTag(usage.Parent) {
- isTypeOnly := ast.IsExclusivelyTypeOnlyImportOrExport(usage.Parent)
- if isTypeOnly {
- var override core.ResolutionMode
- var ok bool
- switch usage.Parent.Kind {
- case ast.KindImportDeclaration, ast.KindJSImportDeclaration:
- override, ok = usage.Parent.AsImportDeclaration().Attributes.GetResolutionModeOverride()
- case ast.KindExportDeclaration:
- override, ok = usage.Parent.AsExportDeclaration().Attributes.GetResolutionModeOverride()
- case ast.KindJSDocImportTag:
- override, ok = usage.Parent.AsJSDocImportTag().Attributes.GetResolutionModeOverride()
- }
- if ok {
- return override
- }
- }
- }
- if ast.IsLiteralTypeNode(usage.Parent) && ast.IsImportTypeNode(usage.Parent.Parent) {
- if override, ok := usage.Parent.Parent.AsImportTypeNode().Attributes.GetResolutionModeOverride(); ok {
- return override
- }
- }
-
- if options != nil && importSyntaxAffectsModuleResolution(options) {
- return getEmitSyntaxForUsageLocationWorker(fileName, meta, usage, options)
- }
-
- return core.ResolutionModeNone
-}
-
-func importSyntaxAffectsModuleResolution(options *core.CompilerOptions) bool {
- moduleResolution := options.GetModuleResolutionKind()
- return core.ModuleResolutionKindNode16 <= moduleResolution && moduleResolution <= core.ModuleResolutionKindNodeNext ||
- options.GetResolvePackageJsonExports() || options.GetResolvePackageJsonImports()
-}
-
-func getEmitSyntaxForUsageLocationWorker(fileName string, meta ast.SourceFileMetaData, usage *ast.Node, options *core.CompilerOptions) core.ResolutionMode {
- if ast.IsRequireCall(usage.Parent, false /*requireStringLiteralLikeArgument*/) || ast.IsExternalModuleReference(usage.Parent) && ast.IsImportEqualsDeclaration(usage.Parent.Parent) {
- return core.ModuleKindCommonJS
- }
- fileEmitMode := ast.GetEmitModuleFormatOfFileWorker(fileName, options, meta)
- if ast.IsImportCall(ast.WalkUpParenthesizedExpressions(usage.Parent)) {
- if ast.ShouldTransformImportCall(fileName, options, fileEmitMode) {
- return core.ModuleKindCommonJS
- } else {
- return core.ModuleKindESNext
- }
- }
- // If we're in --module preserve on an input file, we know that an import
- // is an import. But if this is a declaration file, we'd prefer to use the
- // impliedNodeFormat. Since we want things to be consistent between the two,
- // we need to issue errors when the user writes ESM syntax in a definitely-CJS
- // file, until/unless declaration emit can indicate a true ESM import. On the
- // other hand, writing CJS syntax in a definitely-ESM file is fine, since declaration
- // emit preserves the CJS syntax.
- if fileEmitMode == core.ModuleKindCommonJS {
- return core.ModuleKindCommonJS
- } else {
- if fileEmitMode.IsNonNodeESM() || fileEmitMode == core.ModuleKindPreserve {
- return core.ModuleKindESNext
- }
- }
- return core.ModuleKindNone
-}
diff --git a/kitcom/internal/tsgo/compiler/filesparser.go b/kitcom/internal/tsgo/compiler/filesparser.go
deleted file mode 100644
index e6b2c73..0000000
--- a/kitcom/internal/tsgo/compiler/filesparser.go
+++ /dev/null
@@ -1,280 +0,0 @@
-package compiler
-
-import (
- "math"
- "sync"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type parseTask struct {
- normalizedFilePath string
- path tspath.Path
- file *ast.SourceFile
- libFile *LibFile
- redirectedParseTask *parseTask
- subTasks []*parseTask
- loaded bool
- isForAutomaticTypeDirective bool
- includeReason *fileIncludeReason
-
- metadata ast.SourceFileMetaData
- resolutionsInFile module.ModeAwareCache[*module.ResolvedModule]
- resolutionsTrace []string
- typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective]
- typeResolutionsTrace []string
- resolutionDiagnostics []*ast.Diagnostic
- importHelpersImportSpecifier *ast.Node
- jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier
- increaseDepth bool
- elideOnDepth bool
-
- // Track if this file is from an external library (node_modules)
- // This mirrors the TypeScript currentNodeModulesDepth > 0 check
- fromExternalLibrary bool
-
- loadedTask *parseTask
- allIncludeReasons []*fileIncludeReason
-}
-
-func (t *parseTask) FileName() string {
- return t.normalizedFilePath
-}
-
-func (t *parseTask) Path() tspath.Path {
- return t.path
-}
-
-func (t *parseTask) isRoot() bool {
- // Intentionally not checking t.includeReason != nil to ensure we can catch cases for missing include reason
- return !t.isForAutomaticTypeDirective && (t.includeReason.kind == fileIncludeKindRootFile || t.includeReason.kind == fileIncludeKindLibFile)
-}
-
-func (t *parseTask) load(loader *fileLoader) {
- t.loaded = true
- t.path = loader.toPath(t.normalizedFilePath)
- if t.isForAutomaticTypeDirective {
- t.loadAutomaticTypeDirectives(loader)
- return
- }
- redirect := loader.projectReferenceFileMapper.getParseFileRedirect(t)
- if redirect != "" {
- t.redirect(loader, redirect)
- return
- }
-
- loader.totalFileCount.Add(1)
- if t.libFile != nil {
- loader.libFileCount.Add(1)
- }
-
- t.metadata = loader.loadSourceFileMetaData(t.normalizedFilePath)
- file := loader.parseSourceFile(t)
- if file == nil {
- return
- }
-
- t.file = file
- t.subTasks = make([]*parseTask, 0, len(file.ReferencedFiles)+len(file.Imports())+len(file.ModuleAugmentations))
-
- for index, ref := range file.ReferencedFiles {
- resolvedPath := loader.resolveTripleslashPathReference(ref.FileName, file.FileName(), index)
- t.addSubTask(resolvedPath, nil)
- }
-
- compilerOptions := loader.opts.Config.CompilerOptions()
- loader.resolveTypeReferenceDirectives(t)
-
- if compilerOptions.NoLib != core.TSTrue {
- for index, lib := range file.LibReferenceDirectives {
- includeReason := &fileIncludeReason{
- kind: fileIncludeKindLibReferenceDirective,
- data: &referencedFileData{
- file: t.path,
- index: index,
- },
- }
- if name, ok := tsoptions.GetLibFileName(lib.FileName); ok {
- libFile := loader.pathForLibFile(name)
- t.addSubTask(resolvedRef{
- fileName: libFile.path,
- includeReason: includeReason,
- }, libFile)
- } else {
- loader.includeProcessor.addProcessingDiagnostic(&processingDiagnostic{
- kind: processingDiagnosticKindUnknownReference,
- data: includeReason,
- })
- }
- }
- }
-
- loader.resolveImportsAndModuleAugmentations(t)
-}
-
-func (t *parseTask) redirect(loader *fileLoader, fileName string) {
- t.redirectedParseTask = &parseTask{
- normalizedFilePath: tspath.NormalizePath(fileName),
- libFile: t.libFile,
- fromExternalLibrary: t.fromExternalLibrary,
- includeReason: t.includeReason,
- }
- // increaseDepth and elideOnDepth are not copied to redirects, otherwise their depth would be double counted.
- t.subTasks = []*parseTask{t.redirectedParseTask}
-}
-
-func (t *parseTask) loadAutomaticTypeDirectives(loader *fileLoader) {
- toParseTypeRefs, typeResolutionsInFile, typeResolutionsTrace := loader.resolveAutomaticTypeDirectives(t.normalizedFilePath)
- t.typeResolutionsInFile = typeResolutionsInFile
- t.typeResolutionsTrace = typeResolutionsTrace
- for _, typeResolution := range toParseTypeRefs {
- t.addSubTask(typeResolution, nil)
- }
-}
-
-type resolvedRef struct {
- fileName string
- increaseDepth bool
- elideOnDepth bool
- isFromExternalLibrary bool
- includeReason *fileIncludeReason
-}
-
-func (t *parseTask) addSubTask(ref resolvedRef, libFile *LibFile) {
- normalizedFilePath := tspath.NormalizePath(ref.fileName)
- subTask := &parseTask{
- normalizedFilePath: normalizedFilePath,
- libFile: libFile,
- increaseDepth: ref.increaseDepth,
- elideOnDepth: ref.elideOnDepth,
- fromExternalLibrary: ref.isFromExternalLibrary,
- includeReason: ref.includeReason,
- }
- t.subTasks = append(t.subTasks, subTask)
-}
-
-type filesParser struct {
- wg core.WorkGroup
- tasksByFileName collections.SyncMap[string, *queuedParseTask]
- maxDepth int
-}
-
-type queuedParseTask struct {
- task *parseTask
- mu sync.Mutex
- lowestDepth int
- fromExternalLibrary bool
-}
-
-func (w *filesParser) parse(loader *fileLoader, tasks []*parseTask) {
- w.start(loader, tasks, 0, false)
- w.wg.RunAndWait()
-}
-
-func (w *filesParser) start(loader *fileLoader, tasks []*parseTask, depth int, isFromExternalLibrary bool) {
- for i, task := range tasks {
- taskIsFromExternalLibrary := isFromExternalLibrary || task.fromExternalLibrary
- newTask := &queuedParseTask{task: task, lowestDepth: math.MaxInt}
- loadedTask, loaded := w.tasksByFileName.LoadOrStore(task.FileName(), newTask)
- task = loadedTask.task
- if loaded {
- tasks[i].loadedTask = task
- // Add in the loaded task's external-ness.
- taskIsFromExternalLibrary = taskIsFromExternalLibrary || task.fromExternalLibrary
- }
-
- w.wg.Queue(func() {
- loadedTask.mu.Lock()
- defer loadedTask.mu.Unlock()
-
- startSubtasks := false
-
- currentDepth := depth
- if task.increaseDepth {
- currentDepth++
- }
- if currentDepth < loadedTask.lowestDepth {
- // If we're seeing this task at a lower depth than before,
- // reprocess its subtasks to ensure they are loaded.
- loadedTask.lowestDepth = currentDepth
- startSubtasks = true
- }
-
- if !task.isRoot() && taskIsFromExternalLibrary && !loadedTask.fromExternalLibrary {
- // If we're seeing this task now as an external library,
- // reprocess its subtasks to ensure they are also marked as external.
- loadedTask.fromExternalLibrary = true
- startSubtasks = true
- }
-
- if task.elideOnDepth && currentDepth > w.maxDepth {
- return
- }
-
- if !task.loaded {
- task.load(loader)
- }
-
- if startSubtasks {
- w.start(loader, task.subTasks, loadedTask.lowestDepth, loadedTask.fromExternalLibrary)
- }
- })
- }
-}
-
-func (w *filesParser) collect(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask)) {
- // Mark all tasks we saw as external after the fact.
- w.tasksByFileName.Range(func(key string, value *queuedParseTask) bool {
- if value.fromExternalLibrary {
- value.task.fromExternalLibrary = true
- }
- return true
- })
- w.collectWorker(loader, tasks, iterate, collections.Set[*parseTask]{})
-}
-
-func (w *filesParser) collectWorker(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask), seen collections.Set[*parseTask]) {
- for _, task := range tasks {
- // Exclude automatic type directive tasks from include reason processing,
- // as these are internal implementation details and should not contribute
- // to the reasons for including files.
- if task.redirectedParseTask == nil && !task.isForAutomaticTypeDirective {
- includeReason := task.includeReason
- if task.loadedTask != nil {
- task = task.loadedTask
- }
- w.addIncludeReason(loader, task, includeReason)
- }
- // ensure we only walk each task once
- if !task.loaded || !seen.AddIfAbsent(task) {
- continue
- }
- for _, trace := range task.typeResolutionsTrace {
- loader.opts.Host.Trace(trace)
- }
- for _, trace := range task.resolutionsTrace {
- loader.opts.Host.Trace(trace)
- }
- if subTasks := task.subTasks; len(subTasks) > 0 {
- w.collectWorker(loader, subTasks, iterate, seen)
- }
- iterate(task)
- }
-}
-
-func (w *filesParser) addIncludeReason(loader *fileLoader, task *parseTask, reason *fileIncludeReason) {
- if task.redirectedParseTask != nil {
- w.addIncludeReason(loader, task.redirectedParseTask, reason)
- } else if task.loaded {
- if existing, ok := loader.includeProcessor.fileIncludeReasons[task.path]; ok {
- loader.includeProcessor.fileIncludeReasons[task.path] = append(existing, reason)
- } else {
- loader.includeProcessor.fileIncludeReasons[task.path] = []*fileIncludeReason{reason}
- }
- }
-}
diff --git a/kitcom/internal/tsgo/compiler/host.go b/kitcom/internal/tsgo/compiler/host.go
deleted file mode 100644
index d32df1f..0000000
--- a/kitcom/internal/tsgo/compiler/host.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package compiler
-
-import (
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/parser"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/cachedvfs"
-)
-
-type CompilerHost interface {
- FS() vfs.FS
- DefaultLibraryPath() string
- GetCurrentDirectory() string
- Trace(msg string)
- GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile
- GetResolvedProjectReference(fileName string, path tspath.Path) *tsoptions.ParsedCommandLine
-}
-
-var _ CompilerHost = (*compilerHost)(nil)
-
-type compilerHost struct {
- currentDirectory string
- fs vfs.FS
- defaultLibraryPath string
- extendedConfigCache tsoptions.ExtendedConfigCache
- trace func(msg string)
-}
-
-func NewCachedFSCompilerHost(
- currentDirectory string,
- fs vfs.FS,
- defaultLibraryPath string,
- extendedConfigCache tsoptions.ExtendedConfigCache,
- trace func(msg string),
-) CompilerHost {
- return NewCompilerHost(currentDirectory, cachedvfs.From(fs), defaultLibraryPath, extendedConfigCache, trace)
-}
-
-func NewCompilerHost(
- currentDirectory string,
- fs vfs.FS,
- defaultLibraryPath string,
- extendedConfigCache tsoptions.ExtendedConfigCache,
- trace func(msg string),
-) CompilerHost {
- if trace == nil {
- trace = func(msg string) {}
- }
- return &compilerHost{
- currentDirectory: currentDirectory,
- fs: fs,
- defaultLibraryPath: defaultLibraryPath,
- extendedConfigCache: extendedConfigCache,
- trace: trace,
- }
-}
-
-func (h *compilerHost) FS() vfs.FS {
- return h.fs
-}
-
-func (h *compilerHost) DefaultLibraryPath() string {
- return h.defaultLibraryPath
-}
-
-func (h *compilerHost) GetCurrentDirectory() string {
- return h.currentDirectory
-}
-
-func (h *compilerHost) Trace(msg string) {
- h.trace(msg)
-}
-
-func (h *compilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile {
- text, ok := h.FS().ReadFile(opts.FileName)
- if !ok {
- return nil
- }
- return parser.ParseSourceFile(opts, text, core.GetScriptKindFromFileName(opts.FileName))
-}
-
-func (h *compilerHost) GetResolvedProjectReference(fileName string, path tspath.Path) *tsoptions.ParsedCommandLine {
- commandLine, _ := tsoptions.GetParsedCommandLineOfConfigFilePath(fileName, path, nil, h, h.extendedConfigCache)
- return commandLine
-}
diff --git a/kitcom/internal/tsgo/compiler/includeprocessor.go b/kitcom/internal/tsgo/compiler/includeprocessor.go
deleted file mode 100644
index 6367108..0000000
--- a/kitcom/internal/tsgo/compiler/includeprocessor.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package compiler
-
-import (
- "sync"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type includeProcessor struct {
- fileIncludeReasons map[tspath.Path][]*fileIncludeReason
- processingDiagnostics []*processingDiagnostic
-
- reasonToReferenceLocation collections.SyncMap[*fileIncludeReason, *referenceFileLocation]
- includeReasonToRelatedInfo collections.SyncMap[*fileIncludeReason, *ast.Diagnostic]
- redirectAndFileFormat collections.SyncMap[tspath.Path, []*ast.Diagnostic]
- computedDiagnostics *ast.DiagnosticsCollection
- computedDiagnosticsOnce sync.Once
- compilerOptionsSyntax *ast.ObjectLiteralExpression
- compilerOptionsSyntaxOnce sync.Once
-}
-
-func updateFileIncludeProcessor(p *Program) {
- p.includeProcessor = &includeProcessor{
- fileIncludeReasons: p.includeProcessor.fileIncludeReasons,
- processingDiagnostics: p.includeProcessor.processingDiagnostics,
- }
-}
-
-func (i *includeProcessor) getDiagnostics(p *Program) *ast.DiagnosticsCollection {
- i.computedDiagnosticsOnce.Do(func() {
- i.computedDiagnostics = &ast.DiagnosticsCollection{}
- for _, d := range i.processingDiagnostics {
- i.computedDiagnostics.Add(d.toDiagnostic(p))
- }
- for _, resolutions := range p.resolvedModules {
- for _, resolvedModule := range resolutions {
- for _, diag := range resolvedModule.ResolutionDiagnostics {
- i.computedDiagnostics.Add(diag)
- }
- }
- }
- for _, typeResolutions := range p.typeResolutionsInFile {
- for _, resolvedTypeRef := range typeResolutions {
- for _, diag := range resolvedTypeRef.ResolutionDiagnostics {
- i.computedDiagnostics.Add(diag)
- }
- }
- }
- })
- return i.computedDiagnostics
-}
-
-func (i *includeProcessor) addProcessingDiagnostic(d ...*processingDiagnostic) {
- i.processingDiagnostics = append(i.processingDiagnostics, d...)
-}
-
-func (i *includeProcessor) getReferenceLocation(r *fileIncludeReason, program *Program) *referenceFileLocation {
- if existing, ok := i.reasonToReferenceLocation.Load(r); ok {
- return existing
- }
-
- loc, _ := i.reasonToReferenceLocation.LoadOrStore(r, r.getReferencedLocation(program))
- return loc
-}
-
-func (i *includeProcessor) getCompilerOptionsObjectLiteralSyntax(program *Program) *ast.ObjectLiteralExpression {
- i.compilerOptionsSyntaxOnce.Do(func() {
- configFile := program.opts.Config.ConfigFile
- if configFile != nil {
- if compilerOptionsProperty := tsoptions.ForEachTsConfigPropArray(configFile.SourceFile, "compilerOptions", core.Identity); compilerOptionsProperty != nil &&
- compilerOptionsProperty.Initializer != nil &&
- ast.IsObjectLiteralExpression(compilerOptionsProperty.Initializer) {
- i.compilerOptionsSyntax = compilerOptionsProperty.Initializer.AsObjectLiteralExpression()
- }
- } else {
- i.compilerOptionsSyntax = nil
- }
- })
- return i.compilerOptionsSyntax
-}
-
-func (i *includeProcessor) getRelatedInfo(r *fileIncludeReason, program *Program) *ast.Diagnostic {
- if existing, ok := i.includeReasonToRelatedInfo.Load(r); ok {
- return existing
- }
-
- relatedInfo, _ := i.includeReasonToRelatedInfo.LoadOrStore(r, r.toRelatedInfo(program))
- return relatedInfo
-}
-
-func (i *includeProcessor) explainRedirectAndImpliedFormat(
- program *Program,
- file *ast.SourceFile,
- toFileName func(fileName string) string,
-) []*ast.Diagnostic {
- if existing, ok := i.redirectAndFileFormat.Load(file.Path()); ok {
- return existing
- }
- var result []*ast.Diagnostic
- if source := program.GetSourceOfProjectReferenceIfOutputIncluded(file); source != file.FileName() {
- result = append(result, ast.NewCompilerDiagnostic(
- diagnostics.File_is_output_of_project_reference_source_0,
- toFileName(source),
- ))
- }
- // !!! redirects
- // if (file.redirectInfo) {
- // (result ??= []).push(chainDiagnosticMessages(
- // /*details*/ undefined,
- // Diagnostics.File_redirects_to_file_0,
- // toFileName(file.redirectInfo.redirectTarget, fileNameConvertor),
- // ));
- // }
- if ast.IsExternalOrCommonJSModule(file) {
- metaData := program.GetSourceFileMetaData(file.Path())
- switch program.GetImpliedNodeFormatForEmit(file) {
- case core.ModuleKindESNext:
- if metaData.PackageJsonType == "module" {
- result = append(result, ast.NewCompilerDiagnostic(
- diagnostics.File_is_ECMAScript_module_because_0_has_field_type_with_value_module,
- toFileName(metaData.PackageJsonDirectory+"/package.json"),
- ))
- }
- case core.ModuleKindCommonJS:
- if metaData.PackageJsonType != "" {
- result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module, toFileName(metaData.PackageJsonDirectory+"/package.json")))
- } else if metaData.PackageJsonDirectory != "" {
- if metaData.PackageJsonType == "" {
- result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, toFileName(metaData.PackageJsonDirectory+"/package.json")))
- }
- } else {
- result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_package_json_was_not_found))
- }
- }
- }
-
- result, _ = i.redirectAndFileFormat.LoadOrStore(file.Path(), result)
- return result
-}
diff --git a/kitcom/internal/tsgo/compiler/knownsymlinks.go b/kitcom/internal/tsgo/compiler/knownsymlinks.go
deleted file mode 100644
index 9960a80..0000000
--- a/kitcom/internal/tsgo/compiler/knownsymlinks.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package compiler
-
-import (
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type knownDirectoryLink struct {
- /**
- * Matches the casing returned by `realpath`. Used to compute the `realpath` of children.
- * Always has trailing directory separator
- */
- Real string
- /**
- * toPath(real). Stored to avoid repeated recomputation.
- * Always has trailing directory separator
- */
- RealPath tspath.Path
-}
-
-type knownSymlinks struct {
- directories collections.SyncMap[tspath.Path, *knownDirectoryLink]
- files collections.SyncMap[tspath.Path, string]
-}
-
-/** Gets a map from symlink to realpath. Keys have trailing directory separators. */
-func (cache *knownSymlinks) Directories() *collections.SyncMap[tspath.Path, *knownDirectoryLink] {
- return &cache.directories
-}
-
-/** Gets a map from symlink to realpath */
-func (cache *knownSymlinks) Files() *collections.SyncMap[tspath.Path, string] {
- return &cache.files
-}
-
-// all callers should check !containsIgnoredPath(symlinkPath)
-func (cache *knownSymlinks) SetDirectory(symlink string, symlinkPath tspath.Path, realDirectory *knownDirectoryLink) {
- // Large, interconnected dependency graphs in pnpm will have a huge number of symlinks
- // where both the realpath and the symlink path are inside node_modules/.pnpm. Since
- // this path is never a candidate for a module specifier, we can ignore it entirely.
-
- // !!!
- // if realDirectory != nil {
- // if _, ok := cache.directories.Load(symlinkPath); !ok {
- // cache.directoriesByRealpath.Add(realDirectory.RealPath, symlink)
- // }
- // }
- cache.directories.Store(symlinkPath, realDirectory)
-}
-
-func (cache *knownSymlinks) SetFile(symlinkPath tspath.Path, realpath string) {
- cache.files.Store(symlinkPath, realpath)
-}
diff --git a/kitcom/internal/tsgo/compiler/pkg.go b/kitcom/internal/tsgo/compiler/pkg.go
deleted file mode 100644
index aa86763..0000000
--- a/kitcom/internal/tsgo/compiler/pkg.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package compiler implements the TypeScript compiler.
-package compiler
diff --git a/kitcom/internal/tsgo/compiler/processingDiagnostic.go b/kitcom/internal/tsgo/compiler/processingDiagnostic.go
deleted file mode 100644
index 325ddcd..0000000
--- a/kitcom/internal/tsgo/compiler/processingDiagnostic.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package compiler
-
-import (
- "strings"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type processingDiagnosticKind int
-
-const (
- processingDiagnosticKindUnknownReference processingDiagnosticKind = iota
- processingDiagnosticKindExplainingFileInclude
-)
-
-type processingDiagnostic struct {
- kind processingDiagnosticKind
- data any
-}
-
-func (d *processingDiagnostic) asFileIncludeReason() *fileIncludeReason {
- return d.data.(*fileIncludeReason)
-}
-
-type includeExplainingDiagnostic struct {
- file tspath.Path
- diagnosticReason *fileIncludeReason
- message *diagnostics.Message
- args []any
-}
-
-func (d *processingDiagnostic) asIncludeExplainingDiagnostic() *includeExplainingDiagnostic {
- return d.data.(*includeExplainingDiagnostic)
-}
-
-func (d *processingDiagnostic) toDiagnostic(program *Program) *ast.Diagnostic {
- switch d.kind {
- case processingDiagnosticKindUnknownReference:
- ref := d.asFileIncludeReason()
- loc := ref.getReferencedLocation(program)
- switch ref.kind {
- case fileIncludeKindTypeReferenceDirective:
- return loc.diagnosticAt(diagnostics.Cannot_find_type_definition_file_for_0, loc.ref.FileName)
- case fileIncludeKindLibReferenceDirective:
- libName := tspath.ToFileNameLowerCase(loc.ref.FileName)
- unqualifiedLibName := strings.TrimSuffix(strings.TrimPrefix(libName, "lib."), ".d.ts")
- suggestion := core.GetSpellingSuggestion(unqualifiedLibName, tsoptions.Libs, core.Identity)
- return loc.diagnosticAt(core.IfElse(
- suggestion != "",
- diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1,
- diagnostics.Cannot_find_lib_definition_for_0,
- ), libName, suggestion)
- default:
- panic("unknown include kind")
- }
- case processingDiagnosticKindExplainingFileInclude:
- return d.createDiagnosticExplainingFile(program)
- default:
- panic("unknown processingDiagnosticKind")
- }
-}
-
-func (d *processingDiagnostic) createDiagnosticExplainingFile(program *Program) *ast.Diagnostic {
- diag := d.asIncludeExplainingDiagnostic()
- var includeDetails []*ast.Diagnostic
- var relatedInfo []*ast.Diagnostic
- var redirectInfo []*ast.Diagnostic
- var preferredLocation *fileIncludeReason
- var seenReasons collections.Set[*fileIncludeReason]
- if diag.diagnosticReason.isReferencedFile() && !program.includeProcessor.getReferenceLocation(diag.diagnosticReason, program).isSynthetic {
- preferredLocation = diag.diagnosticReason
- }
-
- processRelatedInfo := func(includeReason *fileIncludeReason) {
- if preferredLocation == nil && includeReason.isReferencedFile() && !program.includeProcessor.getReferenceLocation(includeReason, program).isSynthetic {
- preferredLocation = includeReason
- } else {
- info := program.includeProcessor.getRelatedInfo(includeReason, program)
- if info != nil {
- relatedInfo = append(relatedInfo, info)
- }
- }
- }
- processInclude := func(includeReason *fileIncludeReason) {
- if !seenReasons.AddIfAbsent(includeReason) {
- return
- }
- includeDetails = append(includeDetails, includeReason.toDiagnostic(program, false))
- processRelatedInfo(includeReason)
- }
-
- // !!! todo sheetal caching
-
- if diag.file != "" {
- reasons := program.includeProcessor.fileIncludeReasons[diag.file]
- includeDetails = make([]*ast.Diagnostic, 0, len(reasons))
- for _, reason := range reasons {
- processInclude(reason)
- }
- redirectInfo = program.includeProcessor.explainRedirectAndImpliedFormat(program, program.GetSourceFileByPath(diag.file), func(fileName string) string { return fileName })
- }
- if diag.diagnosticReason != nil {
- processInclude(diag.diagnosticReason)
- }
- var chain []*ast.Diagnostic
- if includeDetails != nil && (preferredLocation == nil || seenReasons.Len() != 1) {
- fileReason := ast.NewCompilerDiagnostic(diagnostics.The_file_is_in_the_program_because_Colon)
- fileReason.SetMessageChain(includeDetails)
- chain = []*ast.Diagnostic{fileReason}
- }
- if redirectInfo != nil {
- chain = append(chain, redirectInfo...)
- }
-
- var result *ast.Diagnostic
- if preferredLocation != nil {
- result = program.includeProcessor.getReferenceLocation(preferredLocation, program).diagnosticAt(diag.message, diag.args...)
- }
- if result == nil {
- result = ast.NewCompilerDiagnostic(diag.message, diag.args...)
- }
- if chain != nil {
- result.SetMessageChain(chain)
- }
- if relatedInfo != nil {
- result.SetRelatedInfo(relatedInfo)
- }
- return result
-}
diff --git a/kitcom/internal/tsgo/compiler/program.go b/kitcom/internal/tsgo/compiler/program.go
deleted file mode 100644
index 06bf28d..0000000
--- a/kitcom/internal/tsgo/compiler/program.go
+++ /dev/null
@@ -1,1722 +0,0 @@
-package compiler
-
-import (
- "context"
- "fmt"
- "io"
- "maps"
- "slices"
- "strings"
- "sync"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/checker"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/outputpaths"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/parser"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/sourcemap"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
- "github.com/go-json-experiment/json"
-)
-
-type ProgramOptions struct {
- Host CompilerHost
- Config *tsoptions.ParsedCommandLine
- UseSourceOfProjectReference bool
- SingleThreaded core.Tristate
- CreateCheckerPool func(*Program) CheckerPool
- TypingsLocation string
- ProjectName string
- JSDocParsingMode ast.JSDocParsingMode
-}
-
-func (p *ProgramOptions) canUseProjectReferenceSource() bool {
- return p.UseSourceOfProjectReference && !p.Config.CompilerOptions().DisableSourceOfProjectReferenceRedirect.IsTrue()
-}
-
-type Program struct {
- opts ProgramOptions
- checkerPool CheckerPool
-
- comparePathsOptions tspath.ComparePathsOptions
-
- processedFiles
-
- usesUriStyleNodeCoreModules core.Tristate
-
- commonSourceDirectory string
- commonSourceDirectoryOnce sync.Once
-
- declarationDiagnosticCache collections.SyncMap[*ast.SourceFile, []*ast.Diagnostic]
-
- programDiagnostics []*ast.Diagnostic
- hasEmitBlockingDiagnostics collections.Set[tspath.Path]
-
- sourceFilesToEmitOnce sync.Once
- sourceFilesToEmit []*ast.SourceFile
-
- // Cached unresolved imports for ATA
- unresolvedImportsOnce sync.Once
- unresolvedImports *collections.Set[string]
-}
-
-// FileExists implements checker.Program.
-func (p *Program) FileExists(path string) bool {
- return p.Host().FS().FileExists(path)
-}
-
-// GetCurrentDirectory implements checker.Program.
-func (p *Program) GetCurrentDirectory() string {
- return p.Host().GetCurrentDirectory()
-}
-
-// GetGlobalTypingsCacheLocation implements checker.Program.
-func (p *Program) GetGlobalTypingsCacheLocation() string {
- return "" // !!! see src/tsserver/nodeServer.ts for strada's node-specific implementation
-}
-
-// GetNearestAncestorDirectoryWithPackageJson implements checker.Program.
-func (p *Program) GetNearestAncestorDirectoryWithPackageJson(dirname string) string {
- scoped := p.resolver.GetPackageScopeForPath(dirname)
- if scoped != nil && scoped.Exists() {
- return scoped.PackageDirectory
- }
- return ""
-}
-
-// GetPackageJsonInfo implements checker.Program.
-func (p *Program) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.PackageJsonInfo {
- scoped := p.resolver.GetPackageScopeForPath(pkgJsonPath)
- if scoped != nil && scoped.Exists() && scoped.PackageDirectory == tspath.GetDirectoryPath(pkgJsonPath) {
- return scoped
- }
- return nil
-}
-
-// GetRedirectTargets implements checker.Program.
-func (p *Program) GetRedirectTargets(path tspath.Path) []string {
- return nil // !!! TODO: project references support
-}
-
-// gets the original file that was included in program
-// this returns original source file name when including output of project reference
-// otherwise same name
-// Equivalent to originalFileName on SourceFile in Strada
-func (p *Program) GetSourceOfProjectReferenceIfOutputIncluded(file ast.HasFileName) string {
- if source, ok := p.outputFileToProjectReferenceSource[file.Path()]; ok {
- return source
- }
- return file.FileName()
-}
-
-// GetProjectReferenceFromSource implements checker.Program.
-func (p *Program) GetProjectReferenceFromSource(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
- return p.projectReferenceFileMapper.getProjectReferenceFromSource(path)
-}
-
-// IsSourceFromProjectReference implements checker.Program.
-func (p *Program) IsSourceFromProjectReference(path tspath.Path) bool {
- return p.projectReferenceFileMapper.isSourceFromProjectReference(path)
-}
-
-func (p *Program) GetProjectReferenceFromOutputDts(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
- return p.projectReferenceFileMapper.getProjectReferenceFromOutputDts(path)
-}
-
-func (p *Program) GetResolvedProjectReferenceFor(path tspath.Path) (*tsoptions.ParsedCommandLine, bool) {
- return p.projectReferenceFileMapper.getResolvedReferenceFor(path)
-}
-
-func (p *Program) GetRedirectForResolution(file ast.HasFileName) *tsoptions.ParsedCommandLine {
- redirect, _ := p.projectReferenceFileMapper.getRedirectForResolution(file)
- return redirect
-}
-
-func (p *Program) GetParseFileRedirect(fileName string) string {
- return p.projectReferenceFileMapper.getParseFileRedirect(ast.NewHasFileName(fileName, p.toPath(fileName)))
-}
-
-func (p *Program) ForEachResolvedProjectReference(
- fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
-) {
- p.projectReferenceFileMapper.forEachResolvedProjectReference(fn)
-}
-
-// UseCaseSensitiveFileNames implements checker.Program.
-func (p *Program) UseCaseSensitiveFileNames() bool {
- return p.Host().FS().UseCaseSensitiveFileNames()
-}
-
-func (p *Program) UsesUriStyleNodeCoreModules() bool {
- return p.usesUriStyleNodeCoreModules.IsTrue()
-}
-
-var _ checker.Program = (*Program)(nil)
-
-/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
-func (p *Program) GetSourceFileFromReference(origin *ast.SourceFile, ref *ast.FileReference) *ast.SourceFile {
- // TODO: The module loader in corsa is fairly different than strada, it should probably be able to expose this functionality at some point,
- // rather than redoing the logic approximately here, since most of the related logic now lives in module.Resolver
- // Still, without the failed lookup reporting that only the loader does, this isn't terribly complicated
-
- fileName := tspath.ResolvePath(tspath.GetDirectoryPath(origin.FileName()), ref.FileName)
- supportedExtensionsBase := tsoptions.GetSupportedExtensions(p.Options(), nil /*extraFileExtensions*/)
- supportedExtensions := tsoptions.GetSupportedExtensionsWithJsonIfResolveJsonModule(p.Options(), supportedExtensionsBase)
- allowNonTsExtensions := p.Options().AllowNonTsExtensions.IsTrue()
- if tspath.HasExtension(fileName) {
- if !allowNonTsExtensions {
- canonicalFileName := tspath.GetCanonicalFileName(fileName, p.UseCaseSensitiveFileNames())
- supported := false
- for _, group := range supportedExtensions {
- if tspath.FileExtensionIsOneOf(canonicalFileName, group) {
- supported = true
- break
- }
- }
- if !supported {
- return nil // unsupported extensions are forced to fail
- }
- }
-
- return p.GetSourceFile(fileName)
- }
- if allowNonTsExtensions {
- extensionless := p.GetSourceFile(fileName)
- if extensionless != nil {
- return extensionless
- }
- }
-
- // Only try adding extensions from the first supported group (which should be .ts/.tsx/.d.ts)
- for _, ext := range supportedExtensions[0] {
- result := p.GetSourceFile(fileName + ext)
- if result != nil {
- return result
- }
- }
- return nil
-}
-
-func NewProgram(opts ProgramOptions) *Program {
- p := &Program{opts: opts}
- p.initCheckerPool()
- p.processedFiles = processAllProgramFiles(p.opts, p.SingleThreaded())
- p.verifyCompilerOptions()
- return p
-}
-
-// Return an updated program for which it is known that only the file with the given path has changed.
-// In addition to a new program, return a boolean indicating whether the data of the old program was reused.
-func (p *Program) UpdateProgram(changedFilePath tspath.Path, newHost CompilerHost) (*Program, bool) {
- oldFile := p.filesByPath[changedFilePath]
- newOpts := p.opts
- newOpts.Host = newHost
- newFile := newHost.GetSourceFile(oldFile.ParseOptions())
- if !canReplaceFileInProgram(oldFile, newFile) {
- return NewProgram(newOpts), false
- }
- // TODO: reverify compiler options when config has changed?
- result := &Program{
- opts: newOpts,
- comparePathsOptions: p.comparePathsOptions,
- processedFiles: p.processedFiles,
- usesUriStyleNodeCoreModules: p.usesUriStyleNodeCoreModules,
- programDiagnostics: p.programDiagnostics,
- hasEmitBlockingDiagnostics: p.hasEmitBlockingDiagnostics,
- unresolvedImports: p.unresolvedImports,
- }
- result.initCheckerPool()
- index := core.FindIndex(result.files, func(file *ast.SourceFile) bool { return file.Path() == newFile.Path() })
- result.files = slices.Clone(result.files)
- result.files[index] = newFile
- result.filesByPath = maps.Clone(result.filesByPath)
- result.filesByPath[newFile.Path()] = newFile
- updateFileIncludeProcessor(result)
- return result, true
-}
-
-func (p *Program) initCheckerPool() {
- if p.opts.CreateCheckerPool != nil {
- p.checkerPool = p.opts.CreateCheckerPool(p)
- } else {
- p.checkerPool = newCheckerPool(core.IfElse(p.SingleThreaded(), 1, 4), p)
- }
-}
-
-func canReplaceFileInProgram(file1 *ast.SourceFile, file2 *ast.SourceFile) bool {
- return file2 != nil &&
- file1.ParseOptions() == file2.ParseOptions() &&
- file1.UsesUriStyleNodeCoreModules == file2.UsesUriStyleNodeCoreModules &&
- slices.EqualFunc(file1.Imports(), file2.Imports(), equalModuleSpecifiers) &&
- slices.EqualFunc(file1.ModuleAugmentations, file2.ModuleAugmentations, equalModuleAugmentationNames) &&
- slices.Equal(file1.AmbientModuleNames, file2.AmbientModuleNames) &&
- slices.EqualFunc(file1.ReferencedFiles, file2.ReferencedFiles, equalFileReferences) &&
- slices.EqualFunc(file1.TypeReferenceDirectives, file2.TypeReferenceDirectives, equalFileReferences) &&
- slices.EqualFunc(file1.LibReferenceDirectives, file2.LibReferenceDirectives, equalFileReferences) &&
- equalCheckJSDirectives(file1.CheckJsDirective, file2.CheckJsDirective)
-}
-
-func equalModuleSpecifiers(n1 *ast.Node, n2 *ast.Node) bool {
- return n1.Kind == n2.Kind && (!ast.IsStringLiteral(n1) || n1.Text() == n2.Text())
-}
-
-func equalModuleAugmentationNames(n1 *ast.Node, n2 *ast.Node) bool {
- return n1.Kind == n2.Kind && n1.Text() == n2.Text()
-}
-
-func equalFileReferences(f1 *ast.FileReference, f2 *ast.FileReference) bool {
- return f1.FileName == f2.FileName && f1.ResolutionMode == f2.ResolutionMode && f1.Preserve == f2.Preserve
-}
-
-func equalCheckJSDirectives(d1 *ast.CheckJsDirective, d2 *ast.CheckJsDirective) bool {
- return d1 == nil && d2 == nil || d1 != nil && d2 != nil && d1.Enabled == d2.Enabled
-}
-
-func (p *Program) SourceFiles() []*ast.SourceFile { return p.files }
-func (p *Program) Options() *core.CompilerOptions { return p.opts.Config.CompilerOptions() }
-func (p *Program) CommandLine() *tsoptions.ParsedCommandLine { return p.opts.Config }
-func (p *Program) Host() CompilerHost { return p.opts.Host }
-func (p *Program) GetConfigFileParsingDiagnostics() []*ast.Diagnostic {
- return slices.Clip(p.opts.Config.GetConfigFileParsingDiagnostics())
-}
-
-// GetUnresolvedImports returns the unresolved imports for this program.
-// The result is cached and computed only once.
-func (p *Program) GetUnresolvedImports() *collections.Set[string] {
- p.unresolvedImportsOnce.Do(func() {
- if p.unresolvedImports == nil {
- p.unresolvedImports = p.extractUnresolvedImports()
- }
- })
-
- return p.unresolvedImports
-}
-
-func (p *Program) extractUnresolvedImports() *collections.Set[string] {
- unresolvedSet := &collections.Set[string]{}
-
- for _, sourceFile := range p.files {
- unresolvedImports := p.extractUnresolvedImportsFromSourceFile(sourceFile)
- for _, imp := range unresolvedImports {
- unresolvedSet.Add(imp)
- }
- }
-
- return unresolvedSet
-}
-
-func (p *Program) extractUnresolvedImportsFromSourceFile(file *ast.SourceFile) []string {
- var unresolvedImports []string
-
- resolvedModules := p.resolvedModules[file.Path()]
- for cacheKey, resolution := range resolvedModules {
- resolved := resolution.IsResolved()
- if (!resolved || !tspath.ExtensionIsOneOf(resolution.Extension, tspath.SupportedTSExtensionsWithJsonFlat)) &&
- !tspath.IsExternalModuleNameRelative(cacheKey.Name) {
- unresolvedImports = append(unresolvedImports, cacheKey.Name)
- }
- }
-
- return unresolvedImports
-}
-
-func (p *Program) SingleThreaded() bool {
- return p.opts.SingleThreaded.DefaultIfUnknown(p.Options().SingleThreaded).IsTrue()
-}
-
-func (p *Program) BindSourceFiles() {
- wg := core.NewWorkGroup(p.SingleThreaded())
- for _, file := range p.files {
- if !file.IsBound() {
- wg.Queue(func() {
- binder.BindSourceFile(file)
- })
- }
- }
- wg.RunAndWait()
-}
-
-func (p *Program) CheckSourceFiles(ctx context.Context, files []*ast.SourceFile) {
- wg := core.NewWorkGroup(p.SingleThreaded())
- checkers, done := p.checkerPool.GetAllCheckers(ctx)
- defer done()
- for _, checker := range checkers {
- wg.Queue(func() {
- for file := range p.checkerPool.Files(checker) {
- if files == nil || slices.Contains(files, file) {
- checker.CheckSourceFile(ctx, file)
- }
- }
- })
- }
- wg.RunAndWait()
-}
-
-// Return the type checker associated with the program.
-func (p *Program) GetTypeChecker(ctx context.Context) (*checker.Checker, func()) {
- return p.checkerPool.GetChecker(ctx)
-}
-
-func (p *Program) GetTypeCheckers(ctx context.Context) ([]*checker.Checker, func()) {
- return p.checkerPool.GetAllCheckers(ctx)
-}
-
-// Return a checker for the given file. We may have multiple checkers in concurrent scenarios and this
-// method returns the checker that was tasked with checking the file. Note that it isn't possible to mix
-// types obtained from different checkers, so only non-type data (such as diagnostics or string
-// representations of types) should be obtained from checkers returned by this method.
-func (p *Program) GetTypeCheckerForFile(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func()) {
- return p.checkerPool.GetCheckerForFile(ctx, file)
-}
-
-func (p *Program) GetResolvedModule(file ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule {
- if resolutions, ok := p.resolvedModules[file.Path()]; ok {
- if resolved, ok := resolutions[module.ModeAwareCacheKey{Name: moduleReference, Mode: mode}]; ok {
- return resolved
- }
- }
- return nil
-}
-
-func (p *Program) GetResolvedModuleFromModuleSpecifier(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) *module.ResolvedModule {
- if !ast.IsStringLiteralLike(moduleSpecifier) {
- panic("moduleSpecifier must be a StringLiteralLike")
- }
- mode := p.GetModeForUsageLocation(file, moduleSpecifier)
- return p.GetResolvedModule(file, moduleSpecifier.Text(), mode)
-}
-
-func (p *Program) GetResolvedModules() map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] {
- return p.resolvedModules
-}
-
-func (p *Program) GetSyntacticDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return p.getDiagnosticsHelper(ctx, sourceFile, false /*ensureBound*/, false /*ensureChecked*/, p.getSyntacticDiagnosticsForFile)
-}
-
-func (p *Program) GetBindDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return p.getDiagnosticsHelper(ctx, sourceFile, true /*ensureBound*/, false /*ensureChecked*/, p.getBindDiagnosticsForFile)
-}
-
-func (p *Program) GetSemanticDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return p.getDiagnosticsHelper(ctx, sourceFile, true /*ensureBound*/, true /*ensureChecked*/, p.getSemanticDiagnosticsForFile)
-}
-
-func (p *Program) GetSemanticDiagnosticsNoFilter(ctx context.Context, sourceFiles []*ast.SourceFile) map[*ast.SourceFile][]*ast.Diagnostic {
- p.BindSourceFiles()
- p.CheckSourceFiles(ctx, sourceFiles)
- if ctx.Err() != nil {
- return nil
- }
- result := make(map[*ast.SourceFile][]*ast.Diagnostic, len(sourceFiles))
- for _, file := range sourceFiles {
- result[file] = SortAndDeduplicateDiagnostics(p.getSemanticDiagnosticsForFileNotFilter(ctx, file))
- }
- return result
-}
-
-func (p *Program) GetSuggestionDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return p.getDiagnosticsHelper(ctx, sourceFile, true /*ensureBound*/, true /*ensureChecked*/, p.getSuggestionDiagnosticsForFile)
-}
-
-func (p *Program) GetProgramDiagnostics() []*ast.Diagnostic {
- return SortAndDeduplicateDiagnostics(slices.Concat(
- p.programDiagnostics,
- p.includeProcessor.getDiagnostics(p).GetGlobalDiagnostics()))
-}
-
-func (p *Program) GetIncludeProcessorDiagnostics(sourceFile *ast.SourceFile) []*ast.Diagnostic {
- if checker.SkipTypeChecking(sourceFile, p.Options(), p, false) {
- return nil
- }
- filtered, _ := p.getDiagnosticsWithPrecedingDirectives(sourceFile, p.includeProcessor.getDiagnostics(p).GetDiagnosticsForFile(sourceFile.FileName()))
- return filtered
-}
-
-func (p *Program) getSourceFilesToEmit(targetSourceFile *ast.SourceFile, forceDtsEmit bool) []*ast.SourceFile {
- if targetSourceFile == nil && !forceDtsEmit {
- p.sourceFilesToEmitOnce.Do(func() {
- p.sourceFilesToEmit = getSourceFilesToEmit(p, nil, false)
- })
- return p.sourceFilesToEmit
- }
- return getSourceFilesToEmit(p, targetSourceFile, forceDtsEmit)
-}
-
-func (p *Program) verifyCompilerOptions() {
- options := p.Options()
-
- sourceFile := core.Memoize(func() *ast.SourceFile {
- configFile := p.opts.Config.ConfigFile
- if configFile == nil {
- return nil
- }
- return configFile.SourceFile
- })
-
- configFilePath := core.Memoize(func() string {
- file := sourceFile()
- if file != nil {
- return file.FileName()
- }
- return ""
- })
-
- getCompilerOptionsPropertySyntax := core.Memoize(func() *ast.PropertyAssignment {
- return tsoptions.ForEachTsConfigPropArray(sourceFile(), "compilerOptions", core.Identity)
- })
-
- getCompilerOptionsObjectLiteralSyntax := core.Memoize(func() *ast.ObjectLiteralExpression {
- compilerOptionsProperty := getCompilerOptionsPropertySyntax()
- if compilerOptionsProperty != nil &&
- compilerOptionsProperty.Initializer != nil &&
- ast.IsObjectLiteralExpression(compilerOptionsProperty.Initializer) {
- return compilerOptionsProperty.Initializer.AsObjectLiteralExpression()
- }
- return nil
- })
-
- createOptionDiagnosticInObjectLiteralSyntax := func(objectLiteral *ast.ObjectLiteralExpression, onKey bool, key1 string, key2 string, message *diagnostics.Message, args ...any) *ast.Diagnostic {
- diag := tsoptions.ForEachPropertyAssignment(objectLiteral, key1, func(property *ast.PropertyAssignment) *ast.Diagnostic {
- return tsoptions.CreateDiagnosticForNodeInSourceFile(sourceFile(), core.IfElse(onKey, property.Name(), property.Initializer), message, args...)
- }, key2)
- if diag != nil {
- p.programDiagnostics = append(p.programDiagnostics, diag)
- }
- return diag
- }
-
- createCompilerOptionsDiagnostic := func(message *diagnostics.Message, args ...any) *ast.Diagnostic {
- compilerOptionsProperty := getCompilerOptionsPropertySyntax()
- var diag *ast.Diagnostic
- if compilerOptionsProperty != nil {
- diag = tsoptions.CreateDiagnosticForNodeInSourceFile(sourceFile(), compilerOptionsProperty.Name(), message, args...)
- } else {
- diag = ast.NewCompilerDiagnostic(message, args...)
- }
- p.programDiagnostics = append(p.programDiagnostics, diag)
- return diag
- }
-
- createDiagnosticForOption := func(onKey bool, option1 string, option2 string, message *diagnostics.Message, args ...any) *ast.Diagnostic {
- diag := createOptionDiagnosticInObjectLiteralSyntax(getCompilerOptionsObjectLiteralSyntax(), onKey, option1, option2, message, args...)
- if diag == nil {
- diag = createCompilerOptionsDiagnostic(message, args...)
- }
- return diag
- }
-
- createDiagnosticForOptionName := func(message *diagnostics.Message, option1 string, option2 string, args ...any) {
- newArgs := make([]any, 0, len(args)+2)
- newArgs = append(newArgs, option1, option2)
- newArgs = append(newArgs, args...)
- createDiagnosticForOption(true /*onKey*/, option1, option2, message, newArgs...)
- }
-
- createOptionValueDiagnostic := func(option1 string, message *diagnostics.Message, args ...any) {
- createDiagnosticForOption(false /*onKey*/, option1, "", message, args...)
- }
-
- createRemovedOptionDiagnostic := func(name string, value string, useInstead string) {
- var message *diagnostics.Message
- var args []any
- if value == "" {
- message = diagnostics.Option_0_has_been_removed_Please_remove_it_from_your_configuration
- args = []any{name}
- } else {
- message = diagnostics.Option_0_1_has_been_removed_Please_remove_it_from_your_configuration
- args = []any{name, value}
- }
-
- diag := createDiagnosticForOption(value == "", name, "", message, args...)
- if useInstead != "" {
- diag.AddMessageChain(ast.NewCompilerDiagnostic(diagnostics.Use_0_instead, useInstead))
- }
- }
-
- // Removed in TS7
-
- if options.BaseUrl != "" {
- // BaseUrl will have been turned absolute by this point.
- var useInstead string
- if configFilePath() != "" {
- relative := tspath.GetRelativePathFromFile(configFilePath(), options.BaseUrl, p.comparePathsOptions)
- if !(strings.HasPrefix(relative, "./") || strings.HasPrefix(relative, "../")) {
- relative = "./" + relative
- }
- suggestion := tspath.CombinePaths(relative, "*")
- useInstead = fmt.Sprintf(`"paths": {"*": [%s]}`, core.Must(json.Marshal(suggestion)))
- }
- createRemovedOptionDiagnostic("baseUrl", "", useInstead)
- }
-
- if options.OutFile != "" {
- createRemovedOptionDiagnostic("outFile", "", "")
- }
-
- // if options.Target == core.ScriptTargetES3 {
- // createRemovedOptionDiagnostic("target", "ES3", "")
- // }
- // if options.Target == core.ScriptTargetES5 {
- // createRemovedOptionDiagnostic("target", "ES5", "")
- // }
-
- if options.Module == core.ModuleKindAMD {
- createRemovedOptionDiagnostic("module", "AMD", "")
- }
- if options.Module == core.ModuleKindSystem {
- createRemovedOptionDiagnostic("module", "System", "")
- }
- if options.Module == core.ModuleKindUMD {
- createRemovedOptionDiagnostic("module", "UMD", "")
- }
-
- if options.StrictPropertyInitialization.IsTrue() && !options.GetStrictOptionValue(options.StrictNullChecks) {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "strictPropertyInitialization", "strictNullChecks")
- }
- if options.ExactOptionalPropertyTypes.IsTrue() && !options.GetStrictOptionValue(options.StrictNullChecks) {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "exactOptionalPropertyTypes", "strictNullChecks")
- }
-
- if options.IsolatedDeclarations.IsTrue() {
- if options.GetAllowJS() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "isolatedDeclarations")
- }
- if !options.GetEmitDeclarations() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "isolatedDeclarations", "declaration", "composite")
- }
- }
-
- if options.InlineSourceMap.IsTrue() {
- if options.SourceMap.IsTrue() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap")
- }
- if options.MapRoot != "" {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap")
- }
- }
-
- if options.Composite.IsTrue() {
- if options.Declaration.IsFalse() {
- createDiagnosticForOptionName(diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration", "")
- }
- if options.Incremental.IsFalse() {
- createDiagnosticForOptionName(diagnostics.Composite_projects_may_not_disable_incremental_compilation, "declaration", "")
- }
- }
-
- p.verifyProjectReferences()
-
- if options.Composite.IsTrue() {
- var rootPaths collections.Set[tspath.Path]
- for _, fileName := range p.opts.Config.FileNames() {
- rootPaths.Add(p.toPath(fileName))
- }
-
- for _, file := range p.files {
- if sourceFileMayBeEmitted(file, p, false) && !rootPaths.Has(file.Path()) {
- p.includeProcessor.addProcessingDiagnostic(&processingDiagnostic{
- kind: processingDiagnosticKindExplainingFileInclude,
- data: &includeExplainingDiagnostic{
- file: file.Path(),
- message: diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
- args: []any{file.FileName(), configFilePath()},
- },
- })
- }
- }
- }
-
- forEachOptionPathsSyntax := func(callback func(*ast.PropertyAssignment) *ast.Diagnostic) *ast.Diagnostic {
- return tsoptions.ForEachPropertyAssignment(getCompilerOptionsObjectLiteralSyntax(), "paths", callback)
- }
-
- createDiagnosticForOptionPaths := func(onKey bool, key string, message *diagnostics.Message, args ...any) *ast.Diagnostic {
- diag := forEachOptionPathsSyntax(func(pathProp *ast.PropertyAssignment) *ast.Diagnostic {
- if ast.IsObjectLiteralExpression(pathProp.Initializer) {
- return createOptionDiagnosticInObjectLiteralSyntax(pathProp.Initializer.AsObjectLiteralExpression(), onKey, key, "", message, args...)
- }
- return nil
- })
- if diag == nil {
- diag = createCompilerOptionsDiagnostic(message, args...)
- }
- return diag
- }
-
- createDiagnosticForOptionPathKeyValue := func(key string, valueIndex int, message *diagnostics.Message, args ...any) *ast.Diagnostic {
- diag := forEachOptionPathsSyntax(func(pathProp *ast.PropertyAssignment) *ast.Diagnostic {
- if ast.IsObjectLiteralExpression(pathProp.Initializer) {
- return tsoptions.ForEachPropertyAssignment(pathProp.Initializer.AsObjectLiteralExpression(), key, func(keyProps *ast.PropertyAssignment) *ast.Diagnostic {
- initializer := keyProps.Initializer
- if ast.IsArrayLiteralExpression(initializer) {
- elements := initializer.AsArrayLiteralExpression().Elements
- if elements != nil && len(elements.Nodes) > valueIndex {
- diag := tsoptions.CreateDiagnosticForNodeInSourceFile(sourceFile(), elements.Nodes[valueIndex], message, args...)
- p.programDiagnostics = append(p.programDiagnostics, diag)
- return diag
- }
- }
- return nil
- })
- }
- return nil
- })
- if diag == nil {
- diag = createCompilerOptionsDiagnostic(message, args...)
- }
- return diag
- }
-
- for key, value := range options.Paths.Entries() {
- // !!! This code does not handle cases where where the path mappings have the wrong types,
- // as that information is mostly lost during the parsing process.
- if !hasZeroOrOneAsteriskCharacter(key) {
- createDiagnosticForOptionPaths(true /*onKey*/, key, diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key)
- }
- if value == nil {
- createDiagnosticForOptionPaths(false /*onKey*/, key, diagnostics.Substitutions_for_pattern_0_should_be_an_array, key)
- } else if len(value) == 0 {
- createDiagnosticForOptionPaths(false /*onKey*/, key, diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key)
- }
- for i, subst := range value {
- if !hasZeroOrOneAsteriskCharacter(subst) {
- createDiagnosticForOptionPathKeyValue(key, i, diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key)
- }
- if !tspath.PathIsRelative(subst) && !tspath.PathIsAbsolute(subst) {
- createDiagnosticForOptionPathKeyValue(key, i, diagnostics.Non_relative_paths_are_not_allowed_Did_you_forget_a_leading_Slash)
- }
- }
- }
-
- if options.SourceMap.IsFalseOrUnknown() && options.InlineSourceMap.IsFalseOrUnknown() {
- if options.InlineSources.IsTrue() {
- createDiagnosticForOptionName(diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources", "")
- }
- if options.SourceRoot != "" {
- createDiagnosticForOptionName(diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot", "")
- }
- }
-
- if options.MapRoot != "" && !(options.SourceMap.IsTrue() || options.DeclarationMap.IsTrue()) {
- // Error to specify --mapRoot without --sourcemap
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap")
- }
-
- if options.DeclarationDir != "" {
- if !options.GetEmitDeclarations() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite")
- }
- }
-
- if options.DeclarationMap.IsTrue() && !options.GetEmitDeclarations() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite")
- }
-
- if options.Lib != nil && options.NoLib.IsTrue() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib")
- }
-
- languageVersion := options.GetEmitScriptTarget()
-
- firstNonAmbientExternalModuleSourceFile := core.Find(p.files, func(f *ast.SourceFile) bool { return ast.IsExternalModule(f) && !f.IsDeclarationFile })
- if options.IsolatedModules.IsTrue() || options.VerbatimModuleSyntax.IsTrue() {
- if options.Module == core.ModuleKindNone && languageVersion < core.ScriptTargetES2015 && options.IsolatedModules.IsTrue() {
- // !!!
- // createDiagnosticForOptionName(diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target")
- }
-
- if options.PreserveConstEnums.IsFalse() {
- createDiagnosticForOptionName(diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_0_is_enabled, core.IfElse(options.VerbatimModuleSyntax.IsTrue(), "verbatimModuleSyntax", "isolatedModules"), "preserveConstEnums")
- }
- } else if firstNonAmbientExternalModuleSourceFile != nil && languageVersion < core.ScriptTargetES2015 && options.Module == core.ModuleKindNone {
- // !!!
- }
-
- if options.OutDir != "" ||
- options.RootDir != "" ||
- options.SourceRoot != "" ||
- options.MapRoot != "" ||
- (options.GetEmitDeclarations() && options.DeclarationDir != "") {
- // !!! sheetal checkSourceFilesBelongToPath - for root Dir and configFile - explaining why file is in the program
- dir := p.CommonSourceDirectory()
- if options.OutDir != "" && dir == "" && core.Some(p.files, func(f *ast.SourceFile) bool { return tspath.GetRootLength(f.FileName()) > 1 }) {
- createDiagnosticForOptionName(diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir", "")
- }
- }
-
- if options.CheckJs.IsTrue() && !options.GetAllowJS() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs")
- }
-
- if options.EmitDeclarationOnly.IsTrue() {
- if !options.GetEmitDeclarations() {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite")
- }
- }
-
- // !!! emitDecoratorMetadata
-
- if options.JsxFactory != "" {
- if options.ReactNamespace != "" {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory")
- }
- if options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", tsoptions.InverseJsxOptionMap.GetOrZero(options.Jsx))
- }
- if parser.ParseIsolatedEntityName(options.JsxFactory) == nil {
- createOptionValueDiagnostic("jsxFactory", diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.JsxFactory)
- }
- } else if options.ReactNamespace != "" && !scanner.IsIdentifierText(options.ReactNamespace, core.LanguageVariantStandard) {
- createOptionValueDiagnostic("reactNamespace", diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.ReactNamespace)
- }
-
- if options.JsxFragmentFactory != "" {
- if options.JsxFactory == "" {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory")
- }
- if options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", tsoptions.InverseJsxOptionMap.GetOrZero(options.Jsx))
- }
- if parser.ParseIsolatedEntityName(options.JsxFragmentFactory) == nil {
- createOptionValueDiagnostic("jsxFragmentFactory", diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.JsxFragmentFactory)
- }
- }
-
- if options.ReactNamespace != "" {
- if options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", tsoptions.InverseJsxOptionMap.GetOrZero(options.Jsx))
- }
- }
-
- if options.JsxImportSource != "" {
- if options.Jsx == core.JsxEmitReact {
- createDiagnosticForOptionName(diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", tsoptions.InverseJsxOptionMap.GetOrZero(options.Jsx))
- }
- }
-
- moduleKind := options.GetEmitModuleKind()
-
- if options.AllowImportingTsExtensions.IsTrue() && !(options.NoEmit.IsTrue() || options.EmitDeclarationOnly.IsTrue() || options.RewriteRelativeImportExtensions.IsTrue()) {
- createOptionValueDiagnostic("allowImportingTsExtensions", diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_either_noEmit_or_emitDeclarationOnly_is_set)
- }
-
- moduleResolution := options.GetModuleResolutionKind()
- if options.ResolvePackageJsonExports.IsTrue() && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution) {
- createDiagnosticForOptionName(diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "resolvePackageJsonExports", "")
- }
- if options.ResolvePackageJsonImports.IsTrue() && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution) {
- createDiagnosticForOptionName(diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "resolvePackageJsonImports", "")
- }
- if options.CustomConditions != nil && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution) {
- createDiagnosticForOptionName(diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "customConditions", "")
- }
-
- // !!! Reenable once we don't map old moduleResolution kinds to bundler.
- // if moduleResolution == core.ModuleResolutionKindBundler && !emitModuleKindIsNonNodeESM(moduleKind) && moduleKind != core.ModuleKindPreserve {
- // createOptionValueDiagnostic("moduleResolution", diagnostics.Option_0_can_only_be_used_when_module_is_set_to_preserve_or_to_es2015_or_later, "bundler")
- // }
-
- if core.ModuleKindNode16 <= moduleKind && moduleKind <= core.ModuleKindNodeNext &&
- !(core.ModuleResolutionKindNode16 <= moduleResolution && moduleResolution <= core.ModuleResolutionKindNodeNext) {
- moduleKindName := moduleKind.String()
- var moduleResolutionName string
- if v, ok := core.ModuleKindToModuleResolutionKind[moduleKind]; ok {
- moduleResolutionName = v.String()
- } else {
- moduleResolutionName = "Node16"
- }
- createOptionValueDiagnostic("moduleResolution", diagnostics.Option_moduleResolution_must_be_set_to_0_or_left_unspecified_when_option_module_is_set_to_1, moduleResolutionName, moduleKindName)
- } else if core.ModuleResolutionKindNode16 <= moduleResolution && moduleResolution <= core.ModuleResolutionKindNodeNext &&
- !(core.ModuleKindNode16 <= moduleKind && moduleKind <= core.ModuleKindNodeNext) {
- moduleResolutionName := moduleResolution.String()
- createOptionValueDiagnostic("module", diagnostics.Option_module_must_be_set_to_0_when_option_moduleResolution_is_set_to_1, moduleResolutionName, moduleResolutionName)
- }
-
- // !!! The below needs filesByName, which is not equivalent to p.filesByPath.
-
- // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
- if !options.NoEmit.IsTrue() && !options.SuppressOutputPathCheck.IsTrue() {
- var emitFilesSeen collections.Set[string]
-
- // Verify that all the emit files are unique and don't overwrite input files
- verifyEmitFilePath := func(emitFileName string) {
- if emitFileName != "" {
- emitFilePath := p.toPath(emitFileName)
- // Report error if the output overwrites input file
- if _, ok := p.filesByPath[emitFilePath]; ok {
- diag := ast.NewCompilerDiagnostic(diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName)
- if configFilePath() == "" {
- // The program is from either an inferred project or an external project
- diag.AddMessageChain(ast.NewCompilerDiagnostic(diagnostics.Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig))
- }
- p.blockEmittingOfFile(emitFileName, diag)
- }
-
- var emitFileKey string
- if !p.Host().FS().UseCaseSensitiveFileNames() {
- emitFileKey = tspath.ToFileNameLowerCase(string(emitFilePath))
- } else {
- emitFileKey = string(emitFilePath)
- }
-
- // Report error if multiple files write into same file
- if emitFilesSeen.Has(emitFileKey) {
- // Already seen the same emit file - report error
- p.blockEmittingOfFile(emitFileName, ast.NewCompilerDiagnostic(diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName))
- } else {
- emitFilesSeen.Add(emitFileKey)
- }
- }
- }
-
- outputpaths.ForEachEmittedFile(p, options, func(emitFileNames *outputpaths.OutputPaths, sourceFile *ast.SourceFile) bool {
- verifyEmitFilePath(emitFileNames.JsFilePath())
- verifyEmitFilePath(emitFileNames.SourceMapFilePath())
- verifyEmitFilePath(emitFileNames.DeclarationFilePath())
- verifyEmitFilePath(emitFileNames.DeclarationMapPath())
- return false
- }, p.getSourceFilesToEmit(nil, false), false)
- verifyEmitFilePath(p.opts.Config.GetBuildInfoFileName())
- }
-}
-
-func (p *Program) blockEmittingOfFile(emitFileName string, diag *ast.Diagnostic) {
- p.hasEmitBlockingDiagnostics.Add(p.toPath(emitFileName))
- p.programDiagnostics = append(p.programDiagnostics, diag)
-}
-
-func (p *Program) IsEmitBlocked(emitFileName string) bool {
- return p.hasEmitBlockingDiagnostics.Has(p.toPath(emitFileName))
-}
-
-func (p *Program) verifyProjectReferences() {
- buildInfoFileName := core.IfElse(!p.Options().SuppressOutputPathCheck.IsTrue(), p.opts.Config.GetBuildInfoFileName(), "")
- createDiagnosticForReference := func(config *tsoptions.ParsedCommandLine, index int, message *diagnostics.Message, args ...any) {
- diag := tsoptions.CreateDiagnosticAtReferenceSyntax(config, index, message, args...)
- if diag == nil {
- diag = ast.NewCompilerDiagnostic(message, args...)
- }
- p.programDiagnostics = append(p.programDiagnostics, diag)
- }
-
- p.ForEachResolvedProjectReference(func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
- ref := parent.ProjectReferences()[index]
- // !!! Deprecated in 5.0 and removed since 5.5
- // verifyRemovedProjectReference(ref, parent, index);
- if config == nil {
- createDiagnosticForReference(parent, index, diagnostics.File_0_not_found, ref.Path)
- return
- }
- refOptions := config.CompilerOptions()
- if !refOptions.Composite.IsTrue() || refOptions.NoEmit.IsTrue() {
- if len(parent.FileNames()) > 0 {
- if !refOptions.Composite.IsTrue() {
- createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.Path)
- }
- if refOptions.NoEmit.IsTrue() {
- createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_may_not_disable_emit, ref.Path)
- }
- }
- }
- if buildInfoFileName != "" && buildInfoFileName == config.GetBuildInfoFileName() {
- createDiagnosticForReference(parent, index, diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoFileName, ref.Path)
- p.hasEmitBlockingDiagnostics.Add(p.toPath(buildInfoFileName))
- }
- })
-}
-
-func hasZeroOrOneAsteriskCharacter(str string) bool {
- seenAsterisk := false
- for _, ch := range str {
- if ch == '*' {
- if !seenAsterisk {
- seenAsterisk = true
- } else {
- // have already seen asterisk
- return false
- }
- }
- }
- return true
-}
-
-func moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution core.ModuleResolutionKind) bool {
- return moduleResolution >= core.ModuleResolutionKindNode16 && moduleResolution <= core.ModuleResolutionKindNodeNext ||
- moduleResolution == core.ModuleResolutionKindBundler
-}
-
-func emitModuleKindIsNonNodeESM(moduleKind core.ModuleKind) bool {
- return moduleKind >= core.ModuleKindES2015 && moduleKind <= core.ModuleKindESNext
-}
-
-func (p *Program) GetGlobalDiagnostics(ctx context.Context) []*ast.Diagnostic {
- if len(p.files) == 0 {
- return nil
- }
-
- var globalDiagnostics []*ast.Diagnostic
- checkers, done := p.checkerPool.GetAllCheckers(ctx)
- defer done()
- for _, checker := range checkers {
- globalDiagnostics = append(globalDiagnostics, checker.GetGlobalDiagnostics()...)
- }
-
- return SortAndDeduplicateDiagnostics(globalDiagnostics)
-}
-
-func (p *Program) GetDeclarationDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return p.getDiagnosticsHelper(ctx, sourceFile, true /*ensureBound*/, true /*ensureChecked*/, p.getDeclarationDiagnosticsForFile)
-}
-
-func (p *Program) GetOptionsDiagnostics(ctx context.Context) []*ast.Diagnostic {
- return SortAndDeduplicateDiagnostics(append(p.GetGlobalDiagnostics(ctx), p.getOptionsDiagnosticsOfConfigFile()...))
-}
-
-func (p *Program) getOptionsDiagnosticsOfConfigFile() []*ast.Diagnostic {
- // todo update p.configParsingDiagnostics when updateAndGetProgramDiagnostics is implemented
- if p.Options() == nil || p.Options().ConfigFilePath == "" {
- return nil
- }
- return p.GetConfigFileParsingDiagnostics() // TODO: actually call getDiagnosticsHelper on config path
-}
-
-func (p *Program) getSyntacticDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return core.Concatenate(sourceFile.Diagnostics(), sourceFile.JSDiagnostics())
-}
-
-func (p *Program) getBindDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- // TODO: restore this; tsgo's main depends on this function binding all files for timing.
- // if checker.SkipTypeChecking(sourceFile, p.compilerOptions) {
- // return nil
- // }
-
- return sourceFile.BindDiagnostics()
-}
-
-func FilterNoEmitSemanticDiagnostics(diagnostics []*ast.Diagnostic, options *core.CompilerOptions) []*ast.Diagnostic {
- if !options.NoEmit.IsTrue() {
- return diagnostics
- }
- return core.Filter(diagnostics, func(d *ast.Diagnostic) bool {
- return !d.SkippedOnNoEmit()
- })
-}
-
-func (p *Program) getSemanticDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- return slices.Concat(
- FilterNoEmitSemanticDiagnostics(p.getSemanticDiagnosticsForFileNotFilter(ctx, sourceFile), p.Options()),
- p.GetIncludeProcessorDiagnostics(sourceFile),
- )
-}
-
-func (p *Program) getSemanticDiagnosticsForFileNotFilter(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- compilerOptions := p.Options()
- if checker.SkipTypeChecking(sourceFile, compilerOptions, p, false) {
- return nil
- }
-
- var fileChecker *checker.Checker
- var done func()
- if sourceFile != nil {
- fileChecker, done = p.checkerPool.GetCheckerForFile(ctx, sourceFile)
- defer done()
- }
- diags := slices.Clip(sourceFile.BindDiagnostics())
- checkers, closeCheckers := p.checkerPool.GetAllCheckers(ctx)
- defer closeCheckers()
-
- // Ask for diags from all checkers; checking one file may add diagnostics to other files.
- // These are deduplicated later.
- for _, checker := range checkers {
- if sourceFile == nil || checker == fileChecker {
- diags = append(diags, checker.GetDiagnostics(ctx, sourceFile)...)
- } else {
- diags = append(diags, checker.GetDiagnosticsWithoutCheck(sourceFile)...)
- }
- }
- if ctx.Err() != nil {
- return nil
- }
-
- // !!! This should be rewritten to work like getBindAndCheckDiagnosticsForFileNoCache.
-
- isPlainJS := ast.IsPlainJSFile(sourceFile, compilerOptions.CheckJs)
- if isPlainJS {
- return core.Filter(diags, func(d *ast.Diagnostic) bool {
- return plainJSErrors.Has(d.Code())
- })
- }
-
- filtered, directivesByLine := p.getDiagnosticsWithPrecedingDirectives(sourceFile, diags)
- for _, directive := range directivesByLine {
- // Above we changed all used directive kinds to @ts-ignore, so any @ts-expect-error directives that
- // remain are unused and thus errors.
- if directive.Kind == ast.CommentDirectiveKindExpectError {
- filtered = append(filtered, ast.NewDiagnostic(sourceFile, directive.Loc, diagnostics.Unused_ts_expect_error_directive))
- }
- }
- return filtered
-}
-
-func (p *Program) getDiagnosticsWithPrecedingDirectives(sourceFile *ast.SourceFile, diags []*ast.Diagnostic) ([]*ast.Diagnostic, map[int]ast.CommentDirective) {
- if len(sourceFile.CommentDirectives) == 0 {
- return diags, nil
- }
- // Build map of directives by line number
- directivesByLine := make(map[int]ast.CommentDirective)
- for _, directive := range sourceFile.CommentDirectives {
- line, _ := scanner.GetECMALineAndCharacterOfPosition(sourceFile, directive.Loc.Pos())
- directivesByLine[line] = directive
- }
- lineStarts := scanner.GetECMALineStarts(sourceFile)
- filtered := make([]*ast.Diagnostic, 0, len(diags))
- for _, diagnostic := range diags {
- ignoreDiagnostic := false
- for line := scanner.ComputeLineOfPosition(lineStarts, diagnostic.Pos()) - 1; line >= 0; line-- {
- // If line contains a @ts-ignore or @ts-expect-error directive, ignore this diagnostic and change
- // the directive kind to @ts-ignore to indicate it was used.
- if directive, ok := directivesByLine[line]; ok {
- ignoreDiagnostic = true
- directive.Kind = ast.CommentDirectiveKindIgnore
- directivesByLine[line] = directive
- break
- }
- // Stop searching backwards when we encounter a line that isn't blank or a comment.
- if !isCommentOrBlankLine(sourceFile.Text(), int(lineStarts[line])) {
- break
- }
- }
- if !ignoreDiagnostic {
- filtered = append(filtered, diagnostic)
- }
- }
- return filtered, directivesByLine
-}
-
-func (p *Program) getDeclarationDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- if sourceFile.IsDeclarationFile {
- return []*ast.Diagnostic{}
- }
-
- if cached, ok := p.declarationDiagnosticCache.Load(sourceFile); ok {
- return cached
- }
-
- host, done := newEmitHost(ctx, p, sourceFile)
- defer done()
- diagnostics := getDeclarationDiagnostics(host, sourceFile)
- diagnostics, _ = p.declarationDiagnosticCache.LoadOrStore(sourceFile, diagnostics)
- return diagnostics
-}
-
-func (p *Program) getSuggestionDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
- if checker.SkipTypeChecking(sourceFile, p.Options(), p, false) {
- return nil
- }
-
- var fileChecker *checker.Checker
- var done func()
- if sourceFile != nil {
- fileChecker, done = p.checkerPool.GetCheckerForFile(ctx, sourceFile)
- defer done()
- }
-
- diags := slices.Clip(sourceFile.BindSuggestionDiagnostics)
-
- checkers, closeCheckers := p.checkerPool.GetAllCheckers(ctx)
- defer closeCheckers()
-
- // Ask for diags from all checkers; checking one file may add diagnostics to other files.
- // These are deduplicated later.
- for _, checker := range checkers {
- if sourceFile == nil || checker == fileChecker {
- diags = append(diags, checker.GetSuggestionDiagnostics(ctx, sourceFile)...)
- } else {
- // !!! is there any case where suggestion diagnostics are produced in other checkers?
- }
- }
- if ctx.Err() != nil {
- return nil
- }
-
- return diags
-}
-
-func isCommentOrBlankLine(text string, pos int) bool {
- for pos < len(text) && (text[pos] == ' ' || text[pos] == '\t') {
- pos++
- }
- return pos == len(text) ||
- pos < len(text) && (text[pos] == '\r' || text[pos] == '\n') ||
- pos+1 < len(text) && text[pos] == '/' && text[pos+1] == '/'
-}
-
-func SortAndDeduplicateDiagnostics(diagnostics []*ast.Diagnostic) []*ast.Diagnostic {
- diagnostics = slices.Clone(diagnostics)
- slices.SortFunc(diagnostics, ast.CompareDiagnostics)
- return compactAndMergeRelatedInfos(diagnostics)
-}
-
-// Remove duplicate diagnostics and, for sequences of diagnostics that differ only by related information,
-// create a single diagnostic with sorted and deduplicated related information.
-func compactAndMergeRelatedInfos(diagnostics []*ast.Diagnostic) []*ast.Diagnostic {
- if len(diagnostics) < 2 {
- return diagnostics
- }
- i := 0
- j := 0
- for i < len(diagnostics) {
- d := diagnostics[i]
- n := 1
- for i+n < len(diagnostics) && ast.EqualDiagnosticsNoRelatedInfo(d, diagnostics[i+n]) {
- n++
- }
- if n > 1 {
- var relatedInfos []*ast.Diagnostic
- for k := range n {
- relatedInfos = append(relatedInfos, diagnostics[i+k].RelatedInformation()...)
- }
- if relatedInfos != nil {
- slices.SortFunc(relatedInfos, ast.CompareDiagnostics)
- relatedInfos = slices.CompactFunc(relatedInfos, ast.EqualDiagnostics)
- d = d.Clone().SetRelatedInfo(relatedInfos)
- }
- }
- diagnostics[j] = d
- i += n
- j++
- }
- clear(diagnostics[j:])
- return diagnostics[:j]
-}
-
-func (p *Program) getDiagnosticsHelper(ctx context.Context, sourceFile *ast.SourceFile, ensureBound bool, ensureChecked bool, getDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic) []*ast.Diagnostic {
- if sourceFile != nil {
- if ensureBound {
- binder.BindSourceFile(sourceFile)
- }
- return SortAndDeduplicateDiagnostics(getDiagnostics(ctx, sourceFile))
- }
- if ensureBound {
- p.BindSourceFiles()
- }
- if ensureChecked {
- p.CheckSourceFiles(ctx, nil)
- if ctx.Err() != nil {
- return nil
- }
- }
- var result []*ast.Diagnostic
- for _, file := range p.files {
- result = append(result, getDiagnostics(ctx, file)...)
- }
- return SortAndDeduplicateDiagnostics(result)
-}
-
-func (p *Program) LineCount() int {
- var count int
- for _, file := range p.files {
- count += len(file.ECMALineMap())
- }
- return count
-}
-
-func (p *Program) IdentifierCount() int {
- var count int
- for _, file := range p.files {
- count += file.IdentifierCount
- }
- return count
-}
-
-func (p *Program) SymbolCount() int {
- var count int
- for _, file := range p.files {
- count += file.SymbolCount
- }
- checkers, done := p.checkerPool.GetAllCheckers(context.Background())
- defer done()
- for _, checker := range checkers {
- count += int(checker.SymbolCount)
- }
- return count
-}
-
-func (p *Program) TypeCount() int {
- var count int
- checkers, done := p.checkerPool.GetAllCheckers(context.Background())
- defer done()
- for _, checker := range checkers {
- count += int(checker.TypeCount)
- }
- return count
-}
-
-func (p *Program) InstantiationCount() int {
- var count int
- checkers, done := p.checkerPool.GetAllCheckers(context.Background())
- defer done()
- for _, checker := range checkers {
- count += int(checker.TotalInstantiationCount)
- }
- return count
-}
-
-func (p *Program) GetSourceFileMetaData(path tspath.Path) ast.SourceFileMetaData {
- return p.sourceFileMetaDatas[path]
-}
-
-func (p *Program) GetEmitModuleFormatOfFile(sourceFile ast.HasFileName) core.ModuleKind {
- return ast.GetEmitModuleFormatOfFileWorker(sourceFile.FileName(), p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile), p.GetSourceFileMetaData(sourceFile.Path()))
-}
-
-func (p *Program) GetEmitSyntaxForUsageLocation(sourceFile ast.HasFileName, location *ast.StringLiteralLike) core.ResolutionMode {
- return getEmitSyntaxForUsageLocationWorker(sourceFile.FileName(), p.sourceFileMetaDatas[sourceFile.Path()], location, p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile))
-}
-
-func (p *Program) GetImpliedNodeFormatForEmit(sourceFile ast.HasFileName) core.ResolutionMode {
- return ast.GetImpliedNodeFormatForEmitWorker(sourceFile.FileName(), p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile).GetEmitModuleKind(), p.GetSourceFileMetaData(sourceFile.Path()))
-}
-
-func (p *Program) GetModeForUsageLocation(sourceFile ast.HasFileName, location *ast.StringLiteralLike) core.ResolutionMode {
- return getModeForUsageLocation(sourceFile.FileName(), p.sourceFileMetaDatas[sourceFile.Path()], location, p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile))
-}
-
-func (p *Program) GetDefaultResolutionModeForFile(sourceFile ast.HasFileName) core.ResolutionMode {
- return getDefaultResolutionModeForFile(sourceFile.FileName(), p.sourceFileMetaDatas[sourceFile.Path()], p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile))
-}
-
-func (p *Program) IsSourceFileDefaultLibrary(path tspath.Path) bool {
- _, ok := p.libFiles[path]
- return ok
-}
-
-func (p *Program) GetDefaultLibFile(path tspath.Path) *LibFile {
- if libFile, ok := p.libFiles[path]; ok {
- return libFile
- }
- return nil
-}
-
-func (p *Program) CommonSourceDirectory() string {
- p.commonSourceDirectoryOnce.Do(func() {
- p.commonSourceDirectory = outputpaths.GetCommonSourceDirectory(
- p.Options(),
- func() []string {
- var files []string
- for _, file := range p.files {
- if sourceFileMayBeEmitted(file, p, false /*forceDtsEmit*/) {
- files = append(files, file.FileName())
- }
- }
- return files
- },
- p.GetCurrentDirectory(),
- p.UseCaseSensitiveFileNames(),
- )
- })
- return p.commonSourceDirectory
-}
-
-type WriteFileData struct {
- SourceMapUrlPos int
- BuildInfo any
- Diagnostics []*ast.Diagnostic
- SkippedDtsWrite bool
-}
-
-type WriteFile func(fileName string, text string, writeByteOrderMark bool, data *WriteFileData) error
-
-type EmitOptions struct {
- TargetSourceFile *ast.SourceFile // Single file to emit. If `nil`, emits all files
- EmitOnly EmitOnly
- WriteFile WriteFile
-}
-
-type EmitResult struct {
- EmitSkipped bool
- Diagnostics []*ast.Diagnostic // Contains declaration emit diagnostics
- EmittedFiles []string // Array of files the compiler wrote to disk
- SourceMaps []*SourceMapEmitResult // Array of sourceMapData if compiler emitted sourcemaps
-}
-
-type SourceMapEmitResult struct {
- InputSourceFileNames []string // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMap.sources list
- SourceMap *sourcemap.RawSourceMap
- GeneratedFile string
-}
-
-func (p *Program) Emit(ctx context.Context, options EmitOptions) *EmitResult {
- // !!! performance measurement
- p.BindSourceFiles()
- if options.EmitOnly != EmitOnlyForcedDts {
- result := HandleNoEmitOnError(
- ctx,
- p,
- options.TargetSourceFile,
- )
- if result != nil || ctx.Err() != nil {
- return result
- }
- }
-
- writerPool := &sync.Pool{
- New: func() any {
- return printer.NewTextWriter(p.Options().NewLine.GetNewLineCharacter())
- },
- }
- wg := core.NewWorkGroup(p.SingleThreaded())
- var emitters []*emitter
- sourceFiles := p.getSourceFilesToEmit(options.TargetSourceFile, options.EmitOnly == EmitOnlyForcedDts)
-
- for _, sourceFile := range sourceFiles {
- emitter := &emitter{
- writer: nil,
- sourceFile: sourceFile,
- emitOnly: options.EmitOnly,
- writeFile: options.WriteFile,
- }
- emitters = append(emitters, emitter)
- wg.Queue(func() {
- host, done := newEmitHost(ctx, p, sourceFile)
- defer done()
- emitter.host = host
-
- // take an unused writer
- writer := writerPool.Get().(printer.EmitTextWriter)
- writer.Clear()
-
- // attach writer and perform emit
- emitter.writer = writer
- emitter.paths = outputpaths.GetOutputPathsFor(sourceFile, host.Options(), host, options.EmitOnly == EmitOnlyForcedDts)
- emitter.emit()
- emitter.writer = nil
-
- // put the writer back in the pool
- writerPool.Put(writer)
- })
- }
-
- // wait for emit to complete
- wg.RunAndWait()
-
- // collect results from emit, preserving input order
- return CombineEmitResults(core.Map(emitters, func(e *emitter) *EmitResult {
- return &e.emitResult
- }))
-}
-
-func CombineEmitResults(results []*EmitResult) *EmitResult {
- result := &EmitResult{}
- for _, emitResult := range results {
- if emitResult == nil {
- continue // Skip nil results
- }
- if emitResult.EmitSkipped {
- result.EmitSkipped = true
- }
- result.Diagnostics = append(result.Diagnostics, emitResult.Diagnostics...)
- result.EmittedFiles = append(result.EmittedFiles, emitResult.EmittedFiles...)
- if emitResult.SourceMaps != nil {
- result.SourceMaps = append(result.SourceMaps, emitResult.SourceMaps...)
- }
- }
- return result
-}
-
-type ProgramLike interface {
- Options() *core.CompilerOptions
- GetSourceFiles() []*ast.SourceFile
- GetConfigFileParsingDiagnostics() []*ast.Diagnostic
- GetSyntacticDiagnostics(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic
- GetBindDiagnostics(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic
- GetOptionsDiagnostics(ctx context.Context) []*ast.Diagnostic
- GetProgramDiagnostics() []*ast.Diagnostic
- GetGlobalDiagnostics(ctx context.Context) []*ast.Diagnostic
- GetSemanticDiagnostics(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic
- GetDeclarationDiagnostics(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic
- Emit(ctx context.Context, options EmitOptions) *EmitResult
-}
-
-func HandleNoEmitOnError(ctx context.Context, program ProgramLike, file *ast.SourceFile) *EmitResult {
- if !program.Options().NoEmitOnError.IsTrue() {
- return nil // No emit on error is not set, so we can proceed with emitting
- }
-
- diagnostics := GetDiagnosticsOfAnyProgram(
- ctx,
- program,
- file,
- true,
- program.GetBindDiagnostics,
- program.GetSemanticDiagnostics,
- )
- if len(diagnostics) == 0 {
- return nil // No diagnostics, so we can proceed with emitting
- }
- return &EmitResult{
- Diagnostics: diagnostics,
- EmitSkipped: true,
- }
-}
-
-func GetDiagnosticsOfAnyProgram(
- ctx context.Context,
- program ProgramLike,
- file *ast.SourceFile,
- skipNoEmitCheckForDtsDiagnostics bool,
- getBindDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic,
- getSemanticDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic,
-) []*ast.Diagnostic {
- allDiagnostics := slices.Clip(program.GetConfigFileParsingDiagnostics())
- configFileParsingDiagnosticsLength := len(allDiagnostics)
-
- allDiagnostics = append(allDiagnostics, program.GetSyntacticDiagnostics(ctx, file)...)
- allDiagnostics = append(allDiagnostics, program.GetProgramDiagnostics()...)
-
- if len(allDiagnostics) == configFileParsingDiagnosticsLength {
- // Options diagnostics include global diagnostics (even though we collect them separately),
- // and global diagnostics create checkers, which then bind all of the files. Do this binding
- // early so we can track the time.
- getBindDiagnostics(ctx, file)
-
- allDiagnostics = append(allDiagnostics, program.GetOptionsDiagnostics(ctx)...)
-
- if program.Options().ListFilesOnly.IsFalseOrUnknown() {
- allDiagnostics = append(allDiagnostics, program.GetGlobalDiagnostics(ctx)...)
-
- if len(allDiagnostics) == configFileParsingDiagnosticsLength {
- allDiagnostics = append(allDiagnostics, getSemanticDiagnostics(ctx, file)...)
- }
-
- if (skipNoEmitCheckForDtsDiagnostics || program.Options().NoEmit.IsTrue()) && program.Options().GetEmitDeclarations() && len(allDiagnostics) == configFileParsingDiagnosticsLength {
- allDiagnostics = append(allDiagnostics, program.GetDeclarationDiagnostics(ctx, file)...)
- }
- }
- }
- return allDiagnostics
-}
-
-func (p *Program) toPath(filename string) tspath.Path {
- return tspath.ToPath(filename, p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames())
-}
-
-func (p *Program) GetSourceFile(filename string) *ast.SourceFile {
- path := p.toPath(filename)
- return p.GetSourceFileByPath(path)
-}
-
-func (p *Program) GetSourceFileForResolvedModule(fileName string) *ast.SourceFile {
- file := p.GetSourceFile(fileName)
- if file == nil {
- filename := p.GetParseFileRedirect(fileName)
- if filename != "" {
- return p.GetSourceFile(filename)
- }
- }
- return file
-}
-
-func (p *Program) GetSourceFileByPath(path tspath.Path) *ast.SourceFile {
- return p.filesByPath[path]
-}
-
-func (p *Program) HasSameFileNames(other *Program) bool {
- return maps.EqualFunc(p.filesByPath, other.filesByPath, func(a, b *ast.SourceFile) bool {
- // checks for casing differences on case-insensitive file systems
- return a.FileName() == b.FileName()
- })
-}
-
-func (p *Program) GetSourceFiles() []*ast.SourceFile {
- return p.files
-}
-
-// Testing only
-func (p *Program) GetIncludeReasons() map[tspath.Path][]*fileIncludeReason {
- return p.includeProcessor.fileIncludeReasons
-}
-
-// Testing only
-func (p *Program) IsMissingPath(path tspath.Path) bool {
- return slices.ContainsFunc(p.missingFiles, func(missingPath string) bool {
- return p.toPath(missingPath) == path
- })
-}
-
-func (p *Program) ExplainFiles(w io.Writer) {
- toRelativeFileName := func(fileName string) string {
- return tspath.GetRelativePathFromDirectory(p.GetCurrentDirectory(), fileName, p.comparePathsOptions)
- }
- for _, file := range p.GetSourceFiles() {
- fmt.Fprintln(w, toRelativeFileName(file.FileName()))
- for _, reason := range p.includeProcessor.fileIncludeReasons[file.Path()] {
- fmt.Fprintln(w, " ", reason.toDiagnostic(p, true).Message())
- }
- for _, diag := range p.includeProcessor.explainRedirectAndImpliedFormat(p, file, toRelativeFileName) {
- fmt.Fprintln(w, " ", diag.Message())
- }
- }
-}
-
-func (p *Program) GetLibFileFromReference(ref *ast.FileReference) *ast.SourceFile {
- path, ok := tsoptions.GetLibFileName(ref.FileName)
- if !ok {
- return nil
- }
- if sourceFile, ok := p.filesByPath[tspath.Path(path)]; ok {
- return sourceFile
- }
- return nil
-}
-
-func (p *Program) GetResolvedTypeReferenceDirectiveFromTypeReferenceDirective(typeRef *ast.FileReference, sourceFile *ast.SourceFile) *module.ResolvedTypeReferenceDirective {
- if resolutions, ok := p.typeResolutionsInFile[sourceFile.Path()]; ok {
- if resolved, ok := resolutions[module.ModeAwareCacheKey{Name: typeRef.FileName, Mode: p.getModeForTypeReferenceDirectiveInFile(typeRef, sourceFile)}]; ok {
- return resolved
- }
- }
- return nil
-}
-
-func (p *Program) GetResolvedTypeReferenceDirectives() map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective] {
- return p.typeResolutionsInFile
-}
-
-func (p *Program) getModeForTypeReferenceDirectiveInFile(ref *ast.FileReference, sourceFile *ast.SourceFile) core.ResolutionMode {
- if ref.ResolutionMode != core.ResolutionModeNone {
- return ref.ResolutionMode
- }
- return p.GetDefaultResolutionModeForFile(sourceFile)
-}
-
-func (p *Program) IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool {
- return p.sourceFilesFoundSearchingNodeModules.Has(file.Path())
-}
-
-// UnsupportedExtensions returns a list of all present "unsupported" extensions,
-// e.g. extensions that are not yet supported by the port.
-func (p *Program) UnsupportedExtensions() []string {
- return p.unsupportedExtensions
-}
-
-func (p *Program) GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node) {
- if result := p.jsxRuntimeImportSpecifiers[path]; result != nil {
- return result.moduleReference, result.specifier
- }
- return "", nil
-}
-
-func (p *Program) GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node {
- return p.importHelpersImportSpecifiers[path]
-}
-
-func (p *Program) SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool {
- return sourceFileMayBeEmitted(sourceFile, p, forceDtsEmit)
-}
-
-var plainJSErrors = collections.NewSetFromItems(
- // binder errors
- diagnostics.Cannot_redeclare_block_scoped_variable_0.Code(),
- diagnostics.A_module_cannot_have_multiple_default_exports.Code(),
- diagnostics.Another_export_default_is_here.Code(),
- diagnostics.The_first_export_default_is_here.Code(),
- diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module.Code(),
- diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode.Code(),
- diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here.Code(),
- diagnostics.X_constructor_is_a_reserved_word.Code(),
- diagnostics.X_delete_cannot_be_called_on_an_identifier_in_strict_mode.Code(),
- diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode.Code(),
- diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode.Code(),
- diagnostics.Invalid_use_of_0_in_strict_mode.Code(),
- diagnostics.A_label_is_not_allowed_here.Code(),
- diagnostics.X_with_statements_are_not_allowed_in_strict_mode.Code(),
- // grammar errors
- diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement.Code(),
- diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement.Code(),
- diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name.Code(),
- diagnostics.A_class_member_cannot_have_the_0_keyword.Code(),
- diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name.Code(),
- diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement.Code(),
- diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement.Code(),
- diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement.Code(),
- diagnostics.A_default_export_must_be_at_the_top_level_of_a_file_or_module_declaration.Code(),
- diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context.Code(),
- diagnostics.A_destructuring_declaration_must_have_an_initializer.Code(),
- diagnostics.A_get_accessor_cannot_have_parameters.Code(),
- diagnostics.A_rest_element_cannot_contain_a_binding_pattern.Code(),
- diagnostics.A_rest_element_cannot_have_a_property_name.Code(),
- diagnostics.A_rest_element_cannot_have_an_initializer.Code(),
- diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern.Code(),
- diagnostics.A_rest_parameter_cannot_have_an_initializer.Code(),
- diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list.Code(),
- diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma.Code(),
- diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block.Code(),
- diagnostics.A_set_accessor_cannot_have_rest_parameter.Code(),
- diagnostics.A_set_accessor_must_have_exactly_one_parameter.Code(),
- diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module.Code(),
- diagnostics.An_export_declaration_cannot_have_modifiers.Code(),
- diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module.Code(),
- diagnostics.An_import_declaration_cannot_have_modifiers.Code(),
- diagnostics.An_object_member_cannot_be_declared_optional.Code(),
- diagnostics.Argument_of_dynamic_import_cannot_be_spread_element.Code(),
- diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable.Code(),
- diagnostics.Cannot_redeclare_identifier_0_in_catch_clause.Code(),
- diagnostics.Catch_clause_variable_cannot_have_an_initializer.Code(),
- diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator.Code(),
- diagnostics.Classes_can_only_extend_a_single_class.Code(),
- diagnostics.Classes_may_not_have_a_field_named_constructor.Code(),
- diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.Code(),
- diagnostics.Duplicate_label_0.Code(),
- diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_set_of_attributes_as_arguments.Code(),
- diagnostics.X_for_await_loops_cannot_be_used_inside_a_class_static_block.Code(),
- diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression.Code(),
- diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name.Code(),
- diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array.Code(),
- diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names.Code(),
- diagnostics.Jump_target_cannot_cross_function_boundary.Code(),
- diagnostics.Line_terminator_not_permitted_before_arrow.Code(),
- diagnostics.Modifiers_cannot_appear_here.Code(),
- diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement.Code(),
- diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement.Code(),
- diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies.Code(),
- diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.Code(),
- diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier.Code(),
- diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain.Code(),
- diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async.Code(),
- diagnostics.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer.Code(),
- diagnostics.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer.Code(),
- diagnostics.Trailing_comma_not_allowed.Code(),
- diagnostics.Variable_declaration_list_cannot_be_empty.Code(),
- diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses.Code(),
- diagnostics.X_0_expected.Code(),
- diagnostics.X_0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2.Code(),
- diagnostics.X_0_list_cannot_be_empty.Code(),
- diagnostics.X_0_modifier_already_seen.Code(),
- diagnostics.X_0_modifier_cannot_appear_on_a_constructor_declaration.Code(),
- diagnostics.X_0_modifier_cannot_appear_on_a_module_or_namespace_element.Code(),
- diagnostics.X_0_modifier_cannot_appear_on_a_parameter.Code(),
- diagnostics.X_0_modifier_cannot_appear_on_class_elements_of_this_kind.Code(),
- diagnostics.X_0_modifier_cannot_be_used_here.Code(),
- diagnostics.X_0_modifier_must_precede_1_modifier.Code(),
- diagnostics.X_0_declarations_can_only_be_declared_inside_a_block.Code(),
- diagnostics.X_0_declarations_must_be_initialized.Code(),
- diagnostics.X_extends_clause_already_seen.Code(),
- diagnostics.X_let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations.Code(),
- diagnostics.Class_constructor_may_not_be_a_generator.Code(),
- diagnostics.Class_constructor_may_not_be_an_accessor.Code(),
- diagnostics.X_await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.Code(),
- diagnostics.X_await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.Code(),
- diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class.Code(),
- // Type errors
- diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value.Code(),
-)
diff --git a/kitcom/internal/tsgo/compiler/program_test.go b/kitcom/internal/tsgo/compiler/program_test.go
deleted file mode 100644
index eba35f2..0000000
--- a/kitcom/internal/tsgo/compiler/program_test.go
+++ /dev/null
@@ -1,314 +0,0 @@
-package compiler_test
-
-import (
- "path/filepath"
- "slices"
- "strings"
- "testing"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/bundled"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/compiler"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/repo"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/osvfs"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/vfstest"
- "gotest.tools/v3/assert"
-)
-
-type testFile struct {
- fileName string
- contents string
-}
-
-type programTest struct {
- testName string
- files []testFile
- expectedFiles []string
- target core.ScriptTarget
-}
-
-var esnextLibs = []string{
- "lib.es5.d.ts",
- "lib.es2015.d.ts",
- "lib.es2016.d.ts",
- "lib.es2017.d.ts",
- "lib.es2018.d.ts",
- "lib.es2019.d.ts",
- "lib.es2020.d.ts",
- "lib.es2021.d.ts",
- "lib.es2022.d.ts",
- "lib.es2023.d.ts",
- "lib.es2024.d.ts",
- "lib.esnext.d.ts",
- "lib.dom.d.ts",
- "lib.dom.iterable.d.ts",
- "lib.dom.asynciterable.d.ts",
- "lib.webworker.importscripts.d.ts",
- "lib.scripthost.d.ts",
- "lib.es2015.core.d.ts",
- "lib.es2015.collection.d.ts",
- "lib.es2015.generator.d.ts",
- "lib.es2015.iterable.d.ts",
- "lib.es2015.promise.d.ts",
- "lib.es2015.proxy.d.ts",
- "lib.es2015.reflect.d.ts",
- "lib.es2015.symbol.d.ts",
- "lib.es2015.symbol.wellknown.d.ts",
- "lib.es2016.array.include.d.ts",
- "lib.es2016.intl.d.ts",
- "lib.es2017.arraybuffer.d.ts",
- "lib.es2017.date.d.ts",
- "lib.es2017.object.d.ts",
- "lib.es2017.sharedmemory.d.ts",
- "lib.es2017.string.d.ts",
- "lib.es2017.intl.d.ts",
- "lib.es2017.typedarrays.d.ts",
- "lib.es2018.asyncgenerator.d.ts",
- "lib.es2018.asynciterable.d.ts",
- "lib.es2018.intl.d.ts",
- "lib.es2018.promise.d.ts",
- "lib.es2018.regexp.d.ts",
- "lib.es2019.array.d.ts",
- "lib.es2019.object.d.ts",
- "lib.es2019.string.d.ts",
- "lib.es2019.symbol.d.ts",
- "lib.es2019.intl.d.ts",
- "lib.es2020.bigint.d.ts",
- "lib.es2020.date.d.ts",
- "lib.es2020.promise.d.ts",
- "lib.es2020.sharedmemory.d.ts",
- "lib.es2020.string.d.ts",
- "lib.es2020.symbol.wellknown.d.ts",
- "lib.es2020.intl.d.ts",
- "lib.es2020.number.d.ts",
- "lib.es2021.promise.d.ts",
- "lib.es2021.string.d.ts",
- "lib.es2021.weakref.d.ts",
- "lib.es2021.intl.d.ts",
- "lib.es2022.array.d.ts",
- "lib.es2022.error.d.ts",
- "lib.es2022.intl.d.ts",
- "lib.es2022.object.d.ts",
- "lib.es2022.string.d.ts",
- "lib.es2022.regexp.d.ts",
- "lib.es2023.array.d.ts",
- "lib.es2023.collection.d.ts",
- "lib.es2023.intl.d.ts",
- "lib.es2024.arraybuffer.d.ts",
- "lib.es2024.collection.d.ts",
- "lib.es2024.object.d.ts",
- "lib.es2024.promise.d.ts",
- "lib.es2024.regexp.d.ts",
- "lib.es2024.sharedmemory.d.ts",
- "lib.es2024.string.d.ts",
- "lib.esnext.array.d.ts",
- "lib.esnext.collection.d.ts",
- "lib.esnext.intl.d.ts",
- "lib.esnext.disposable.d.ts",
- "lib.esnext.promise.d.ts",
- "lib.esnext.decorators.d.ts",
- "lib.esnext.iterator.d.ts",
- "lib.esnext.float16.d.ts",
- "lib.esnext.error.d.ts",
- "lib.esnext.sharedmemory.d.ts",
- "lib.decorators.d.ts",
- "lib.decorators.legacy.d.ts",
- "lib.esnext.full.d.ts",
-}
-
-var programTestCases = []programTest{
- {
- testName: "BasicFileOrdering",
- files: []testFile{
- {fileName: "c:/dev/src/index.ts", contents: "/// \n/// "},
- {fileName: "c:/dev/src2/a/5.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/4.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/3.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/2.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/c/1.ts", contents: "console.log('hello');"},
- {fileName: "c:/dev/src2/a/10.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/c/d/9.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/c/d/e/8.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/c/d/e/7.ts", contents: "/// "},
- {fileName: "c:/dev/src2/a/b/c/d/e/f/6.ts", contents: "console.log('world!');"},
- },
- expectedFiles: slices.Concat(esnextLibs,
- []string{
- "c:/dev/src2/a/b/c/1.ts",
- "c:/dev/src2/a/b/2.ts",
- "c:/dev/src2/a/b/3.ts",
- "c:/dev/src2/a/4.ts",
- "c:/dev/src2/a/5.ts",
- "c:/dev/src2/a/b/c/d/e/f/6.ts",
- "c:/dev/src2/a/b/c/d/e/7.ts",
- "c:/dev/src2/a/b/c/d/e/8.ts",
- "c:/dev/src2/a/b/c/d/9.ts",
- "c:/dev/src2/a/10.ts",
- "c:/dev/src/index.ts",
- }),
- target: core.ScriptTargetESNext,
- },
- {
- testName: "FileOrderingImports",
- files: []testFile{
- {fileName: "c:/dev/src/index.ts", contents: "import * as five from '../src2/a/5.ts';\nimport * as ten from '../src2/a/10.ts';"},
- {fileName: "c:/dev/src2/a/5.ts", contents: "import * as four from './4.ts';"},
- {fileName: "c:/dev/src2/a/4.ts", contents: "import * as three from './b/3.ts';"},
- {fileName: "c:/dev/src2/a/b/3.ts", contents: "import * as two from './2.ts';"},
- {fileName: "c:/dev/src2/a/b/2.ts", contents: "import * as one from './c/1.ts';"},
- {fileName: "c:/dev/src2/a/b/c/1.ts", contents: "console.log('hello');"},
- {fileName: "c:/dev/src2/a/10.ts", contents: "import * as nine from './b/c/d/9.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/9.ts", contents: "import * as eight from './e/8.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/8.ts", contents: "import * as seven from './7.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/7.ts", contents: "import * as six from './f/6.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/f/6.ts", contents: "console.log('world!');"},
- },
- expectedFiles: slices.Concat(esnextLibs,
- []string{
- "c:/dev/src2/a/b/c/1.ts",
- "c:/dev/src2/a/b/2.ts",
- "c:/dev/src2/a/b/3.ts",
- "c:/dev/src2/a/4.ts",
- "c:/dev/src2/a/5.ts",
- "c:/dev/src2/a/b/c/d/e/f/6.ts",
- "c:/dev/src2/a/b/c/d/e/7.ts",
- "c:/dev/src2/a/b/c/d/e/8.ts",
- "c:/dev/src2/a/b/c/d/9.ts",
- "c:/dev/src2/a/10.ts",
- "c:/dev/src/index.ts",
- }),
- target: core.ScriptTargetESNext,
- },
- {
- testName: "FileOrderingCycles",
- files: []testFile{
- {fileName: "c:/dev/src/index.ts", contents: "import * as five from '../src2/a/5.ts';\nimport * as ten from '../src2/a/10.ts';"},
- {fileName: "c:/dev/src2/a/5.ts", contents: "import * as four from './4.ts';"},
- {fileName: "c:/dev/src2/a/4.ts", contents: "import * as three from './b/3.ts';"},
- {fileName: "c:/dev/src2/a/b/3.ts", contents: "import * as two from './2.ts';\nimport * as cycle from 'c:/dev/src/index.ts'; "},
- {fileName: "c:/dev/src2/a/b/2.ts", contents: "import * as one from './c/1.ts';"},
- {fileName: "c:/dev/src2/a/b/c/1.ts", contents: "console.log('hello');"},
- {fileName: "c:/dev/src2/a/10.ts", contents: "import * as nine from './b/c/d/9.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/9.ts", contents: "import * as eight from './e/8.ts';\nimport * as cycle from 'c:/dev/src/index.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/8.ts", contents: "import * as seven from './7.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/7.ts", contents: "import * as six from './f/6.ts';"},
- {fileName: "c:/dev/src2/a/b/c/d/e/f/6.ts", contents: "console.log('world!');"},
- },
- expectedFiles: slices.Concat(esnextLibs,
- []string{
- "c:/dev/src2/a/b/c/1.ts",
- "c:/dev/src2/a/b/2.ts",
- "c:/dev/src2/a/b/3.ts",
- "c:/dev/src2/a/4.ts",
- "c:/dev/src2/a/5.ts",
- "c:/dev/src2/a/b/c/d/e/f/6.ts",
- "c:/dev/src2/a/b/c/d/e/7.ts",
- "c:/dev/src2/a/b/c/d/e/8.ts",
- "c:/dev/src2/a/b/c/d/9.ts",
- "c:/dev/src2/a/10.ts",
- "c:/dev/src/index.ts",
- }),
- target: core.ScriptTargetESNext,
- },
-}
-
-func TestProgram(t *testing.T) {
- t.Parallel()
-
- if !bundled.Embedded {
- // Without embedding, we'd need to read all of the lib files out from disk into the MapFS.
- // Just skip this for now.
- t.Skip("bundled files are not embedded")
- }
-
- for _, testCase := range programTestCases {
- t.Run(testCase.testName, func(t *testing.T) {
- t.Parallel()
- libPrefix := bundled.LibPath() + "/"
- fs := vfstest.FromMap[any](nil, false /*useCaseSensitiveFileNames*/)
- fs = bundled.WrapFS(fs)
-
- for _, testFile := range testCase.files {
- _ = fs.WriteFile(testFile.fileName, testFile.contents, false)
- }
-
- opts := core.CompilerOptions{Target: testCase.target}
-
- program := compiler.NewProgram(compiler.ProgramOptions{
- Config: &tsoptions.ParsedCommandLine{
- ParsedConfig: &core.ParsedOptions{
- FileNames: []string{"c:/dev/src/index.ts"},
- CompilerOptions: &opts,
- },
- },
- Host: compiler.NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil, nil),
- })
-
- actualFiles := []string{}
- for _, file := range program.GetSourceFiles() {
- actualFiles = append(actualFiles, strings.TrimPrefix(file.FileName(), libPrefix))
- }
-
- assert.DeepEqual(t, testCase.expectedFiles, actualFiles)
- })
- }
-}
-
-func BenchmarkNewProgram(b *testing.B) {
- if !bundled.Embedded {
- // Without embedding, we'd need to read all of the lib files out from disk into the MapFS.
- // Just skip this for now.
- b.Skip("bundled files are not embedded")
- }
-
- for _, testCase := range programTestCases {
- b.Run(testCase.testName, func(b *testing.B) {
- fs := vfstest.FromMap[any](nil, false /*useCaseSensitiveFileNames*/)
- fs = bundled.WrapFS(fs)
-
- for _, testFile := range testCase.files {
- _ = fs.WriteFile(testFile.fileName, testFile.contents, false)
- }
-
- opts := core.CompilerOptions{Target: testCase.target}
- programOpts := compiler.ProgramOptions{
- Config: &tsoptions.ParsedCommandLine{
- ParsedConfig: &core.ParsedOptions{
- FileNames: []string{"c:/dev/src/index.ts"},
- CompilerOptions: &opts,
- },
- },
- Host: compiler.NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil, nil),
- }
-
- for b.Loop() {
- compiler.NewProgram(programOpts)
- }
- })
- }
-
- b.Run("compiler", func(b *testing.B) {
- repo.SkipIfNoTypeScriptSubmodule(b)
-
- rootPath := tspath.NormalizeSlashes(filepath.Join(repo.TypeScriptSubmodulePath, "src", "compiler"))
-
- fs := osvfs.FS()
- fs = bundled.WrapFS(fs)
-
- host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)
-
- parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), nil, host, nil)
- assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")
-
- opts := compiler.ProgramOptions{
- Config: parsed,
- Host: host,
- }
-
- for b.Loop() {
- compiler.NewProgram(opts)
- }
- })
-}
diff --git a/kitcom/internal/tsgo/compiler/projectreferencedtsfakinghost.go b/kitcom/internal/tsgo/compiler/projectreferencedtsfakinghost.go
deleted file mode 100644
index a5ced2d..0000000
--- a/kitcom/internal/tsgo/compiler/projectreferencedtsfakinghost.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package compiler
-
-import (
- "strings"
- "time"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/cachedvfs"
-)
-
-type projectReferenceDtsFakingHost struct {
- host CompilerHost
- fs *cachedvfs.FS
-}
-
-var _ module.ResolutionHost = (*projectReferenceDtsFakingHost)(nil)
-
-func newProjectReferenceDtsFakingHost(loader *fileLoader) module.ResolutionHost {
- // Create a new host that will fake the dts files
- host := &projectReferenceDtsFakingHost{
- host: loader.opts.Host,
- fs: cachedvfs.From(&projectReferenceDtsFakingVfs{
- projectReferenceFileMapper: loader.projectReferenceFileMapper,
- dtsDirectories: loader.dtsDirectories,
- knownSymlinks: knownSymlinks{},
- }),
- }
- return host
-}
-
-// FS implements module.ResolutionHost.
-func (h *projectReferenceDtsFakingHost) FS() vfs.FS {
- return h.fs
-}
-
-// GetCurrentDirectory implements module.ResolutionHost.
-func (h *projectReferenceDtsFakingHost) GetCurrentDirectory() string {
- return h.host.GetCurrentDirectory()
-}
-
-type projectReferenceDtsFakingVfs struct {
- projectReferenceFileMapper *projectReferenceFileMapper
- dtsDirectories collections.Set[tspath.Path]
- knownSymlinks knownSymlinks
-}
-
-var _ vfs.FS = (*projectReferenceDtsFakingVfs)(nil)
-
-// UseCaseSensitiveFileNames implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) UseCaseSensitiveFileNames() bool {
- return fs.projectReferenceFileMapper.opts.Host.FS().UseCaseSensitiveFileNames()
-}
-
-// FileExists implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) FileExists(path string) bool {
- if fs.projectReferenceFileMapper.opts.Host.FS().FileExists(path) {
- return true
- }
- if !tspath.IsDeclarationFileName(path) {
- return false
- }
- // Project references go to source file instead of .d.ts file
- return fs.fileOrDirectoryExistsUsingSource(path /*isFile*/, true)
-}
-
-// ReadFile implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) ReadFile(path string) (contents string, ok bool) {
- // Dont need to override as we cannot mimick read file
- return fs.projectReferenceFileMapper.opts.Host.FS().ReadFile(path)
-}
-
-// WriteFile implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) WriteFile(path string, data string, writeByteOrderMark bool) error {
- panic("should not be called by resolver")
-}
-
-// Remove implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) Remove(path string) error {
- panic("should not be called by resolver")
-}
-
-// Chtimes implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) Chtimes(path string, aTime time.Time, mTime time.Time) error {
- panic("should not be called by resolver")
-}
-
-// DirectoryExists implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) DirectoryExists(path string) bool {
- if fs.projectReferenceFileMapper.opts.Host.FS().DirectoryExists(path) {
- fs.handleDirectoryCouldBeSymlink(path)
- return true
- }
- return fs.fileOrDirectoryExistsUsingSource(path /*isFile*/, false)
-}
-
-// GetAccessibleEntries implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) GetAccessibleEntries(path string) vfs.Entries {
- panic("should not be called by resolver")
-}
-
-// Stat implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) Stat(path string) vfs.FileInfo {
- panic("should not be called by resolver")
-}
-
-// WalkDir implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) WalkDir(root string, walkFn vfs.WalkDirFunc) error {
- panic("should not be called by resolver")
-}
-
-// Realpath implements vfs.FS.
-func (fs *projectReferenceDtsFakingVfs) Realpath(path string) string {
- result, ok := fs.knownSymlinks.Files().Load(fs.toPath(path))
- if ok {
- return result
- }
- return fs.projectReferenceFileMapper.opts.Host.FS().Realpath(path)
-}
-
-func (fs *projectReferenceDtsFakingVfs) toPath(path string) tspath.Path {
- return tspath.ToPath(path, fs.projectReferenceFileMapper.opts.Host.GetCurrentDirectory(), fs.UseCaseSensitiveFileNames())
-}
-
-func (fs *projectReferenceDtsFakingVfs) handleDirectoryCouldBeSymlink(directory string) {
- if tspath.ContainsIgnoredPath(directory) {
- return
- }
-
- // Because we already watch node_modules, handle symlinks in there
- if !strings.Contains(directory, "/node_modules/") {
- return
- }
-
- directoryPath := tspath.Path(tspath.EnsureTrailingDirectorySeparator(string(fs.toPath(directory))))
- if _, ok := fs.knownSymlinks.Directories().Load(directoryPath); ok {
- return
- }
-
- realDirectory := fs.Realpath(directory)
- var realPath tspath.Path
- if realDirectory == directory {
- // not symlinked
- return
- }
- if realPath = tspath.Path(tspath.EnsureTrailingDirectorySeparator(string(fs.toPath(realDirectory)))); realPath == directoryPath {
- // not symlinked
- return
- }
- fs.knownSymlinks.SetDirectory(directory, directoryPath, &knownDirectoryLink{
- Real: tspath.EnsureTrailingDirectorySeparator(realDirectory),
- RealPath: realPath,
- })
-}
-
-func (fs *projectReferenceDtsFakingVfs) fileOrDirectoryExistsUsingSource(fileOrDirectory string, isFile bool) bool {
- fileOrDirectoryExistsUsingSource := core.IfElse(isFile, fs.fileExistsIfProjectReferenceDts, fs.directoryExistsIfProjectReferenceDeclDir)
- // Check current directory or file
- result := fileOrDirectoryExistsUsingSource(fileOrDirectory)
- if result != core.TSUnknown {
- return result == core.TSTrue
- }
-
- knownDirectoryLinks := fs.knownSymlinks.Directories()
- if knownDirectoryLinks.Size() == 0 {
- return false
- }
- fileOrDirectoryPath := fs.toPath(fileOrDirectory)
- if !strings.Contains(string(fileOrDirectoryPath), "/node_modules/") {
- return false
- }
- if isFile {
- _, ok := fs.knownSymlinks.Files().Load(fileOrDirectoryPath)
- if ok {
- return true
- }
- }
-
- // If it contains node_modules check if its one of the symlinked path we know of
- var exists bool
- knownDirectoryLinks.Range(func(directoryPath tspath.Path, knownDirectoryLink *knownDirectoryLink) bool {
- relative, hasPrefix := strings.CutPrefix(string(fileOrDirectoryPath), string(directoryPath))
- if !hasPrefix {
- return true
- }
- if exists = fileOrDirectoryExistsUsingSource(string(knownDirectoryLink.RealPath) + relative).IsTrue(); exists {
- if isFile {
- // Store the real path for the file
- absolutePath := tspath.GetNormalizedAbsolutePath(fileOrDirectory, fs.projectReferenceFileMapper.opts.Host.GetCurrentDirectory())
- fs.knownSymlinks.SetFile(
- fileOrDirectoryPath,
- knownDirectoryLink.Real+absolutePath[len(directoryPath):],
- )
- }
- return false
- }
- return true
- })
- return exists
-}
-
-func (fs *projectReferenceDtsFakingVfs) fileExistsIfProjectReferenceDts(file string) core.Tristate {
- source := fs.projectReferenceFileMapper.getProjectReferenceFromOutputDts(fs.toPath(file))
- if source != nil {
- return core.IfElse(fs.projectReferenceFileMapper.opts.Host.FS().FileExists(source.Source), core.TSTrue, core.TSFalse)
- }
- return core.TSUnknown
-}
-
-func (fs *projectReferenceDtsFakingVfs) directoryExistsIfProjectReferenceDeclDir(dir string) core.Tristate {
- dirPath := fs.toPath(dir)
- dirPathWithTrailingDirectorySeparator := dirPath + "/"
- for declDirPath := range fs.dtsDirectories.Keys() {
- if dirPath == declDirPath ||
- // Any parent directory of declaration dir
- strings.HasPrefix(string(declDirPath), string(dirPathWithTrailingDirectorySeparator)) ||
- // Any directory inside declaration dir
- strings.HasPrefix(string(dirPath), string(declDirPath)+"/") {
- return core.TSTrue
- }
- }
- return core.TSUnknown
-}
diff --git a/kitcom/internal/tsgo/compiler/projectreferencefilemapper.go b/kitcom/internal/tsgo/compiler/projectreferencefilemapper.go
deleted file mode 100644
index 40a50df..0000000
--- a/kitcom/internal/tsgo/compiler/projectreferencefilemapper.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package compiler
-
-import (
- "strings"
-
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type projectReferenceFileMapper struct {
- opts ProgramOptions
- host module.ResolutionHost
- loader *fileLoader // Only present during populating the mapper and parsing, released after that
-
- configToProjectReference map[tspath.Path]*tsoptions.ParsedCommandLine // All the resolved references needed
- referencesInConfigFile map[tspath.Path][]tspath.Path // Map of config file to its references
- sourceToProjectReference map[tspath.Path]*tsoptions.SourceOutputAndProjectReference
- outputDtsToProjectReference map[tspath.Path]*tsoptions.SourceOutputAndProjectReference
-
- // Store all the realpath from dts in node_modules to source file from project reference needed during parsing so it can be used later
- realpathDtsToSource collections.SyncMap[tspath.Path, *tsoptions.SourceOutputAndProjectReference]
-}
-
-func (mapper *projectReferenceFileMapper) getParseFileRedirect(file ast.HasFileName) string {
- if mapper.opts.canUseProjectReferenceSource() {
- // Map to source file from project reference
- source := mapper.getProjectReferenceFromOutputDts(file.Path())
- if source == nil {
- source = mapper.getSourceToDtsIfSymlink(file)
- }
- if source != nil {
- return source.Source
- }
- } else {
- // Map to dts file from project reference
- output := mapper.getProjectReferenceFromSource(file.Path())
- if output != nil && output.OutputDts != "" {
- return output.OutputDts
- }
- }
- return ""
-}
-
-func (mapper *projectReferenceFileMapper) getResolvedProjectReferences() []*tsoptions.ParsedCommandLine {
- refs, ok := mapper.referencesInConfigFile[mapper.opts.Config.ConfigFile.SourceFile.Path()]
- var result []*tsoptions.ParsedCommandLine
- if ok {
- result = make([]*tsoptions.ParsedCommandLine, 0, len(refs))
- for _, refPath := range refs {
- refConfig, _ := mapper.configToProjectReference[refPath]
- result = append(result, refConfig)
- }
- }
- return result
-}
-
-func (mapper *projectReferenceFileMapper) getProjectReferenceFromSource(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
- return mapper.sourceToProjectReference[path]
-}
-
-func (mapper *projectReferenceFileMapper) getProjectReferenceFromOutputDts(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
- return mapper.outputDtsToProjectReference[path]
-}
-
-func (mapper *projectReferenceFileMapper) isSourceFromProjectReference(path tspath.Path) bool {
- return mapper.opts.canUseProjectReferenceSource() && mapper.getProjectReferenceFromSource(path) != nil
-}
-
-func (mapper *projectReferenceFileMapper) getCompilerOptionsForFile(file ast.HasFileName) *core.CompilerOptions {
- redirect := mapper.getRedirectParsedCommandLineForResolution(file)
- return module.GetCompilerOptionsWithRedirect(mapper.opts.Config.CompilerOptions(), redirect)
-}
-
-func (mapper *projectReferenceFileMapper) getRedirectParsedCommandLineForResolution(file ast.HasFileName) *tsoptions.ParsedCommandLine {
- redirect, _ := mapper.getRedirectForResolution(file)
- return redirect
-}
-
-func (mapper *projectReferenceFileMapper) getRedirectForResolution(file ast.HasFileName) (*tsoptions.ParsedCommandLine, string) {
- path := file.Path()
- // Check if outputdts of source file from project reference
- output := mapper.getProjectReferenceFromSource(path)
- if output != nil {
- return output.Resolved, output.Source
- }
-
- // Source file from project reference
- resultFromDts := mapper.getProjectReferenceFromOutputDts(path)
- if resultFromDts != nil {
- return resultFromDts.Resolved, resultFromDts.Source
- }
-
- realpathDtsToSource := mapper.getSourceToDtsIfSymlink(file)
- if realpathDtsToSource != nil {
- return realpathDtsToSource.Resolved, realpathDtsToSource.Source
- }
- return nil, file.FileName()
-}
-
-func (mapper *projectReferenceFileMapper) getResolvedReferenceFor(path tspath.Path) (*tsoptions.ParsedCommandLine, bool) {
- config, ok := mapper.configToProjectReference[path]
- return config, ok
-}
-
-func (mapper *projectReferenceFileMapper) forEachResolvedProjectReference(
- fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
-) {
- if mapper.opts.Config.ConfigFile == nil {
- return
- }
- seenRef := collections.NewSetWithSizeHint[tspath.Path](len(mapper.referencesInConfigFile))
- seenRef.Add(mapper.opts.Config.ConfigFile.SourceFile.Path())
- refs := mapper.referencesInConfigFile[mapper.opts.Config.ConfigFile.SourceFile.Path()]
- mapper.forEachResolvedReferenceWorker(refs, fn, mapper.opts.Config, seenRef)
-}
-
-func (mapper *projectReferenceFileMapper) forEachResolvedReferenceWorker(
- references []tspath.Path,
- fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
- parent *tsoptions.ParsedCommandLine,
- seenRef *collections.Set[tspath.Path],
-) {
- for index, path := range references {
- if !seenRef.AddIfAbsent(path) {
- continue
- }
- config, _ := mapper.configToProjectReference[path]
- fn(path, config, parent, index)
- mapper.forEachResolvedReferenceWorker(mapper.referencesInConfigFile[path], fn, config, seenRef)
- }
-}
-
-func (mapper *projectReferenceFileMapper) getSourceToDtsIfSymlink(file ast.HasFileName) *tsoptions.SourceOutputAndProjectReference {
- // If preserveSymlinks is true, module resolution wont jump the symlink
- // but the resolved real path may be the .d.ts from project reference
- // Note:: Currently we try the real path only if the
- // file is from node_modules to avoid having to run real path on all file paths
- path := file.Path()
- realpathDtsToSource, ok := mapper.realpathDtsToSource.Load(path)
- if ok {
- return realpathDtsToSource
- }
- if mapper.loader != nil && mapper.opts.Config.CompilerOptions().PreserveSymlinks == core.TSTrue {
- fileName := file.FileName()
- if !strings.Contains(fileName, "/node_modules/") {
- mapper.realpathDtsToSource.Store(path, nil)
- } else {
- realDeclarationPath := mapper.loader.toPath(mapper.host.FS().Realpath(fileName))
- if realDeclarationPath == path {
- mapper.realpathDtsToSource.Store(path, nil)
- } else {
- realpathDtsToSource := mapper.getProjectReferenceFromOutputDts(realDeclarationPath)
- if realpathDtsToSource != nil {
- mapper.realpathDtsToSource.Store(path, realpathDtsToSource)
- return realpathDtsToSource
- }
- mapper.realpathDtsToSource.Store(path, nil)
- }
- }
- }
- return nil
-}
diff --git a/kitcom/internal/tsgo/compiler/projectreferenceparser.go b/kitcom/internal/tsgo/compiler/projectreferenceparser.go
deleted file mode 100644
index 98d43ed..0000000
--- a/kitcom/internal/tsgo/compiler/projectreferenceparser.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package compiler
-
-import (
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
- "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
-)
-
-type projectReferenceParseTask struct {
- configName string
- resolved *tsoptions.ParsedCommandLine
- subTasks []*projectReferenceParseTask
-}
-
-func (t *projectReferenceParseTask) parse(projectReferenceParser *projectReferenceParser) {
- t.resolved = projectReferenceParser.loader.opts.Host.GetResolvedProjectReference(t.configName, projectReferenceParser.loader.toPath(t.configName))
- if t.resolved == nil {
- return
- }
- t.resolved.ParseInputOutputNames()
- if subReferences := t.resolved.ResolvedProjectReferencePaths(); len(subReferences) > 0 {
- t.subTasks = createProjectReferenceParseTasks(subReferences)
- }
-}
-
-func createProjectReferenceParseTasks(projectReferences []string) []*projectReferenceParseTask {
- return core.Map(projectReferences, func(configName string) *projectReferenceParseTask {
- return &projectReferenceParseTask{
- configName: configName,
- }
- })
-}
-
-type projectReferenceParser struct {
- loader *fileLoader
- wg core.WorkGroup
- tasksByFileName collections.SyncMap[tspath.Path, *projectReferenceParseTask]
-}
-
-func (p *projectReferenceParser) parse(tasks []*projectReferenceParseTask) {
- p.loader.projectReferenceFileMapper.loader = p.loader
- p.start(tasks)
- p.wg.RunAndWait()
- p.initMapper(tasks)
-}
-
-func (p *projectReferenceParser) start(tasks []*projectReferenceParseTask) {
- for i, task := range tasks {
- path := p.loader.toPath(task.configName)
- if loadedTask, loaded := p.tasksByFileName.LoadOrStore(path, task); loaded {
- // dedup tasks to ensure correct file order, regardless of which task would be started first
- tasks[i] = loadedTask
- } else {
- p.wg.Queue(func() {
- task.parse(p)
- p.start(task.subTasks)
- })
- }
- }
-}
-
-func (p *projectReferenceParser) initMapper(tasks []*projectReferenceParseTask) {
- totalReferences := p.tasksByFileName.Size() + 1
- p.loader.projectReferenceFileMapper.configToProjectReference = make(map[tspath.Path]*tsoptions.ParsedCommandLine, totalReferences)
- p.loader.projectReferenceFileMapper.referencesInConfigFile = make(map[tspath.Path][]tspath.Path, totalReferences)
- p.loader.projectReferenceFileMapper.sourceToProjectReference = make(map[tspath.Path]*tsoptions.SourceOutputAndProjectReference)
- p.loader.projectReferenceFileMapper.outputDtsToProjectReference = make(map[tspath.Path]*tsoptions.SourceOutputAndProjectReference)
- p.loader.projectReferenceFileMapper.referencesInConfigFile[p.loader.opts.Config.ConfigFile.SourceFile.Path()] = p.initMapperWorker(tasks, &collections.Set[*projectReferenceParseTask]{})
- if p.loader.projectReferenceFileMapper.opts.canUseProjectReferenceSource() && len(p.loader.projectReferenceFileMapper.outputDtsToProjectReference) != 0 {
- p.loader.projectReferenceFileMapper.host = newProjectReferenceDtsFakingHost(p.loader)
- }
-}
-
-func (p *projectReferenceParser) initMapperWorker(tasks []*projectReferenceParseTask, seen *collections.Set[*projectReferenceParseTask]) []tspath.Path {
- if len(tasks) == 0 {
- return nil
- }
- results := make([]tspath.Path, 0, len(tasks))
- for _, task := range tasks {
- path := p.loader.toPath(task.configName)
- results = append(results, path)
- // ensure we only walk each task once
- if !seen.AddIfAbsent(task) {
- continue
- }
- var referencesInConfig []tspath.Path
- referencesInConfig = p.initMapperWorker(task.subTasks, seen)
- p.loader.projectReferenceFileMapper.configToProjectReference[path] = task.resolved
- p.loader.projectReferenceFileMapper.referencesInConfigFile[path] = referencesInConfig
- if task.resolved == nil || p.loader.projectReferenceFileMapper.opts.Config.ConfigFile == task.resolved.ConfigFile {
- continue
- }
- for key, value := range task.resolved.SourceToProjectReference() {
- p.loader.projectReferenceFileMapper.sourceToProjectReference[key] = value
- }
- for key, value := range task.resolved.OutputDtsToProjectReference() {
- p.loader.projectReferenceFileMapper.outputDtsToProjectReference[key] = value
- }
- if p.loader.projectReferenceFileMapper.opts.canUseProjectReferenceSource() {
- declDir := task.resolved.CompilerOptions().DeclarationDir
- if declDir == "" {
- declDir = task.resolved.CompilerOptions().OutDir
- }
- if declDir != "" {
- p.loader.dtsDirectories.Add(p.loader.toPath(declDir))
- }
- }
- }
- return results
-}