1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-03 12:58:54 -05:00

fix(cli): fix handling of non-normalized specifier (#9357)

This commit is contained in:
Yoshiya Hinosawa 2021-02-01 17:02:02 +09:00 committed by GitHub
parent 534531e4dd
commit 23281be33a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 7 deletions

View file

@ -305,3 +305,17 @@ Deno.test({
});
},
});
Deno.test({
name: "Deno.emit() - non-normalized specifier and source can compile",
async fn() {
const specifier = "https://example.com/foo//bar.ts";
const { files } = await Deno.emit(specifier, {
sources: {
[specifier]: `export let foo: string = "foo";`,
},
});
assertEquals(files[`${specifier}.js`], 'export let foo = "foo";\n');
assert(typeof files[`${specifier}.js.map`] === "string");
},
});

View file

@ -19,6 +19,14 @@ delete Object.prototype.__proto__;
let logDebug = false;
let logSource = "JS";
// The map from the normalized specifier to the original.
// TypeScript normalizes the specifier in its internal processing,
// but the original specifier is needed when looking up the source from the runtime.
// This map stores that relationship, and the original can be restored by the
// normalized specifier.
// See: https://github.com/denoland/deno/issues/9277#issuecomment-769653834
const normalizedToOriginalMap = new Map();
function setLogDebug(debug, source) {
logDebug = debug;
if (source) {
@ -260,6 +268,9 @@ delete Object.prototype.__proto__;
return sourceFile;
}
// Needs the original specifier
specifier = normalizedToOriginalMap.get(specifier) ?? specifier;
/** @type {{ data: string; hash?: string; scriptKind: ts.ScriptKind }} */
const { data, hash, scriptKind } = core.jsonOpSync(
"op_load",
@ -436,6 +447,27 @@ delete Object.prototype.__proto__;
* @property {string[]} rootNames
*/
/**
* Checks the normalized version of the root name and stores it in
* `normalizedToOriginalMap`. If the normalized specifier is already
* registered for the different root name, it throws an AssertionError.
*
* @param {string} rootName
*/
function checkNormalizedPath(rootName) {
const normalized = ts.normalizePath(rootName);
const originalRootName = normalizedToOriginalMap.get(normalized);
if (typeof originalRootName === "undefined") {
normalizedToOriginalMap.set(normalized, rootName);
} else if (originalRootName !== rootName) {
// The different root names are normalizd to the same path.
// This will cause problem when looking up the source for each.
throw new AssertionError(
`The different names for the same normalized specifier are specified: normalized=${normalized}, rootNames=${originalRootName},${rootName}`,
);
}
}
/** The API that is called by Rust when executing a request.
* @param {Request} request
*/
@ -445,6 +477,8 @@ delete Object.prototype.__proto__;
debug(">>> exec start", { rootNames });
debug(config);
rootNames.forEach(checkNormalizedPath);
const { options, errors: configFileParsingDiagnostics } = ts
.convertCompilerOptionsFromJson(config, "");
// The `allowNonTsExtensions` is a "hidden" compiler option used in VSCode