Skip to content

Commit e7fd76d

Browse files
committed
Report project reference diagnostics
1 parent 57f8f04 commit e7fd76d

File tree

10 files changed

+94
-31
lines changed

10 files changed

+94
-31
lines changed

internal/compiler/emitHost.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ func (host *emitHost) UseCaseSensitiveFileNames() bool {
108108
}
109109

110110
func (host *emitHost) IsEmitBlocked(file string) bool {
111-
// !!!
112-
return false
111+
return host.program.IsEmitBlocked(file)
113112
}
114113

115114
func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool) error {

internal/compiler/program.go

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (p *Program) GetParseFileRedirect(fileName string) string {
128128
}
129129

130130
func (p *Program) ForEachResolvedProjectReference(
131-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
131+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
132132
) {
133133
p.projectReferenceFileMapper.forEachResolvedProjectReference(fn)
134134
}
@@ -544,9 +544,7 @@ func (p *Program) verifyCompilerOptions() {
544544
}
545545
}
546546

547-
// !!! Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified
548-
549-
// !!! verifyProjectReferences
547+
p.verifyProjectReferences()
550548

551549
if options.Composite.IsTrue() {
552550
var rootPaths collections.Set[tspath.Path]
@@ -810,12 +808,13 @@ func (p *Program) verifyCompilerOptions() {
810808
}
811809

812810
outputpaths.ForEachEmittedFile(p, options, func(emitFileNames *outputpaths.OutputPaths, sourceFile *ast.SourceFile) bool {
813-
if !options.EmitDeclarationOnly.IsTrue() {
814-
verifyEmitFilePath(emitFileNames.JsFilePath())
815-
}
811+
verifyEmitFilePath(emitFileNames.JsFilePath())
812+
verifyEmitFilePath(emitFileNames.SourceMapFilePath())
816813
verifyEmitFilePath(emitFileNames.DeclarationFilePath())
814+
verifyEmitFilePath(emitFileNames.DeclarationMapPath())
817815
return false
818816
}, p.getSourceFilesToEmit(nil, false), false)
817+
verifyEmitFilePath(p.opts.Config.GetBuildInfoFileName())
819818
}
820819
}
821820

@@ -824,6 +823,59 @@ func (p *Program) blockEmittingOfFile(emitFileName string, diag *ast.Diagnostic)
824823
p.programDiagnostics = append(p.programDiagnostics, diag)
825824
}
826825

