diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 390c843b0c968..aa0e7dafed03f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4705,6 +4705,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : undefined; } + function getImportAttributesFromLocation(location: Node): ImportAttributes | undefined { + // Try to find import attributes from the location node + const importDecl = findAncestor(location, isImportDeclaration); + if (importDecl?.attributes) { + return importDecl.attributes; + } + const exportDecl = findAncestor(location, isExportDeclaration); + if (exportDecl?.attributes) { + return exportDecl.attributes; + } + const importType = findAncestor(location, isImportTypeNode); + if (importType?.attributes) { + return importType.attributes; + } + return undefined; + } + function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node | undefined, isForAugmentation = false): Symbol | undefined { if (errorNode && startsWith(moduleReference, "@types/")) { const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; @@ -4712,7 +4729,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(errorNode, diag, withoutAtTypePrefix, moduleReference); } - const ambientModule = tryFindAmbientModule(moduleReference, /*withAugmentations*/ true); + // Get import attributes from the import/export statement + const importAttributes = getImportAttributesFromLocation(location); + + const ambientModule = tryFindAmbientModule(moduleReference, /*withAugmentations*/ true, importAttributes); if (ambientModule) { return ambientModule; } @@ -4845,6 +4865,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (patternAmbientModules) { const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleReference); if (pattern) { + // Check if the pattern module has matching import attributes + const patternSymbol = pattern.symbol; + if (patternSymbol.declarations) { + const hasMatchingDeclaration = patternSymbol.declarations.some(decl => { + if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) { + return importAttributesMatch(importAttributes, decl.withClause); + } + return false; + }); + if (!hasMatchingDeclaration) { + // Pattern matched but attributes don't match + if (errorNode && moduleNotFoundError) { + error(errorNode, Diagnostics.No_ambient_module_declaration_matches_import_of_0_with_the_specified_import_attributes, moduleReference); + } + return undefined; + } + } // If the module reference matched a pattern ambient module ('*.foo') but there's also a // module augmentation by the specific name requested ('a.foo'), we store the merged symbol // by the augmentation name ('a.foo'), because asking for *.foo should not give you exports @@ -16010,11 +16047,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function tryFindAmbientModule(moduleName: string, withAugmentations: boolean) { + function importAttributesMatch(importAttributes: ImportAttributes | undefined, moduleAttributes: ImportAttributes | undefined): boolean { + // If neither has attributes, they match + if (!importAttributes && !moduleAttributes) { + return true; + } + // If only one has attributes, they don't match + if (!importAttributes || !moduleAttributes) { + return false; + } + // Both have attributes - check if they match + // For now, we require exact match of all attributes + if (importAttributes.elements.length !== moduleAttributes.elements.length) { + return false; + } + // Create a map of module attributes for easier lookup + const moduleAttrsMap = new Map(); + for (const attr of moduleAttributes.elements) { + const name = isIdentifier(attr.name) ? idText(attr.name) : attr.name.text; + const value = isStringLiteral(attr.value) ? attr.value.text : undefined; + if (value !== undefined) { + moduleAttrsMap.set(name, value); + } + } + // Check that all import attributes match + for (const attr of importAttributes.elements) { + const name = isIdentifier(attr.name) ? idText(attr.name) : attr.name.text; + const value = isStringLiteral(attr.value) ? attr.value.text : undefined; + if (value === undefined || moduleAttrsMap.get(name) !== value) { + return false; + } + } + return true; + } + + function tryFindAmbientModule(moduleName: string, withAugmentations: boolean, importAttributes?: ImportAttributes) { if (isExternalModuleNameRelative(moduleName)) { return undefined; } const symbol = getSymbol(globals, '"' + moduleName + '"' as __String, SymbolFlags.ValueModule); + if (!symbol) { + return undefined; + } + // Check if the module declaration has matching import attributes + const declarations = symbol.declarations; + if (declarations) { + const hasMatchingDeclaration = declarations.some(decl => { + if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) { + return importAttributesMatch(importAttributes, decl.withClause); + } + return false; + }); + if (!hasMatchingDeclaration) { + return undefined; + } + } // merged symbol is module declaration symbol combined with all augmentations return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1a69dba02a6c1..3fa7f79ac0743 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -8547,5 +8547,13 @@ "'{0}' is not a valid meta-property for keyword 'import'. Did you mean 'meta' or 'defer'?": { "category": "Error", "code": 18061 + }, + "Module '{0}' was resolved to '{1}', but import attributes do not match the ambient module declaration.": { + "category": "Error", + "code": 18062 + }, + "No ambient module declaration matches import of '{0}' with the specified import attributes.": { + "category": "Error", + "code": 18063 } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9ba1afcae27ea..297b121f08ba4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3635,6 +3635,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } emit(node.name); + if (node.withClause) { + writeSpace(); + emit(node.withClause); + } + let body = node.body; if (!body) return writeTrailingSemicolon(); while (body && isModuleDeclaration(body)) { diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index e31d925fadd8f..cd8dd1e1d0964 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -4546,12 +4546,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: ModuleName, body: ModuleBody | undefined, flags = NodeFlags.None, + withClause?: ImportAttributes, ) { const node = createBaseDeclaration(SyntaxKind.ModuleDeclaration); node.modifiers = asNodeArray(modifiers); node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation); node.name = name; node.body = body; + node.withClause = withClause; if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } @@ -4575,11 +4577,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, + withClause?: ImportAttributes, ) { return node.modifiers !== modifiers || node.name !== name || node.body !== body - ? update(createModuleDeclaration(modifiers, name, body, node.flags), node) + || node.withClause !== withClause + ? update(createModuleDeclaration(modifiers, name, body, node.flags, withClause), node) : node; } @@ -7092,7 +7096,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) : isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) : - isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) : + isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body, node.withClause) : isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) : isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.attributes) : isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) : diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 68133ac5f1e40..2ee6d8e3a3aec 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -923,6 +923,7 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.modifiers) || visitNode(cbNode, node.name) || + visitNode(cbNode, node.withClause) || visitNode(cbNode, node.body); }, [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { @@ -8324,6 +8325,7 @@ namespace Parser { name = parseLiteralNode() as StringLiteral; name.text = internIdentifier(name.text); } + const withClause = tryParseImportAttributes(); let body: ModuleBlock | undefined; if (token() === SyntaxKind.OpenBraceToken) { body = parseModuleBlock(); @@ -8331,7 +8333,7 @@ namespace Parser { else { parseSemicolon(); } - const node = factory.createModuleDeclaration(modifiersIn, name, body, flags); + const node = factory.createModuleDeclaration(modifiersIn, name, body, flags, withClause); return withJSDoc(finishNode(node, pos), hasJSDoc); } diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 66c2dbc00ebd9..9bb6f99abf5a9 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -1360,7 +1360,7 @@ export function transformDeclarations(context: TransformationContext): Transform name: ModuleName, body: ModuleBody | undefined, ) { - const updated = factory.updateModuleDeclaration(node, modifiers, name, body); + const updated = factory.updateModuleDeclaration(node, modifiers, name, body, node.withClause); if (isAmbientModule(updated) || updated.flags & NodeFlags.Namespace) { return updated; @@ -1371,6 +1371,7 @@ export function transformDeclarations(context: TransformationContext): Transform updated.name, updated.body, updated.flags | NodeFlags.Namespace, + updated.withClause, ); setOriginalNode(fixed, updated); @@ -1512,6 +1513,7 @@ export function transformDeclarations(context: TransformationContext): Transform modifiers, namespaceDecl.name, namespaceDecl.body, + namespaceDecl.withClause, ); const exportDefaultDeclaration = factory.createExportAssignment( diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4e9f872720d79..84fb8cf1f4da8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3634,6 +3634,7 @@ export interface ModuleDeclaration extends DeclarationStatement, JSDocContainer, readonly modifiers?: NodeArray; readonly name: ModuleName; readonly body?: ModuleBody | JSDocNamespaceDeclaration; + readonly withClause?: ImportAttributes; } export type NamespaceBody = @@ -3749,7 +3750,7 @@ export interface ImportAttribute extends Node { export interface ImportAttributes extends Node { readonly token: SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword; readonly kind: SyntaxKind.ImportAttributes; - readonly parent: ImportDeclaration | ExportDeclaration; + readonly parent: ImportDeclaration | ExportDeclaration | ModuleDeclaration; readonly elements: NodeArray; readonly multiLine?: boolean; } @@ -9062,8 +9063,8 @@ export interface NodeFactory { updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; createEnumDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; - createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; - updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; + createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags, withClause?: ImportAttributes): ModuleDeclaration; + updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, withClause?: ImportAttributes): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]): ModuleBlock; createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock; diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index d1aee94bc6e1b..d5a84d70b9cd2 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -1486,6 +1486,7 @@ const visitEachChildTable: VisitEachChildTable = { nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isModuleName)), nodeVisitor(node.body, visitor, isModuleBody), + nodeVisitor(node.withClause, visitor, isImportAttributes), ); }, diff --git a/tests/baselines/reference/ambientModuleWithImportAttributes.errors.txt b/tests/baselines/reference/ambientModuleWithImportAttributes.errors.txt new file mode 100644 index 0000000000000..aaa343b8fba30 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributes.errors.txt @@ -0,0 +1,48 @@ +ambientModuleWithImportAttributes.ts(2,16): error TS2664: Invalid module name in augmentation, module '*.css' cannot be found. +ambientModuleWithImportAttributes.ts(7,16): error TS2664: Invalid module name in augmentation, module '*.json' cannot be found. +ambientModuleWithImportAttributes.ts(13,16): error TS2664: Invalid module name in augmentation, module 'my-module' cannot be found. +ambientModuleWithImportAttributes.ts(19,16): error TS2664: Invalid module name in augmentation, module 'multi-attr' cannot be found. +ambientModuleWithImportAttributes.ts(24,16): error TS2664: Invalid module name in augmentation, module 'regular-module' cannot be found. + + +==== ambientModuleWithImportAttributes.ts (5 errors) ==== + // Ambient module declaration with import attributes + declare module "*.css" with { type: "css" } { + ~~~~~~~ +!!! error TS2664: Invalid module name in augmentation, module '*.css' cannot be found. + const stylesheet: CSSStyleSheet; + export default stylesheet; + } + + declare module "*.json" with { type: "json" } { + ~~~~~~~~ +!!! error TS2664: Invalid module name in augmentation, module '*.json' cannot be found. + const data: any; + export default data; + } + + // Ambient module with specific name and import attributes + declare module "my-module" with { type: "custom" } { + ~~~~~~~~~~~ +!!! error TS2664: Invalid module name in augmentation, module 'my-module' cannot be found. + export function foo(): void; + export const bar: string; + } + + // Ambient module with multiple attributes + declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { + ~~~~~~~~~~~~ +!!! error TS2664: Invalid module name in augmentation, module 'multi-attr' cannot be found. + export const value: number; + } + + // Ambient module without import attributes (should still work) + declare module "regular-module" { + ~~~~~~~~~~~~~~~~ +!!! error TS2664: Invalid module name in augmentation, module 'regular-module' cannot be found. + export function baz(): void; + } + + export {}; + + \ No newline at end of file diff --git a/tests/baselines/reference/ambientModuleWithImportAttributes.js b/tests/baselines/reference/ambientModuleWithImportAttributes.js new file mode 100644 index 0000000000000..9dbe1804483a3 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributes.js @@ -0,0 +1,58 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts] //// + +//// [ambientModuleWithImportAttributes.ts] +// Ambient module declaration with import attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +// Ambient module with specific name and import attributes +declare module "my-module" with { type: "custom" } { + export function foo(): void; + export const bar: string; +} + +// Ambient module with multiple attributes +declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { + export const value: number; +} + +// Ambient module without import attributes (should still work) +declare module "regular-module" { + export function baz(): void; +} + +export {}; + + + +//// [ambientModuleWithImportAttributes.js] +export {}; + + +//// [ambientModuleWithImportAttributes.d.ts] +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} +declare module "my-module" with { type: "custom" } { + function foo(): void; + const bar: string; +} +declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { + const value: number; +} +declare module "regular-module" { + function baz(): void; +} +export {}; diff --git a/tests/baselines/reference/ambientModuleWithImportAttributes.symbols b/tests/baselines/reference/ambientModuleWithImportAttributes.symbols new file mode 100644 index 0000000000000..423ce5b75f974 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributes.symbols @@ -0,0 +1,55 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts] //// + +=== ambientModuleWithImportAttributes.ts === +// Ambient module declaration with import attributes +declare module "*.css" with { type: "css" } { +>"*.css" : Symbol("*.css", Decl(ambientModuleWithImportAttributes.ts, 0, 0)) + + const stylesheet: CSSStyleSheet; +>stylesheet : Symbol(stylesheet, Decl(ambientModuleWithImportAttributes.ts, 2, 9)) +>CSSStyleSheet : Symbol(CSSStyleSheet, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + export default stylesheet; +>stylesheet : Symbol(stylesheet, Decl(ambientModuleWithImportAttributes.ts, 2, 9)) +} + +declare module "*.json" with { type: "json" } { +>"*.json" : Symbol("*.json", Decl(ambientModuleWithImportAttributes.ts, 4, 1)) + + const data: any; +>data : Symbol(data, Decl(ambientModuleWithImportAttributes.ts, 7, 9)) + + export default data; +>data : Symbol(data, Decl(ambientModuleWithImportAttributes.ts, 7, 9)) +} + +// Ambient module with specific name and import attributes +declare module "my-module" with { type: "custom" } { +>"my-module" : Symbol("my-module", Decl(ambientModuleWithImportAttributes.ts, 9, 1)) + + export function foo(): void; +>foo : Symbol(foo, Decl(ambientModuleWithImportAttributes.ts, 12, 52)) + + export const bar: string; +>bar : Symbol(bar, Decl(ambientModuleWithImportAttributes.ts, 14, 16)) +} + +// Ambient module with multiple attributes +declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { +>"multi-attr" : Symbol("multi-attr", Decl(ambientModuleWithImportAttributes.ts, 15, 1)) + + export const value: number; +>value : Symbol(value, Decl(ambientModuleWithImportAttributes.ts, 19, 16)) +} + +// Ambient module without import attributes (should still work) +declare module "regular-module" { +>"regular-module" : Symbol("regular-module", Decl(ambientModuleWithImportAttributes.ts, 20, 1)) + + export function baz(): void; +>baz : Symbol(baz, Decl(ambientModuleWithImportAttributes.ts, 23, 33)) +} + +export {}; + + diff --git a/tests/baselines/reference/ambientModuleWithImportAttributes.types b/tests/baselines/reference/ambientModuleWithImportAttributes.types new file mode 100644 index 0000000000000..7b1c0328fa6be --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributes.types @@ -0,0 +1,77 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts] //// + +=== ambientModuleWithImportAttributes.ts === +// Ambient module declaration with import attributes +declare module "*.css" with { type: "css" } { +>"*.css" : typeof import("*.css") +> : ^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const stylesheet: CSSStyleSheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ + + export default stylesheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ +} + +declare module "*.json" with { type: "json" } { +>"*.json" : typeof import("*.json") +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const data: any; +>data : any +> : ^^^ + + export default data; +>data : any +> : ^^^ +} + +// Ambient module with specific name and import attributes +declare module "my-module" with { type: "custom" } { +>"my-module" : typeof import("my-module") +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + export function foo(): void; +>foo : () => void +> : ^^^^^^ + + export const bar: string; +>bar : string +> : ^^^^^^ +} + +// Ambient module with multiple attributes +declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { +>"multi-attr" : typeof import("multi-attr") +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ +>integrity : any +> : ^^^ + + export const value: number; +>value : number +> : ^^^^^^ +} + +// Ambient module without import attributes (should still work) +declare module "regular-module" { +>"regular-module" : typeof import("regular-module") +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + export function baz(): void; +>baz : () => void +> : ^^^^^^ +} + +export {}; + + diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.errors.txt b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.errors.txt new file mode 100644 index 0000000000000..918b0fec0e9ec --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.errors.txt @@ -0,0 +1,45 @@ +test.ts(2,21): error TS18063: No ambient module declaration matches import of 'styles.css' with the specified import attributes. +test.ts(5,21): error TS18063: No ambient module declaration matches import of 'styles2.css' with the specified import attributes. +test.ts(8,18): error TS18063: No ambient module declaration matches import of 'file.txt' with the specified import attributes. +test.ts(11,18): error TS18063: No ambient module declaration matches import of 'data.json' with the specified import attributes. + + +==== types.d.ts (0 errors) ==== + // Declare ambient modules with import attributes + declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; + } + + declare module "*.json" with { type: "json" } { + const data: any; + export default data; + } + + declare module "*.txt" { + const content: string; + export default content; + } + +==== test.ts (4 errors) ==== + // Should error - pattern matches but attributes don't match + import styles1 from "styles.css" with { type: "style" }; + ~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'styles.css' with the specified import attributes. + + // Should error - pattern matches but import has no attributes when declaration requires them + import styles2 from "styles2.css"; + ~~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'styles2.css' with the specified import attributes. + + // Should error - pattern matches but import has attributes when declaration doesn't + import text from "file.txt" with { type: "text" }; + ~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'file.txt' with the specified import attributes. + + // Should error - pattern matches but attribute value is wrong + import data from "data.json" with { type: "data" }; + ~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'data.json' with the specified import attributes. + + \ No newline at end of file diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.js b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.js new file mode 100644 index 0000000000000..b64c23ed2e09f --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.js @@ -0,0 +1,40 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts] //// + +//// [types.d.ts] +// Declare ambient modules with import attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +declare module "*.txt" { + const content: string; + export default content; +} + +//// [test.ts] +// Should error - pattern matches but attributes don't match +import styles1 from "styles.css" with { type: "style" }; + +// Should error - pattern matches but import has no attributes when declaration requires them +import styles2 from "styles2.css"; + +// Should error - pattern matches but import has attributes when declaration doesn't +import text from "file.txt" with { type: "text" }; + +// Should error - pattern matches but attribute value is wrong +import data from "data.json" with { type: "data" }; + + + +//// [test.js] +export {}; + + +//// [test.d.ts] +export {}; diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.symbols b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.symbols new file mode 100644 index 0000000000000..016a91f5cb800 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.symbols @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts] //// + +=== types.d.ts === +// Declare ambient modules with import attributes +declare module "*.css" with { type: "css" } { +>"*.css" : Symbol("*.css", Decl(types.d.ts, 0, 0)) + + const stylesheet: CSSStyleSheet; +>stylesheet : Symbol(stylesheet, Decl(types.d.ts, 2, 9)) +>CSSStyleSheet : Symbol(CSSStyleSheet, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + export default stylesheet; +>stylesheet : Symbol(stylesheet, Decl(types.d.ts, 2, 9)) +} + +declare module "*.json" with { type: "json" } { +>"*.json" : Symbol("*.json", Decl(types.d.ts, 4, 1)) + + const data: any; +>data : Symbol(data, Decl(types.d.ts, 7, 9)) + + export default data; +>data : Symbol(data, Decl(types.d.ts, 7, 9)) +} + +declare module "*.txt" { +>"*.txt" : Symbol("*.txt", Decl(types.d.ts, 9, 1)) + + const content: string; +>content : Symbol(content, Decl(types.d.ts, 12, 9)) + + export default content; +>content : Symbol(content, Decl(types.d.ts, 12, 9)) +} + +=== test.ts === +// Should error - pattern matches but attributes don't match +import styles1 from "styles.css" with { type: "style" }; +>styles1 : Symbol(styles1, Decl(test.ts, 1, 6)) + +// Should error - pattern matches but import has no attributes when declaration requires them +import styles2 from "styles2.css"; +>styles2 : Symbol(styles2, Decl(test.ts, 4, 6)) + +// Should error - pattern matches but import has attributes when declaration doesn't +import text from "file.txt" with { type: "text" }; +>text : Symbol(text, Decl(test.ts, 7, 6)) + +// Should error - pattern matches but attribute value is wrong +import data from "data.json" with { type: "data" }; +>data : Symbol(data, Decl(test.ts, 10, 6)) + + diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.types b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.types new file mode 100644 index 0000000000000..22610341e3529 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesDiagnostics.types @@ -0,0 +1,75 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts] //// + +=== types.d.ts === +// Declare ambient modules with import attributes +declare module "*.css" with { type: "css" } { +>"*.css" : typeof import("*.css") +> : ^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const stylesheet: CSSStyleSheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ + + export default stylesheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ +} + +declare module "*.json" with { type: "json" } { +>"*.json" : typeof import("*.json") +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const data: any; +>data : any +> : ^^^ + + export default data; +>data : any +> : ^^^ +} + +declare module "*.txt" { +>"*.txt" : typeof import("*.txt") +> : ^^^^^^^^^^^^^^^^^^^^^^ + + const content: string; +>content : string +> : ^^^^^^ + + export default content; +>content : string +> : ^^^^^^ +} + +=== test.ts === +// Should error - pattern matches but attributes don't match +import styles1 from "styles.css" with { type: "style" }; +>styles1 : any +> : ^^^ +>type : any +> : ^^^ + +// Should error - pattern matches but import has no attributes when declaration requires them +import styles2 from "styles2.css"; +>styles2 : any +> : ^^^ + +// Should error - pattern matches but import has attributes when declaration doesn't +import text from "file.txt" with { type: "text" }; +>text : any +> : ^^^ +>type : any +> : ^^^ + +// Should error - pattern matches but attribute value is wrong +import data from "data.json" with { type: "data" }; +>data : any +> : ^^^ +>type : any +> : ^^^ + + diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.errors.txt b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.errors.txt new file mode 100644 index 0000000000000..a215d11f6d973 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.errors.txt @@ -0,0 +1,101 @@ +test.ts(2,33): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(6,30): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(14,38): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(18,19): error TS18063: No ambient module declaration matches import of 'file2.txt' with the specified import attributes. +test.ts(18,31): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(22,21): error TS18063: No ambient module declaration matches import of 'styles2.css' with the specified import attributes. +test.ts(26,21): error TS18063: No ambient module declaration matches import of 'styles3.css' with the specified import attributes. +test.ts(26,35): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(30,25): error TS18063: No ambient module declaration matches import of 'module2.wasm' with the specified import attributes. +test.ts(30,40): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. +test.ts(34,25): error TS18063: No ambient module declaration matches import of 'module3.wasm' with the specified import attributes. +test.ts(34,40): error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + + +==== types.d.ts (0 errors) ==== + // Test exact match with attributes + declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; + } + + // Test exact match with different attributes + declare module "*.json" with { type: "json" } { + const data: any; + export default data; + } + + // Test exact match without attributes + declare module "*.txt" { + const content: string; + export default content; + } + + // Test multiple attributes + declare module "*.wasm" with { type: "module", version: "1" } { + const module: WebAssembly.Module; + export default module; + } + +==== test.ts (12 errors) ==== + // Should resolve correctly - matching attributes + import styles from "styles.css" with { type: "css" }; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + styles; // Should be CSSStyleSheet + + // Should resolve correctly - matching attributes + import data from "data.json" with { type: "json" }; + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + data; // Should be any + + // Should resolve correctly - no attributes on either side + import text from "file.txt"; + text; // Should be string + + // Should resolve correctly - multiple matching attributes + import wasmModule from "module.wasm" with { type: "module", version: "1" }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + wasmModule; // Should be WebAssembly.Module + + // Should NOT resolve - import has attributes but declaration doesn't + import text2 from "file2.txt" with { type: "text" }; + ~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'file2.txt' with the specified import attributes. + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + text2; // Should be any (no match) + + // Should NOT resolve - import has no attributes but declaration does + import styles2 from "styles2.css"; + ~~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'styles2.css' with the specified import attributes. + styles2; // Should be any (no match) + + // Should NOT resolve - mismatched attribute values + import styles3 from "styles3.css" with { type: "style" }; + ~~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'styles3.css' with the specified import attributes. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + styles3; // Should be any (no match) + + // Should NOT resolve - missing attribute + import wasmModule2 from "module2.wasm" with { type: "module" }; + ~~~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'module2.wasm' with the specified import attributes. + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + wasmModule2; // Should be any (no match - missing version attribute) + + // Should NOT resolve - extra attribute + import wasmModule3 from "module3.wasm" with { type: "module", version: "1", extra: "value" }; + ~~~~~~~~~~~~~~ +!!! error TS18063: No ambient module declaration matches import of 'module3.wasm' with the specified import attributes. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2856: Import attributes are not allowed on statements that compile to CommonJS 'require' calls. + wasmModule3; // Should be any (no match - extra attribute) + + \ No newline at end of file diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.js b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.js new file mode 100644 index 0000000000000..6923770bce5d6 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.js @@ -0,0 +1,99 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts] //// + +//// [types.d.ts] +// Test exact match with attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +// Test exact match with different attributes +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +// Test exact match without attributes +declare module "*.txt" { + const content: string; + export default content; +} + +// Test multiple attributes +declare module "*.wasm" with { type: "module", version: "1" } { + const module: WebAssembly.Module; + export default module; +} + +//// [test.ts] +// Should resolve correctly - matching attributes +import styles from "styles.css" with { type: "css" }; +styles; // Should be CSSStyleSheet + +// Should resolve correctly - matching attributes +import data from "data.json" with { type: "json" }; +data; // Should be any + +// Should resolve correctly - no attributes on either side +import text from "file.txt"; +text; // Should be string + +// Should resolve correctly - multiple matching attributes +import wasmModule from "module.wasm" with { type: "module", version: "1" }; +wasmModule; // Should be WebAssembly.Module + +// Should NOT resolve - import has attributes but declaration doesn't +import text2 from "file2.txt" with { type: "text" }; +text2; // Should be any (no match) + +// Should NOT resolve - import has no attributes but declaration does +import styles2 from "styles2.css"; +styles2; // Should be any (no match) + +// Should NOT resolve - mismatched attribute values +import styles3 from "styles3.css" with { type: "style" }; +styles3; // Should be any (no match) + +// Should NOT resolve - missing attribute +import wasmModule2 from "module2.wasm" with { type: "module" }; +wasmModule2; // Should be any (no match - missing version attribute) + +// Should NOT resolve - extra attribute +import wasmModule3 from "module3.wasm" with { type: "module", version: "1", extra: "value" }; +wasmModule3; // Should be any (no match - extra attribute) + + + +//// [test.js] +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// Should resolve correctly - matching attributes +const styles_css_1 = __importDefault(require("styles.css")); +styles_css_1.default; // Should be CSSStyleSheet +// Should resolve correctly - matching attributes +const data_json_1 = __importDefault(require("data.json")); +data_json_1.default; // Should be any +// Should resolve correctly - no attributes on either side +const file_txt_1 = __importDefault(require("file.txt")); +file_txt_1.default; // Should be string +// Should resolve correctly - multiple matching attributes +const module_wasm_1 = __importDefault(require("module.wasm")); +module_wasm_1.default; // Should be WebAssembly.Module +// Should NOT resolve - import has attributes but declaration doesn't +const file2_txt_1 = __importDefault(require("file2.txt")); +file2_txt_1.default; // Should be any (no match) +// Should NOT resolve - import has no attributes but declaration does +const styles2_css_1 = __importDefault(require("styles2.css")); +styles2_css_1.default; // Should be any (no match) +// Should NOT resolve - mismatched attribute values +const styles3_css_1 = __importDefault(require("styles3.css")); +styles3_css_1.default; // Should be any (no match) +// Should NOT resolve - missing attribute +const module2_wasm_1 = __importDefault(require("module2.wasm")); +module2_wasm_1.default; // Should be any (no match - missing version attribute) +// Should NOT resolve - extra attribute +const module3_wasm_1 = __importDefault(require("module3.wasm")); +module3_wasm_1.default; // Should be any (no match - extra attribute) diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.symbols b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.symbols new file mode 100644 index 0000000000000..6101cbbb22065 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.symbols @@ -0,0 +1,115 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts] //// + +=== types.d.ts === +// Test exact match with attributes +declare module "*.css" with { type: "css" } { +>"*.css" : Symbol("*.css", Decl(types.d.ts, 0, 0)) + + const stylesheet: CSSStyleSheet; +>stylesheet : Symbol(stylesheet, Decl(types.d.ts, 2, 9)) +>CSSStyleSheet : Symbol(CSSStyleSheet, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + export default stylesheet; +>stylesheet : Symbol(stylesheet, Decl(types.d.ts, 2, 9)) +} + +// Test exact match with different attributes +declare module "*.json" with { type: "json" } { +>"*.json" : Symbol("*.json", Decl(types.d.ts, 4, 1)) + + const data: any; +>data : Symbol(data, Decl(types.d.ts, 8, 9)) + + export default data; +>data : Symbol(data, Decl(types.d.ts, 8, 9)) +} + +// Test exact match without attributes +declare module "*.txt" { +>"*.txt" : Symbol("*.txt", Decl(types.d.ts, 10, 1)) + + const content: string; +>content : Symbol(content, Decl(types.d.ts, 14, 9)) + + export default content; +>content : Symbol(content, Decl(types.d.ts, 14, 9)) +} + +// Test multiple attributes +declare module "*.wasm" with { type: "module", version: "1" } { +>"*.wasm" : Symbol("*.wasm", Decl(types.d.ts, 16, 1)) + + const module: WebAssembly.Module; +>module : Symbol(module, Decl(types.d.ts, 20, 9)) +>WebAssembly : Symbol(WebAssembly, Decl(lib.dom.d.ts, --, --)) +>Module : Symbol(WebAssembly.Module, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + export default module; +>module : Symbol(module, Decl(types.d.ts, 20, 9)) +} + +=== test.ts === +// Should resolve correctly - matching attributes +import styles from "styles.css" with { type: "css" }; +>styles : Symbol(styles, Decl(test.ts, 1, 6)) + +styles; // Should be CSSStyleSheet +>styles : Symbol(styles, Decl(test.ts, 1, 6)) + +// Should resolve correctly - matching attributes +import data from "data.json" with { type: "json" }; +>data : Symbol(data, Decl(test.ts, 5, 6)) + +data; // Should be any +>data : Symbol(data, Decl(test.ts, 5, 6)) + +// Should resolve correctly - no attributes on either side +import text from "file.txt"; +>text : Symbol(text, Decl(test.ts, 9, 6)) + +text; // Should be string +>text : Symbol(text, Decl(test.ts, 9, 6)) + +// Should resolve correctly - multiple matching attributes +import wasmModule from "module.wasm" with { type: "module", version: "1" }; +>wasmModule : Symbol(wasmModule, Decl(test.ts, 13, 6)) + +wasmModule; // Should be WebAssembly.Module +>wasmModule : Symbol(wasmModule, Decl(test.ts, 13, 6)) + +// Should NOT resolve - import has attributes but declaration doesn't +import text2 from "file2.txt" with { type: "text" }; +>text2 : Symbol(text2, Decl(test.ts, 17, 6)) + +text2; // Should be any (no match) +>text2 : Symbol(text2, Decl(test.ts, 17, 6)) + +// Should NOT resolve - import has no attributes but declaration does +import styles2 from "styles2.css"; +>styles2 : Symbol(styles2, Decl(test.ts, 21, 6)) + +styles2; // Should be any (no match) +>styles2 : Symbol(styles2, Decl(test.ts, 21, 6)) + +// Should NOT resolve - mismatched attribute values +import styles3 from "styles3.css" with { type: "style" }; +>styles3 : Symbol(styles3, Decl(test.ts, 25, 6)) + +styles3; // Should be any (no match) +>styles3 : Symbol(styles3, Decl(test.ts, 25, 6)) + +// Should NOT resolve - missing attribute +import wasmModule2 from "module2.wasm" with { type: "module" }; +>wasmModule2 : Symbol(wasmModule2, Decl(test.ts, 29, 6)) + +wasmModule2; // Should be any (no match - missing version attribute) +>wasmModule2 : Symbol(wasmModule2, Decl(test.ts, 29, 6)) + +// Should NOT resolve - extra attribute +import wasmModule3 from "module3.wasm" with { type: "module", version: "1", extra: "value" }; +>wasmModule3 : Symbol(wasmModule3, Decl(test.ts, 33, 6)) + +wasmModule3; // Should be any (no match - extra attribute) +>wasmModule3 : Symbol(wasmModule3, Decl(test.ts, 33, 6)) + + diff --git a/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.types b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.types new file mode 100644 index 0000000000000..b4244ba1c92e3 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithImportAttributesSemantics.types @@ -0,0 +1,172 @@ +//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts] //// + +=== types.d.ts === +// Test exact match with attributes +declare module "*.css" with { type: "css" } { +>"*.css" : typeof import("*.css") +> : ^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const stylesheet: CSSStyleSheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ + + export default stylesheet; +>stylesheet : CSSStyleSheet +> : ^^^^^^^^^^^^^ +} + +// Test exact match with different attributes +declare module "*.json" with { type: "json" } { +>"*.json" : typeof import("*.json") +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + + const data: any; +>data : any +> : ^^^ + + export default data; +>data : any +> : ^^^ +} + +// Test exact match without attributes +declare module "*.txt" { +>"*.txt" : typeof import("*.txt") +> : ^^^^^^^^^^^^^^^^^^^^^^ + + const content: string; +>content : string +> : ^^^^^^ + + export default content; +>content : string +> : ^^^^^^ +} + +// Test multiple attributes +declare module "*.wasm" with { type: "module", version: "1" } { +>"*.wasm" : typeof import("*.wasm") +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ +>version : any +> : ^^^ + + const module: WebAssembly.Module; +>module : WebAssembly.Module +> : ^^^^^^^^^^^^^^^^^^ +>WebAssembly : any +> : ^^^ + + export default module; +>module : WebAssembly.Module +> : ^^^^^^^^^^^^^^^^^^ +} + +=== test.ts === +// Should resolve correctly - matching attributes +import styles from "styles.css" with { type: "css" }; +>styles : CSSStyleSheet +> : ^^^^^^^^^^^^^ +>type : any +> : ^^^ + +styles; // Should be CSSStyleSheet +>styles : CSSStyleSheet +> : ^^^^^^^^^^^^^ + +// Should resolve correctly - matching attributes +import data from "data.json" with { type: "json" }; +>data : any +> : ^^^ +>type : any +> : ^^^ + +data; // Should be any +>data : any +> : ^^^ + +// Should resolve correctly - no attributes on either side +import text from "file.txt"; +>text : string +> : ^^^^^^ + +text; // Should be string +>text : string +> : ^^^^^^ + +// Should resolve correctly - multiple matching attributes +import wasmModule from "module.wasm" with { type: "module", version: "1" }; +>wasmModule : WebAssembly.Module +> : ^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ +>version : any +> : ^^^ + +wasmModule; // Should be WebAssembly.Module +>wasmModule : WebAssembly.Module +> : ^^^^^^^^^^^^^^^^^^ + +// Should NOT resolve - import has attributes but declaration doesn't +import text2 from "file2.txt" with { type: "text" }; +>text2 : any +> : ^^^ +>type : any +> : ^^^ + +text2; // Should be any (no match) +>text2 : any +> : ^^^ + +// Should NOT resolve - import has no attributes but declaration does +import styles2 from "styles2.css"; +>styles2 : any +> : ^^^ + +styles2; // Should be any (no match) +>styles2 : any +> : ^^^ + +// Should NOT resolve - mismatched attribute values +import styles3 from "styles3.css" with { type: "style" }; +>styles3 : any +> : ^^^ +>type : any +> : ^^^ + +styles3; // Should be any (no match) +>styles3 : any +> : ^^^ + +// Should NOT resolve - missing attribute +import wasmModule2 from "module2.wasm" with { type: "module" }; +>wasmModule2 : any +> : ^^^ +>type : any +> : ^^^ + +wasmModule2; // Should be any (no match - missing version attribute) +>wasmModule2 : any +> : ^^^ + +// Should NOT resolve - extra attribute +import wasmModule3 from "module3.wasm" with { type: "module", version: "1", extra: "value" }; +>wasmModule3 : any +> : ^^^ +>type : any +> : ^^^ +>version : any +> : ^^^ +>extra : any +> : ^^^ + +wasmModule3; // Should be any (no match - extra attribute) +>wasmModule3 : any +> : ^^^ + + diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 6ca73b0b2fe8b..db2ad471c1f3a 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5477,6 +5477,7 @@ declare namespace ts { readonly modifiers?: NodeArray; readonly name: ModuleName; readonly body?: ModuleBody | JSDocNamespaceDeclaration; + readonly withClause?: ImportAttributes; } type NamespaceBody = ModuleBlock | NamespaceDeclaration; interface NamespaceDeclaration extends ModuleDeclaration { @@ -5552,7 +5553,7 @@ declare namespace ts { interface ImportAttributes extends Node { readonly token: SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword; readonly kind: SyntaxKind.ImportAttributes; - readonly parent: ImportDeclaration | ExportDeclaration; + readonly parent: ImportDeclaration | ExportDeclaration | ModuleDeclaration; readonly elements: NodeArray; readonly multiLine?: boolean; } @@ -7732,8 +7733,8 @@ declare namespace ts { updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; createEnumDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; - createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; - updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; + createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags, withClause?: ImportAttributes): ModuleDeclaration; + updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, withClause?: ImportAttributes): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]): ModuleBlock; createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock; diff --git a/tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts b/tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts new file mode 100644 index 0000000000000..66112c626c67b --- /dev/null +++ b/tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts @@ -0,0 +1,33 @@ +// @declaration: true +// @target: es2015 +// @module: esnext + +// Ambient module declaration with import attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +// Ambient module with specific name and import attributes +declare module "my-module" with { type: "custom" } { + export function foo(): void; + export const bar: string; +} + +// Ambient module with multiple attributes +declare module "multi-attr" with { type: "json", integrity: "sha384-..." } { + export const value: number; +} + +// Ambient module without import attributes (should still work) +declare module "regular-module" { + export function baz(): void; +} + +export {}; + diff --git a/tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts b/tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts new file mode 100644 index 0000000000000..5b8a903187f5a --- /dev/null +++ b/tests/cases/conformance/ambient/ambientModuleWithImportAttributesDiagnostics.ts @@ -0,0 +1,34 @@ +// @declaration: true +// @target: es2015 +// @module: esnext + +// @filename: types.d.ts +// Declare ambient modules with import attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +declare module "*.txt" { + const content: string; + export default content; +} + +// @filename: test.ts +// Should error - pattern matches but attributes don't match +import styles1 from "styles.css" with { type: "style" }; + +// Should error - pattern matches but import has no attributes when declaration requires them +import styles2 from "styles2.css"; + +// Should error - pattern matches but import has attributes when declaration doesn't +import text from "file.txt" with { type: "text" }; + +// Should error - pattern matches but attribute value is wrong +import data from "data.json" with { type: "data" }; + diff --git a/tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts b/tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts new file mode 100644 index 0000000000000..902b9302a9690 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientModuleWithImportAttributesSemantics.ts @@ -0,0 +1,63 @@ +// @module: nodenext +// @filename: types.d.ts +// Test exact match with attributes +declare module "*.css" with { type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +// Test exact match with different attributes +declare module "*.json" with { type: "json" } { + const data: any; + export default data; +} + +// Test exact match without attributes +declare module "*.txt" { + const content: string; + export default content; +} + +// Test multiple attributes +declare module "*.wasm" with { type: "module", version: "1" } { + const module: WebAssembly.Module; + export default module; +} + +// @filename: test.ts +// Should resolve correctly - matching attributes +import styles from "styles.css" with { type: "css" }; +styles; // Should be CSSStyleSheet + +// Should resolve correctly - matching attributes +import data from "data.json" with { type: "json" }; +data; // Should be any + +// Should resolve correctly - no attributes on either side +import text from "file.txt"; +text; // Should be string + +// Should resolve correctly - multiple matching attributes +import wasmModule from "module.wasm" with { type: "module", version: "1" }; +wasmModule; // Should be WebAssembly.Module + +// Should NOT resolve - import has attributes but declaration doesn't +import text2 from "file2.txt" with { type: "text" }; +text2; // Should be any (no match) + +// Should NOT resolve - import has no attributes but declaration does +import styles2 from "styles2.css"; +styles2; // Should be any (no match) + +// Should NOT resolve - mismatched attribute values +import styles3 from "styles3.css" with { type: "style" }; +styles3; // Should be any (no match) + +// Should NOT resolve - missing attribute +import wasmModule2 from "module2.wasm" with { type: "module" }; +wasmModule2; // Should be any (no match - missing version attribute) + +// Should NOT resolve - extra attribute +import wasmModule3 from "module3.wasm" with { type: "module", version: "1", extra: "value" }; +wasmModule3; // Should be any (no match - extra attribute) +