Skip to content

Fix internal resolution error tracing #44

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

Merged
merged 6 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chilly-candles-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arethetypeswrong/core": patch
---

Fixed an issue where InternalResolutionError and UnexpectedModuleSyntax could be duplicated
5 changes: 5 additions & 0 deletions .changeset/curvy-masks-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arethetypeswrong/core": patch
---

Fixed an issue where InternalResolutionError was missing traces
5 changes: 5 additions & 0 deletions .changeset/twelve-feet-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arethetypeswrong/core": minor
---

Inlined `InternalResolutionErrorDetails` into `InternalResolutionError` and renamed the interface to `InternalResolutionErrorProblem` to match other problem interfaces
55 changes: 18 additions & 37 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@changesets/cli": "^2.26.1",
"@types/node": "^18.11.18",
"prettier": "^2.8.3",
"typescript": "^5.0.0-dev.20230207"
"typescript": "^5.1.3"
},
"volta": {
"node": "19.8.1"
Expand Down
30 changes: 30 additions & 0 deletions packages/cli/test/snapshots/@[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# @[email protected]

```
$ attw @[email protected]


⚠️ A require call resolved to an ESM JavaScript file, which is an error in Node and some bundlers. CommonJS consumers will need to use a dynamic import. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/CJSResolvesToESM.md

💀 Import failed to resolve to type declarations or JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/NoResolution.md

🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md


┌────────────────────┬───────────────────────────────────┬───────────────────────────────────┬───────────────────────────────────┐
│ │ "@ice/app" │ "@ice/app/types" │ "@ice/app/analyze" │
├────────────────────┼───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ node10 │ 🟢 │ 🟢 │ 💀 Resolution failed │
├────────────────────┼───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ node16 (from CJS) │ ⚠️ ESM (dynamic import only) │ ⚠️ ESM (dynamic import only) │ ⚠️ ESM (dynamic import only) │
│ │ 🥴 Internal resolution error │ 🥴 Internal resolution error │ │
├────────────────────┼───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ node16 (from ESM) │ 🥴 Internal resolution error │ 🥴 Internal resolution error │ 🟢 (ESM) │
├────────────────────┼───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ bundler │ 🟢 │ 🟢 │ 🟢 │
└────────────────────┴───────────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘


```

Exit code: 1
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@
"@andrewbranch/untar.js": "^1.0.0",
"fetch-ponyfill": "^7.1.0",
"fflate": "^0.7.4",
"typescript": "^5.0.0-dev.20230207",
"typescript": "^5.1.3",
"validate-npm-package-name": "^5.0.0"
},
"devDependencies": {
"@types/node": "^18.15.11",
"@types/ts-expose-internals": "npm:ts-expose-internals@4.9.4",
"@types/ts-expose-internals": "npm:ts-expose-internals@5.1.3",
"@types/validate-npm-package-name": "^4.0.0"
},
"volta": {
Expand Down
94 changes: 49 additions & 45 deletions packages/core/src/checks/resolutionBasedFileProblems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ export function getResolutionBasedFileProblems(
): ResolutionBasedFileProblem[] {
const result: ResolutionBasedFileProblem[] = [];
for (const resolutionOption of allResolutionOptions) {
const visibleFiles = Object.values(entrypointResolutions).flatMap((entrypoint) => {
const files = new Set<string>();
getResolutionKinds(resolutionOption).forEach((resolutionKind) => {
entrypoint.resolutions[resolutionKind].files?.forEach((file) => files.add(file));
if (entrypoint.resolutions[resolutionKind].implementationResolution) {
files.add(entrypoint.resolutions[resolutionKind].implementationResolution!.fileName);
}
});
return Array.from(files);
});
const visibleFiles = new Set(
Object.values(entrypointResolutions).flatMap((entrypoint) => {
const files = new Set<string>();
getResolutionKinds(resolutionOption).forEach((resolutionKind) => {
entrypoint.resolutions[resolutionKind].files?.forEach((file) => files.add(file));
if (entrypoint.resolutions[resolutionKind].implementationResolution) {
files.add(entrypoint.resolutions[resolutionKind].implementationResolution!.fileName);
}
});
return Array.from(files);
})
);

for (const fileName of visibleFiles) {
const sourceFile = host.getSourceFile(fileName, resolutionOption)!;
Expand All @@ -46,13 +48,11 @@ export function getResolutionBasedFileProblems(
kind: "InternalResolutionError",
resolutionOption,
fileName,
error: {
moduleSpecifier: reference,
pos: moduleSpecifier.pos,
end: moduleSpecifier.end,
resolutionMode,
trace: host.getTrace(resolutionOption, fileName, moduleSpecifier.text, resolutionMode)!,
},
moduleSpecifier: reference,
pos: moduleSpecifier.pos,
end: moduleSpecifier.end,
resolutionMode,
trace: host.getTrace(resolutionOption, fileName, moduleSpecifier.text, resolutionMode)!,
});
}
}
Expand All @@ -62,34 +62,38 @@ export function getResolutionBasedFileProblems(
// try to do a ts->js extension substitution and assume that's a
// visible JS file if it exists.
//
// TODO: this should maybe only be issued in node16
if (ts.hasJSFileExtension(fileName)) {
const expectedModuleKind = host.getModuleKindForFile(fileName, resolutionOption);
const syntaxImpliedModuleKind = sourceFile.externalModuleIndicator
? ts.ModuleKind.ESNext
: sourceFile.commonJsModuleIndicator
? ts.ModuleKind.CommonJS
: undefined;
if (
expectedModuleKind !== undefined &&
syntaxImpliedModuleKind !== undefined &&
expectedModuleKind.detectedKind !== syntaxImpliedModuleKind
) {
const syntax = sourceFile.externalModuleIndicator ?? sourceFile.commonJsModuleIndicator;
result.push({
kind: "UnexpectedModuleSyntax",
resolutionOption,
syntax: syntaxImpliedModuleKind,
fileName,
range:
typeof syntax === "object"
? {
pos: syntax.getStart(sourceFile),
end: syntax.end,
}
: undefined,
moduleKind: expectedModuleKind,
});
// Actually, we probably want to check the relative directory relationship
// between an entrypoint resolution and implementationResolution as the basis
// for looking for a JS file.
if (resolutionOption === "node16") {
if (ts.hasJSFileExtension(fileName)) {
const expectedModuleKind = host.getModuleKindForFile(fileName, resolutionOption);
const syntaxImpliedModuleKind = sourceFile.externalModuleIndicator
? ts.ModuleKind.ESNext
: sourceFile.commonJsModuleIndicator
? ts.ModuleKind.CommonJS
: undefined;
if (
expectedModuleKind !== undefined &&
syntaxImpliedModuleKind !== undefined &&
expectedModuleKind.detectedKind !== syntaxImpliedModuleKind
) {
const syntax = sourceFile.externalModuleIndicator ?? sourceFile.commonJsModuleIndicator;
result.push({
kind: "UnexpectedModuleSyntax",
resolutionOption,
syntax: syntaxImpliedModuleKind,
fileName,
range:
typeof syntax === "object"
? {
pos: syntax.getStart(sourceFile),
end: syntax.end,
}
: undefined,
moduleKind: expectedModuleKind,
});
}
}
}
}
Expand Down
26 changes: 22 additions & 4 deletions packages/core/src/multiCompilerHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export function createMultiCompilerHost(fs: FS): MultiCompilerHost {
traceResolution: true,
},
bundler: {
// @ts-expect-error
moduleResolution: ts.ModuleResolutionKind.Bundler,
module: ts.ModuleKind.ESNext,
target: ts.ScriptTarget.Latest,
Expand Down Expand Up @@ -182,15 +181,22 @@ export function createMultiCompilerHost(fs: FS): MultiCompilerHost {
);
const trace = traceCollector.read();
const moduleKey = `${resolutionMode ?? 1}:${moduleName}`;
(traceCache[moduleResolution][containingFile] ??= {})[moduleKey] = trace;
if (!traceCache[moduleResolution][containingFile]?.[moduleKey]) {
(traceCache[moduleResolution][containingFile] ??= {})[moduleKey] = trace;
}
return {
resolution,
trace,
};
}

function getTrace(moduleResolution: ResolutionOption, fromFileName: string, key: string): string[] | undefined {
return traceCache[moduleResolution][fromFileName]?.[key];
function getTrace(
moduleResolution: ResolutionOption,
fromFileName: string,
moduleSpecifier: string,
resolutionMode: ts.ModuleKind.ESNext | ts.ModuleKind.CommonJS
): string[] | undefined {
return traceCache[moduleResolution][fromFileName]?.[`${resolutionMode ?? 1}:${moduleSpecifier}`];
}

function createProgram(moduleResolution: ResolutionOption, rootNames: string[]): ts.Program {
Expand Down Expand Up @@ -231,6 +237,18 @@ export function createMultiCompilerHost(fs: FS): MultiCompilerHost {
useCaseSensitiveFileNames,
getNewLine,
trace: traceCollector.trace,
resolveModuleNameLiterals(moduleLiterals, containingFile, _redirectedReference, options, containingSourceFile) {
return moduleLiterals.map(
(literal) =>
resolveModuleName(
literal.text,
containingFile,
moduleResolution,
ts.getModeForUsageLocation(containingSourceFile, literal),
options.noDtsResolution
).resolution
);
},
};
}

Expand Down
Loading