mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Allow untyped imports
This commit is contained in:
@@ -1069,7 +1069,7 @@ namespace ts {
|
||||
const moduleSymbol = resolveExternalModuleName(node, (<ImportDeclaration>node.parent).moduleSpecifier);
|
||||
|
||||
if (moduleSymbol) {
|
||||
const exportDefaultSymbol = isShorthandAmbientModuleSymbol(moduleSymbol) ?
|
||||
const exportDefaultSymbol = isUntypedModuleSymbol(moduleSymbol) ?
|
||||
moduleSymbol :
|
||||
moduleSymbol.exports["export="] ?
|
||||
getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") :
|
||||
@@ -1145,7 +1145,7 @@ namespace ts {
|
||||
if (targetSymbol) {
|
||||
const name = specifier.propertyName || specifier.name;
|
||||
if (name.text) {
|
||||
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
|
||||
if (isUntypedModuleSymbol(moduleSymbol)) {
|
||||
return moduleSymbol;
|
||||
}
|
||||
|
||||
@@ -1365,8 +1365,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
const isRelative = isExternalModuleNameRelative(moduleName);
|
||||
const quotedName = '"' + moduleName + '"';
|
||||
if (!isRelative) {
|
||||
const symbol = getSymbol(globals, '"' + moduleName + '"', SymbolFlags.ValueModule);
|
||||
const symbol = getSymbol(globals, quotedName, SymbolFlags.ValueModule);
|
||||
if (symbol) {
|
||||
// merged symbol is module declaration symbol combined with all augmentations
|
||||
return getMergedSymbol(symbol);
|
||||
@@ -1395,6 +1396,28 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// May be an untyped module. If so, ignore resolutionDiagnostic.
|
||||
if (!isRelative && resolvedModule && !extensionIsTypeScript(resolvedModule.extension)) {
|
||||
if (compilerOptions.noImplicitAny) {
|
||||
if (moduleNotFoundError) {
|
||||
error(errorNode,
|
||||
Diagnostics.A_package_for_0_was_found_at_1_but_is_untyped_Because_noImplicitAny_is_enabled_this_package_must_have_a_declaration,
|
||||
moduleReference,
|
||||
resolvedModule.resolvedFileName);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Create a new symbol to represent the untyped module and store it in globals.
|
||||
// This provides a name to the module. See the test tests/cases/fourslash/untypedModuleImport.ts
|
||||
const newSymbol = createSymbol(SymbolFlags.ValueModule, quotedName);
|
||||
// Module symbols are expected to have 'exports', although since this is an untyped module it can be empty.
|
||||
newSymbol.exports = createMap<Symbol>();
|
||||
// Cache it so subsequent accesses will return the same module.
|
||||
globals[quotedName] = newSymbol;
|
||||
return newSymbol;
|
||||
}
|
||||
|
||||
if (moduleNotFoundError) {
|
||||
// report errors only if it was requested
|
||||
if (resolutionDiagnostic) {
|
||||
@@ -3462,7 +3485,7 @@ namespace ts {
|
||||
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.type) {
|
||||
if (symbol.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && isShorthandAmbientModuleSymbol(symbol)) {
|
||||
if (symbol.flags & SymbolFlags.Module && isUntypedModuleSymbol(symbol)) {
|
||||
links.type = anyType;
|
||||
}
|
||||
else {
|
||||
@@ -19011,7 +19034,7 @@ namespace ts {
|
||||
|
||||
function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean {
|
||||
let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression);
|
||||
if (!moduleSymbol || isShorthandAmbientModuleSymbol(moduleSymbol)) {
|
||||
if (!moduleSymbol || isUntypedModuleSymbol(moduleSymbol)) {
|
||||
// If the module is not found or is shorthand, assume that it may export a value.
|
||||
return true;
|
||||
}
|
||||
@@ -19512,7 +19535,7 @@ namespace ts {
|
||||
(typeReferenceDirectives || (typeReferenceDirectives = [])).push(typeReferenceDirective);
|
||||
}
|
||||
else {
|
||||
// found at least one entry that does not originate from type reference directive
|
||||
// found at least one entry that does not originate from type reference directive
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2869,6 +2869,10 @@
|
||||
"category": "Error",
|
||||
"code": 6143
|
||||
},
|
||||
"A package for '{0}' was found at '{1}', but is untyped. Because '--noImplicitAny' is enabled, this package must have a declaration.": {
|
||||
"category": "Error",
|
||||
"code": 6144
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
|
||||
@@ -1324,6 +1324,7 @@ namespace ts {
|
||||
// - it's not a top level JavaScript module that exceeded the search max
|
||||
const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth;
|
||||
// Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs')
|
||||
// This may still end up being an untyped module -- the file won't be included but imports will be allowed.
|
||||
const shouldAddFile = resolvedFileName && !getResolutionDiagnostic(options, resolution) && !options.noResolve && i < file.imports.length && !elideImport;
|
||||
|
||||
if (elideImport) {
|
||||
@@ -1571,8 +1572,9 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
/**
|
||||
* Returns a DiagnosticMessage if we can't use a resolved module due to its extension.
|
||||
* Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
|
||||
* The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
|
||||
* This returns a diagnostic even if the module will be an untyped module.
|
||||
*/
|
||||
export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModule): DiagnosticMessage | undefined {
|
||||
switch (extension) {
|
||||
|
||||
@@ -406,8 +406,9 @@ namespace ts {
|
||||
((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(<ModuleDeclaration>node));
|
||||
}
|
||||
|
||||
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
|
||||
/** Given a symbol for a module, checks that it is either an untyped import or a shorthand ambient module. */
|
||||
export function isUntypedModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
return !moduleSymbol.valueDeclaration || isShorthandAmbientModule(moduleSymbol.valueDeclaration);
|
||||
}
|
||||
|
||||
function isShorthandAmbientModule(node: Node): boolean {
|
||||
|
||||
@@ -1108,22 +1108,7 @@ namespace Harness {
|
||||
const option = getCommandLineOption(name);
|
||||
if (option) {
|
||||
const errors: ts.Diagnostic[] = [];
|
||||
switch (option.type) {
|
||||
case "boolean":
|
||||
options[option.name] = value.toLowerCase() === "true";
|
||||
break;
|
||||
case "string":
|
||||
options[option.name] = value;
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
case "list":
|
||||
options[option.name] = ts.parseListTypeOption(<ts.CommandLineOptionOfListType>option, value, errors);
|
||||
break;
|
||||
default:
|
||||
options[option.name] = ts.parseCustomTypeOption(<ts.CommandLineOptionOfCustomType>option, value, errors);
|
||||
break;
|
||||
}
|
||||
|
||||
options[option.name] = optionValue(option, value, errors);
|
||||
if (errors.length > 0) {
|
||||
throw new Error(`Unknown value '${value}' for compiler option '${name}'.`);
|
||||
}
|
||||
@@ -1135,6 +1120,27 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
function optionValue(option: ts.CommandLineOption, value: string, errors: ts.Diagnostic[]): any {
|
||||
switch (option.type) {
|
||||
case "boolean":
|
||||
return value.toLowerCase() === "true";
|
||||
case "string":
|
||||
return value;
|
||||
case "number": {
|
||||
const number = parseInt(value, 10);
|
||||
if (isNaN(number)) {
|
||||
throw new Error(`Value must be a number, got: ${JSON.stringify(value)}`);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
case "list":
|
||||
return ts.parseListTypeOption(<ts.CommandLineOptionOfListType>option, value, errors);
|
||||
default:
|
||||
return ts.parseCustomTypeOption(<ts.CommandLineOptionOfCustomType>option, value, errors);
|
||||
}
|
||||
}
|
||||
|
||||
export interface TestFile {
|
||||
unitName: string;
|
||||
content: string;
|
||||
|
||||
Reference in New Issue
Block a user