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