Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add moduleDetection compiler flag to allow for changing how modules are parsed #47495

Merged
merged 10 commits into from
Mar 11, 2022
2 changes: 1 addition & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,7 @@ namespace ts {
affectsModuleResolution: true,
description: Diagnostics.Control_what_method_is_used_to_detect_module_format_JS_files,
category: Diagnostics.Language_and_Environment,
defaultValueDescription: Diagnostics.auto_Colon_Assume_jsx_containing_under_react_jsx_or_esm_mode_under_module_Colon_node12_files_are_modules_along_with_files_with_imports_exports_or_import_meta,
defaultValueDescription: Diagnostics.auto_Colon_Treat_files_with_imports_exports_imporpt_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node12_as_modules,
}
];

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1453,7 +1453,7 @@
"category": "Message",
"code": 1475
},
"\"auto\": Assume jsx-containing (under react-jsx) or esm mode (under module: node12+) files are modules, along with files with imports, exports, or import.meta.": {
"\"auto\": Treat files with imports, exports, imporpt.meta, jsx (with jsx: react-jsx), or esm format (with module: node12+) as modules.": {
weswigham marked this conversation as resolved.
Show resolved Hide resolved
"category": "Message",
"code": 1476
},
Expand Down
13 changes: 9 additions & 4 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,14 +703,19 @@ namespace ts {
let result: SourceFile;

perfLogger.logStartParseSourceFile(fileName);
const languageVersion = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions;
const {
languageVersion,
setExternalModuleIndicator: overrideSetExternalModuleIndicator,
impliedNodeFormat: format
} = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions);
if (languageVersion === ScriptTarget.JSON) {
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop);
}
else {
const overrideSetExternalModuleIndicator = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.setExternalModuleIndicator : undefined;
const format = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined;
const setIndicator = format !== undefined ? (file: SourceFile) => (file.impliedNodeFormat = format, void (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file)) : overrideSetExternalModuleIndicator;
const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => {
file.impliedNodeFormat = format;
return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file);
};
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator);
}
perfLogger.logStopParseSourceFile();
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6211,12 +6211,13 @@ namespace ts {
* Unfortunately, there's no `NodeFlag` space to do the same for JSX.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be? (there might not be any NodeFlags left in any case)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bails on the first JSX tag you find in a JSX tag, which is usually almost instantly, so.... probably not? Still, I think node.transformFlags & TransformFlags.ContainsJsx probably already tracks the same thing and post-node-factory change should always be set, so... I'll try that out for narrowing the search.

*/
function walkTreeForJSXTags(node: Node): Node | undefined {
sandersn marked this conversation as resolved.
Show resolved Hide resolved
if (!(node.transformFlags & TransformFlags.ContainsJsx)) return undefined;
return isJsxOpeningLikeElement(node) || isJsxFragment(node) ? node : forEachChild(node, walkTreeForJSXTags);
}

function isFileModuleFromUsingJSXTag(file: SourceFile): Node | undefined {
// Excludes declaration files - they still require an explicit `export {}` or the like
// for back compat purposes. (not that declaration files should contian JSX tags!)
// for back compat purposes. (not that declaration files should contain JSX tags!)
return !file.isDeclarationFile ? walkTreeForJSXTags(file) : undefined;
}

Expand All @@ -6235,10 +6236,10 @@ namespace ts {
switch (getEmitModuleDetectionKind(options)) {
case ModuleDetectionKind.Force:
// All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule
return (file: SourceFile) => void (file.externalModuleIndicator = !file.isDeclarationFile || isFileProbablyExternalModule(file));
return (file: SourceFile) => { file.externalModuleIndicator = !file.isDeclarationFile || isFileProbablyExternalModule(file); };
case ModuleDetectionKind.Legacy:
// Files are modules if they have imports, exports, or import.meta
return (file: SourceFile) => void (file.externalModuleIndicator = isFileProbablyExternalModule(file));
return (file: SourceFile) => { file.externalModuleIndicator = isFileProbablyExternalModule(file); };
case ModuleDetectionKind.Auto:
// If module is nodenext or node12, all esm format files are modules
// If jsx is react-jsx or react-jsxdev then jsx tags force module-ness
Expand Down
10 changes: 9 additions & 1 deletion src/services/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ namespace ts {

// if jsx is specified then treat file as .tsx
const inputFileName = transpileOptions.fileName || (transpileOptions.compilerOptions && transpileOptions.compilerOptions.jsx ? "module.tsx" : "module.ts");
const sourceFile = createSourceFile(inputFileName, input, { languageVersion: getEmitScriptTarget(options), impliedNodeFormat: getImpliedNodeFormatForFile(toPath(inputFileName, "", compilerHost.getCanonicalFileName), /*cache*/ undefined, compilerHost, options), setExternalModuleIndicator: getSetExternalModuleIndicator(options) });
const sourceFile = createSourceFile(
inputFileName,
input,
{
languageVersion: getEmitScriptTarget(options),
impliedNodeFormat: getImpliedNodeFormatForFile(toPath(inputFileName, "", compilerHost.getCanonicalFileName), /*cache*/ undefined, compilerHost, options),
setExternalModuleIndicator: getSetExternalModuleIndicator(options)
}
);
if (transpileOptions.moduleName) {
sourceFile.moduleName = transpileOptions.moduleName;
}
Expand Down
9 changes: 6 additions & 3 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,15 @@ namespace ts {
/*
* LS host can optionally implement these methods to support completions for module specifiers.
* Without these methods, only completions for ambient modules will be provided.
*
* `readFile` and `fileExists` are now _required_ to properly acquire and setup source files under module: node12+ modes.
*/
readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[];
readFile(path: string, encoding?: string): string | undefined;
realpath?(path: string): string;

/*
* Unlike `realpath and `readDirectory`, `readFile` and `fileExists` are now _required_
* to properly acquire and setup source files under module: node12+ modes.
*/
readFile(path: string, encoding?: string): string | undefined;
fileExists(path: string): boolean;

/*
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5731,8 +5731,8 @@ declare namespace ts {
error?(s: string): void;
useCaseSensitiveFileNames?(): boolean;
readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[];
readFile(path: string, encoding?: string): string | undefined;
realpath?(path: string): string;
readFile(path: string, encoding?: string): string | undefined;
fileExists(path: string): boolean;
getTypeRootsVersion?(): number;
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[];
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5731,8 +5731,8 @@ declare namespace ts {
error?(s: string): void;
useCaseSensitiveFileNames?(): boolean;
readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[];
readFile(path: string, encoding?: string): string | undefined;
realpath?(path: string): string;
readFile(path: string, encoding?: string): string | undefined;
fileExists(path: string): boolean;
getTypeRootsVersion?(): number;
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[];
Expand Down