Skip to content

Commit 5021088

Browse files
committed
Handle synthetic imports
1 parent f414531 commit 5021088

File tree

8 files changed

+310
-86
lines changed

8 files changed

+310
-86
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,22 @@
13321332
"category": "Message",
13331333
"code": 1425
13341334
},
1335+
"Imported via {0} from file '{1}' to import 'importHelpers' as specified in compilerOptions": {
1336+
"category": "Message",
1337+
"code": 1426
1338+
},
1339+
"Imported via {0} from file '{1}' with packageId '{2}' to import 'importHelpers' as specified in compilerOptions": {
1340+
"category": "Message",
1341+
"code": 1427
1342+
},
1343+
"Imported via {0} from file '{1}' to import 'jsx' and 'jsxs' factory functions": {
1344+
"category": "Message",
1345+
"code": 1428
1346+
},
1347+
"Imported via {0} from file '{1}' with packageId '{2}' to import 'jsx' and 'jsxs' factory functions": {
1348+
"category": "Message",
1349+
"code": 1429
1350+
},
13351351
"The types of '{0}' are incompatible between these types.": {
13361352
"category": "Error",
13371353
"code": 2200

src/compiler/program.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -596,16 +596,37 @@ namespace ts {
596596
}
597597

598598
/*@internal*/
599-
export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile) {
600-
const file = Debug.assertDefined(getSourceFileByPath(ref.file));
599+
export interface ReferenceFileLocation {
600+
file: SourceFile;
601+
pos: number;
602+
end: number;
603+
packageId: PackageId | undefined;
604+
}
605+
606+
/*@internal*/
607+
export interface SyntheticReferenceFileLocation {
608+
file: SourceFile;
609+
packageId: PackageId | undefined;
610+
text: string;
611+
}
612+
613+
/*@internal*/
614+
export function isReferenceFileLocation(location: ReferenceFileLocation | SyntheticReferenceFileLocation): location is ReferenceFileLocation {
615+
return (location as ReferenceFileLocation).pos !== undefined;
616+
}
617+
618+
/*@internal*/
619+
export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation {
620+
const file = Debug.checkDefined(getSourceFileByPath(ref.file));
601621
const { kind, index } = ref;
602-
let pos: number, end: number, packageId: PackageId | undefined;
622+
let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined;
603623
switch (kind) {
604624
case FileIncludeKind.Import:
605625
const importLiteral = getModuleNameStringLiteralAt(file, index);
626+
packageId = file.resolvedModules?.get(importLiteral.text)?.packageId;
627+
if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text };
606628
pos = skipTrivia(file.text, importLiteral.pos);
607629
end = importLiteral.end;
608-
packageId = file.resolvedModules?.get(importLiteral.text)?.packageId;
609630
break;
610631
case FileIncludeKind.ReferenceFile:
611632
({ pos, end } = file.referencedFiles[index]);
@@ -1077,8 +1098,8 @@ namespace ts {
10771098
case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
10781099
return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray));
10791100
case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic:
1080-
const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason);
1081-
return programDiagnostics.add(createFileDiagnostic(file, pos, end - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
1101+
const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation;
1102+
return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
10821103
default:
10831104
Debug.assertNever(diagnostic);
10841105
}
@@ -3321,7 +3342,7 @@ namespace ts {
33213342
const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
33223343
const redirectInfo = file && explainIfFileIsRedirect(file);
33233344
const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray);
3324-
return location ?
3345+
return location && isReferenceFileLocation(location) ?
33253346
createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
33263347
createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
33273348

@@ -3355,7 +3376,7 @@ namespace ts {
33553376

33563377
function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
33573378
if (isReferencedFile(reason)) {
3358-
const { file: referencedFromFile, pos, end } = getReferencedFileLocation(getSourceFileByPath, reason);
3379+
const referenceLocation = getReferencedFileLocation(getSourceFileByPath, reason);
33593380
let message: DiagnosticMessage;
33603381
switch (reason.kind) {
33613382
case FileIncludeKind.Import:
@@ -3373,12 +3394,12 @@ namespace ts {
33733394
default:
33743395
Debug.assertNever(reason);
33753396
}
3376-
return createFileDiagnostic(
3377-
referencedFromFile,
3378-
pos,
3379-
end - pos,
3397+
return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
3398+
referenceLocation.file,
3399+
referenceLocation.pos,
3400+
referenceLocation.end - referenceLocation.pos,
33803401
message,
3381-
);
3402+
) : undefined;
33823403
}
33833404

33843405
if (!options.configFile) return undefined;

src/compiler/watch.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,26 +186,39 @@ namespace ts {
186186
export function fileIncludeReasonToDiagnostics(program: Program, reason: FileIncludeReason, fileNameConvertor?: (fileName: string) => string,): DiagnosticMessageChain {
187187
const options = program.getCompilerOptions();
188188
if (isReferencedFile(reason)) {
189-
const { file: referecedFromFile, pos, end, packageId } = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason);
190-
const referenceText = referecedFromFile.text.substring(pos, end);
189+
const referenceLocation = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason);
190+
const referenceText = isReferenceFileLocation(referenceLocation) ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) : `"${referenceLocation.text}"`;
191191
let message: DiagnosticMessage;
192+
Debug.assert(isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, "Only synthetic references are imports");
192193
switch (reason.kind) {
193194
case FileIncludeKind.Import:
194-
message = packageId ?
195-
Diagnostics.Imported_via_0_from_file_1_with_packageId_2 :
196-
Diagnostics.Imported_via_0_from_file_1;
195+
if (isReferenceFileLocation(referenceLocation)) {
196+
message = referenceLocation.packageId ?
197+
Diagnostics.Imported_via_0_from_file_1_with_packageId_2 :
198+
Diagnostics.Imported_via_0_from_file_1;
199+
}
200+
else if (referenceLocation.text === externalHelpersModuleNameText) {
201+
message = referenceLocation.packageId ?
202+
Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions :
203+
Diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions;
204+
}
205+
else {
206+
message = referenceLocation.packageId ?
207+
Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions :
208+
Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions;
209+
}
197210
break;
198211
case FileIncludeKind.ReferenceFile:
199-
Debug.assert(!packageId);
212+
Debug.assert(!referenceLocation.packageId);
200213
message = Diagnostics.Referenced_via_0_from_file_1;
201214
break;
202215
case FileIncludeKind.TypeReferenceDirective:
203-
message = packageId ?
216+
message = referenceLocation.packageId ?
204217
Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 :
205218
Diagnostics.Type_library_referenced_via_0_from_file_1;
206219
break;
207220
case FileIncludeKind.LibReferenceDirective:
208-
Debug.assert(!packageId);
221+
Debug.assert(!referenceLocation.packageId);
209222
message = Diagnostics.Library_referenced_via_0_from_file_1;
210223
break;
211224
default:
@@ -215,8 +228,8 @@ namespace ts {
215228
/*details*/ undefined,
216229
message,
217230
referenceText,
218-
toFileName(referecedFromFile, fileNameConvertor),
219-
packageId && packageIdToString(packageId)
231+
toFileName(referenceLocation.file, fileNameConvertor),
232+
referenceLocation.packageId && packageIdToString(referenceLocation.packageId)
220233
);
221234
}
222235
switch (reason.kind) {

src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,45 @@ namespace ts.tscWatch {
7979
}
8080
],
8181
});
82+
83+
verifyTscWatch({
84+
scenario: "forceConsistentCasingInFileNames",
85+
subScenario: "jsxImportSource option changed",
86+
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
87+
sys: () => createWatchedSystem([
88+
libFile,
89+
{
90+
path: `${projectRoot}/node_modules/react/Jsx-runtime/index.d.ts`,
91+
content: `export namespace JSX {
92+
interface Element {}
93+
interface IntrinsicElements {
94+
div: {
95+
propA?: boolean;
96+
};
97+
}
98+
}
99+
export function jsx(...args: any[]): void;
100+
export function jsxs(...args: any[]): void;
101+
export const Fragment: unique symbol;
102+
`,
103+
},
104+
{
105+
path: `${projectRoot}/node_modules/react/package.json`,
106+
content: JSON.stringify({ name: "react", version: "0.0.1" })
107+
},
108+
{
109+
path: `${projectRoot}/index.tsx`,
110+
content: `export const App = () => <div propA={true}></div>;`
111+
},
112+
{
113+
path: `${projectRoot}/tsconfig.json`,
114+
content: JSON.stringify({
115+
compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true },
116+
files: ["node_modules/react/Jsx-runtime/index.d.ts", "index.tsx"]
117+
})
118+
}
119+
], { currentDirectory: projectRoot }),
120+
changes: emptyArray,
121+
});
82122
});
83123
}

0 commit comments

Comments
 (0)