Skip to content

Commit

Permalink
Allow cross-project references to const enums in isolatedModules when…
Browse files Browse the repository at this point in the history
… referenced project has preserveConstEnums (#57914)
  • Loading branch information
andrewbranch authored Mar 27, 2024
1 parent fd388f7 commit b24b5c4
Show file tree
Hide file tree
Showing 7 changed files with 464 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39782,7 +39782,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (getIsolatedModules(compilerOptions)) {
Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum));
const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration;
if (constEnumDeclaration.flags & NodeFlags.Ambient && !isValidTypeOnlyAliasUseSite(node)) {
const redirect = host.getRedirectReferenceForResolutionFromSourceOfProject(getSourceFileOfNode(constEnumDeclaration).resolvedPath);
if (constEnumDeclaration.flags & NodeFlags.Ambient && !isValidTypeOnlyAliasUseSite(node) && (!redirect || !shouldPreserveConstEnums(redirect.commandLine.options))) {
error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
getResolvedProjectReferenceByPath,
forEachResolvedProjectReference,
isSourceOfProjectReferenceRedirect,
getRedirectReferenceForResolutionFromSourceOfProject,
emitBuildInfo,
fileExists,
readFile,
Expand Down
8 changes: 7 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4734,9 +4734,14 @@ export interface Program extends ScriptReferenceHost {
getProjectReferences(): readonly ProjectReference[] | undefined;
getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
/** @internal */ getProjectReferenceRedirect(fileName: string): string | undefined;
/** @internal */ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
/**
* @internal
* Get the referenced project if the file is input file from that reference project
*/
getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
/** @internal */ forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
/** @internal */ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
/** @internal */ getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
/** @internal */ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
/** @internal */ getBuildInfo?(): BuildInfo;
/** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
Expand Down Expand Up @@ -4853,6 +4858,7 @@ export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
getSourceFile(fileName: string): SourceFile | undefined;
getProjectReferenceRedirect(fileName: string): string | undefined;
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;

getResolvedModule(f: SourceFile, moduleName: string, mode: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined;
Expand Down
27 changes: 27 additions & 0 deletions src/testRunner/unittests/tsc/projectReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,31 @@ describe("unittests:: tsc:: projectReferences::", () => {
}),
commandLineArgs: ["--p", "src/project"],
});

verifyTsc({
scenario: "projectReferences",
subScenario: "referencing ambient const enum from referenced project with preserveConstEnums",
fs: () =>
loadProjectFromFiles({
"/src/utils/index.ts": "export const enum E { A = 1 }",
"/src/utils/index.d.ts": "export declare const enum E { A = 1 }",
"/src/utils/tsconfig.json": jsonToReadableText({
compilerOptions: {
composite: true,
declaration: true,
preserveConstEnums: true,
},
}),
"/src/project/index.ts": `import { E } from "../utils"; E.A;`,
"/src/project/tsconfig.json": jsonToReadableText({
compilerOptions: {
isolatedModules: true,
},
references: [
{ path: "../utils" },
],
}),
}),
commandLineArgs: ["--p", "src/project"],
});
});
29 changes: 29 additions & 0 deletions src/testRunner/unittests/tsserver/projectReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,35 @@ function foo() {
baselineTsserverLogs("projectReferences", "reusing d.ts files from composite and non composite projects", session);
});

it("referencing const enum from referenced project with preserveConstEnums", () => {
const projectLocation = `/user/username/projects/project`;
const utilsIndex: File = {
path: `${projectLocation}/src/utils/index.ts`,
content: "export const enum E { A = 1 }",
};
const utilsDeclaration: File = {
path: `${projectLocation}/src/utils/index.d.ts`,
content: "export declare const enum E { A = 1 }",
};
const utilsConfig: File = {
path: `${projectLocation}/src/utils/tsconfig.json`,
content: jsonToReadableText({ compilerOptions: { composite: true, declaration: true, preserveConstEnums: true } }),
};
const projectIndex: File = {
path: `${projectLocation}/src/project/index.ts`,
content: `import { E } from "../utils"; E.A;`,
};
const projectConfig: File = {
path: `${projectLocation}/src/project/tsconfig.json`,
content: jsonToReadableText({ compilerOptions: { isolatedModules: true }, references: [{ path: "../utils" }] }),
};
const host = createServerHost([libFile, utilsIndex, utilsDeclaration, utilsConfig, projectIndex, projectConfig]);
const session = new TestSession(host);
openFilesForSession([projectIndex], session);
verifyGetErrRequest({ session, files: [projectIndex] });
baselineTsserverLogs("projectReferences", `referencing const enum from referenced project with preserveConstEnums`, session);
});

describe("when references are monorepo like with symlinks", () => {
interface Packages {
bPackageJson: File;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
currentDirectory:: / useCaseSensitiveFileNames: false
Input::
//// [/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
declare const console: { log(msg: any): void; };

//// [/src/project/index.ts]
import { E } from "../utils"; E.A;

//// [/src/project/tsconfig.json]
{
"compilerOptions": {
"isolatedModules": true
},
"references": [
{
"path": "../utils"
}
]
}

//// [/src/utils/index.d.ts]
export declare const enum E { A = 1 }

//// [/src/utils/index.ts]
export const enum E { A = 1 }

//// [/src/utils/tsconfig.json]
{
"compilerOptions": {
"composite": true,
"declaration": true,
"preserveConstEnums": true
}
}



Output::
/lib/tsc --p src/project
exitCode:: ExitStatus.Success


//// [/src/project/index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = require("../utils");
utils_1.E.A;


Loading

0 comments on commit b24b5c4

Please sign in to comment.