826+
func (p *Program) IsEmitBlocked(emitFileName string) bool {
827+
return p.hasEmitBlockingDiagnostics.Has(p.toPath(emitFileName))
828+
}
829+
830+
func (p *Program) verifyProjectReferences() {
831+
buildInfoFileName := core.IfElse(!p.Options().SuppressOutputPathCheck.IsTrue(), p.opts.Config.GetBuildInfoFileName(), "")
832+
createDiagnosticForReference := func(config *tsoptions.ParsedCommandLine, index int, message *diagnostics.Message, args ...any) {
833+
var sourceFile *ast.SourceFile
834+
if config.ConfigFile != nil {
835+
sourceFile = config.ConfigFile.SourceFile
836+
}
837+
diag := tsoptions.ForEachTsConfigPropArray(sourceFile, "references", func(property *ast.PropertyAssignment) *ast.Diagnostic {
838+
if ast.IsArrayLiteralExpression(property.Initializer) {
839+
value := property.Initializer.AsArrayLiteralExpression().Elements.Nodes
840+
if len(value) > index {
841+
return tsoptions.CreateDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, value[index], message, args...)
842+
}
843+
}
844+
return nil
845+
})
846+
if diag == nil {
847+
diag = ast.NewCompilerDiagnostic(message, args...)
848+
}
849+
p.programDiagnostics = append(p.programDiagnostics, diag)
850+
}
851+
852+
p.ForEachResolvedProjectReference(func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
853+
// Implementation goes here
854+
ref := parent.ProjectReferences()[index]
855+
// !!! Deprecated in 5.0 and removed since 5.5
856+
// verifyRemovedProjectReference(ref, parent, index);
857+
if config == nil {
858+
createDiagnosticForReference(parent, index, diagnostics.File_0_not_found, ref.Path)
859+
return
860+
}
861+
refOptions := config.CompilerOptions()
862+
if !refOptions.Composite.IsTrue() || refOptions.NoEmit.IsTrue() {
863+
if len(config.FileNames()) > 0 {
864+
if !refOptions.Composite.IsTrue() {
865+
createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.Path)
866+
}
867+
if refOptions.NoEmit.IsTrue() {
868+
createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_may_not_disable_emit, ref.Path)
869+
}
870+
}
871+
}
872+
if buildInfoFileName != "" && buildInfoFileName == config.GetBuildInfoFileName() {
873+
createDiagnosticForReference(parent, index, diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoFileName, ref.Path)
874+
p.hasEmitBlockingDiagnostics.Add(p.toPath(buildInfoFileName))
875+
}
876+
})
877+
}
878+
827879
func hasZeroOrOneAsteriskCharacter(str string) bool {
828880
seenAsterisk := false
829881
for _, ch := range str {

internal/compiler/projectreferencefilemapper.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,23 +140,30 @@ func (mapper *projectReferenceFileMapper) getResolvedReferenceFor(path tspath.Pa
140140
}
141141

142142
func (mapper *projectReferenceFileMapper) forEachResolvedProjectReference(
143-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
143+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
144144
) {
145145
if mapper.opts.Config.ConfigFile == nil {
146146
return
147147
}
148+
seenRef := collections.NewSetWithSizeHint[tspath.Path](len(mapper.referencesInConfigFile))
149+
seenRef.Add(mapper.opts.Config.ConfigFile.SourceFile.Path())
148150
refs := mapper.referencesInConfigFile[mapper.opts.Config.ConfigFile.SourceFile.Path()]
149-
mapper.forEachResolvedReferenceWorker(refs, fn)
151+
mapper.forEachResolvedReferenceWorker(refs, fn, mapper.opts.Config, seenRef)
150152
}
151153

152154
func (mapper *projectReferenceFileMapper) forEachResolvedReferenceWorker(
153155
references []tspath.Path,
154-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
156+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
157+
parent *tsoptions.ParsedCommandLine,
158+
seenRef *collections.Set[tspath.Path],
155159
) {
156-
for _, path := range references {
160+
for index, path := range references {
161+
if !seenRef.AddIfAbsent(path) {
162+
continue
163+
}
157164
config, _ := mapper.configToProjectReference[path]
158-
fn(path, config)
159-
mapper.forEachResolvedReferenceWorker(mapper.referencesInConfigFile[path], fn)
165+
fn(path, config, parent, index)
166+
mapper.forEachResolvedReferenceWorker(mapper.referencesInConfigFile[path], fn, config, seenRef)
160167
}
161168
}
162169

internal/execute/tscprojectreferences_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
func TestProjectReferences(t *testing.T) {
1010
t.Parallel()
1111
cases := []tscInput{
12-
// !!! sheetal todo verifyCompilerOptions - check for noEmit
1312
{
1413
subScenario: "when project references composite project with noEmit",
1514
files: FileMap{
@@ -76,7 +75,6 @@ func TestProjectReferences(t *testing.T) {
7675
commandLineArgs: []string{"--p", "project"},
7776
},
7877
{
79-
// !!! sheetal verifyProjectReferences - checks this
8078
subScenario: "when project contains invalid project reference",
8179
files: FileMap{
8280
"/home/src/workspaces/solution/project/index.ts": `export const x = 10;`,

internal/incremental/incremental.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package incremental
33
import (
44
"github.com/go-json-experiment/json"
55
"github.com/microsoft/typescript-go/internal/compiler"
6-
"github.com/microsoft/typescript-go/internal/outputpaths"
76
"github.com/microsoft/typescript-go/internal/tsoptions"
8-
"github.com/microsoft/typescript-go/internal/tspath"
97
)
108

119
type BuildInfoReader interface {
@@ -39,10 +37,7 @@ func NewBuildInfoReader(
3937
}
4038

4139
func ReadBuildInfoProgram(config *tsoptions.ParsedCommandLine, reader BuildInfoReader) *Program {
42-
buildInfoFileName := outputpaths.GetBuildInfoFileName(config.CompilerOptions(), tspath.ComparePathsOptions{
43-
CurrentDirectory: config.GetCurrentDirectory(),
44-
UseCaseSensitiveFileNames: config.UseCaseSensitiveFileNames(),
45-
})
40+
buildInfoFileName := config.GetBuildInfoFileName()
4641
if buildInfoFileName == "" {
4742
return nil
4843
}

internal/incremental/program.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (p *Program) emitBuildInfo(ctx context.Context, options compiler.EmitOption
240240
CurrentDirectory: p.program.GetCurrentDirectory(),
241241
UseCaseSensitiveFileNames: p.program.UseCaseSensitiveFileNames(),
242242
})
243-
if buildInfoFileName == "" {
243+
if buildInfoFileName == "" || p.program.IsEmitBlocked(buildInfoFileName) {
244244
return nil
245245
}
246246
if p.snapshot.hasErrors == core.TSUnknown {

internal/project/project.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ func (p *Project) updateGraph() (*compiler.Program, bool) {
533533
}
534534
}
535535

536-
oldProgram.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine) {
536+
oldProgram.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
537537
if _, ok := p.program.GetResolvedProjectReferenceFor(path); !ok {
538538
p.host.ConfigFileRegistry().releaseConfig(path, p)
539539
}
@@ -1096,7 +1096,7 @@ func (p *Project) Close() {
10961096
// Detach script info if its not root or is root of non inferred project
10971097
p.detachScriptInfoIfNotInferredRoot(sourceFile.Path())
10981098
}
1099-
p.program.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine) {
1099+
p.program.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
11001100
p.host.ConfigFileRegistry().releaseConfig(path, p)
11011101
})
11021102
if p.kind == KindConfigured {

internal/tsoptions/parsedcommandline.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ func (p *ParsedCommandLine) CompilerOptions() *core.CompilerOptions {
179179
return p.ParsedConfig.CompilerOptions
180180
}
181181

182+
func (p *ParsedCommandLine) GetBuildInfoFileName() string {
183+
return outputpaths.GetBuildInfoFileName(p.CompilerOptions(), p.comparePathsOptions)
184+
}
185+
182186
func (p *ParsedCommandLine) SetTypeAcquisition(o *core.TypeAcquisition) {
183187
p.ParsedConfig.TypeAcquisition = o
184188
}

testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ export const x = 10;
1111
}
1212

1313
tsgo --p project
14-
ExitStatus:: Success
14+
ExitStatus:: DiagnosticsPresent_OutputsGenerated
1515
Output::
16+
project/tsconfig.json:3:9 - error TS6053: File '/home/src/workspaces/solution/utils' not found.
17+
18+
3 { "path": "../utils" },
19+
   ~~~~~~~~~~~~~~~~~~~~~~
20+
21+
22+
Found 1 error in project/tsconfig.json:3
23+
1624
//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib*
1725
/// <reference no-default-lib="true"/>
1826
interface Boolean {}

testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ export const x = 10;
2222
tsgo --p project
2323
ExitStatus:: DiagnosticsPresent_OutputsGenerated
2424
Output::
25-
[96mproject/index.ts[0m:[93m1[0m:[93m19[0m - [91merror[0m[90m TS6305: [0mOutput file '/home/src/workspaces/solution/utils/index.d.ts' has not been built from source file '/home/src/workspaces/solution/utils/index.ts'.
25+
[96mproject/tsconfig.json[0m:[93m3[0m:[93m9[0m - [91merror[0m[90m TS6310: [0mReferenced project '/home/src/workspaces/solution/utils' may not disable emit.
2626

27-
[7m1[0m import { x } from "../utils";
28-
[7m [0m [91m ~~~~~~~~~~[0m
27+
[7m3[0m { "path": "../utils" },
28+
[7m [0m [91m ~~~~~~~~~~~~~~~~~~~~~~[0m
2929

3030

31-
Found 1 error in project/index.ts[90m:1[0m
31+
Found 1 error in project/tsconfig.json[90m:3[0m
3232

3333
//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib*
3434
/// <reference no-default-lib="true"/>

0 commit comments

Comments
 (0)