remove unused packages
This commit is contained in:
parent
b1f5661baf
commit
2ba4cf4f1e
@ -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() {}
|
||||
@ -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)
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
// Package compiler implements the TypeScript compiler.
|
||||
package compiler
|
||||
@ -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
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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: "/// <reference path='c:/dev/src2/a/5.ts' />\n/// <reference path='c:/dev/src2/a/10.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/5.ts", contents: "/// <reference path='4.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/4.ts", contents: "/// <reference path='b/3.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/3.ts", contents: "/// <reference path='2.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/2.ts", contents: "/// <reference path='c/1.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/c/1.ts", contents: "console.log('hello');"},
|
||||
{fileName: "c:/dev/src2/a/10.ts", contents: "/// <reference path='b/c/d/9.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/c/d/9.ts", contents: "/// <reference path='e/8.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/c/d/e/8.ts", contents: "/// <reference path='7.ts' />"},
|
||||
{fileName: "c:/dev/src2/a/b/c/d/e/7.ts", contents: "/// <reference path='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: "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)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user