Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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 src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
8 changes: 6 additions & 2 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4546,12 +4546,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
name: ModuleName,
body: ModuleBody | undefined,
flags = NodeFlags.None,
withClause?: ImportAttributes,
) {
const node = createBaseDeclaration<ModuleDeclaration>(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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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) :
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8324,14 +8324,15 @@ namespace Parser {
name = parseLiteralNode() as StringLiteral;
name.text = internIdentifier(name.text);
}
const withClause = tryParseImportAttributes();
let body: ModuleBlock | undefined;
if (token() === SyntaxKind.OpenBraceToken) {
body = parseModuleBlock();
}
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);
}

Expand Down
4 changes: 3 additions & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -1371,6 +1371,7 @@ export function transformDeclarations(context: TransformationContext): Transform
updated.name,
updated.body,
updated.flags | NodeFlags.Namespace,
updated.withClause,
);

setOriginalNode(fixed, updated);
Expand Down Expand Up @@ -1512,6 +1513,7 @@ export function transformDeclarations(context: TransformationContext): Transform
modifiers,
namespaceDecl.name,
namespaceDecl.body,
namespaceDecl.withClause,
);

const exportDefaultDeclaration = factory.createExportAssignment(
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3634,6 +3634,7 @@ export interface ModuleDeclaration extends DeclarationStatement, JSDocContainer,
readonly modifiers?: NodeArray<ModifierLike>;
readonly name: ModuleName;
readonly body?: ModuleBody | JSDocNamespaceDeclaration;
readonly withClause?: ImportAttributes;
}

export type NamespaceBody =
Expand Down Expand Up @@ -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<ImportAttribute>;
readonly multiLine?: boolean;
}
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/compiler/visitorPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
},

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {};


58 changes: 58 additions & 0 deletions tests/baselines/reference/ambientModuleWithImportAttributes.js
Original file line number Diff line number Diff line change
@@ -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 {};
Original file line number Diff line number Diff line change
@@ -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 {};


67 changes: 67 additions & 0 deletions tests/baselines/reference/ambientModuleWithImportAttributes.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//// [tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts] ////

=== ambientModuleWithImportAttributes.ts ===
// Ambient module declaration with import attributes
declare module "*.css" with { type: "css" } {
>"*.css" : typeof import("*.css")
> : ^^^^^^^^^^^^^^^^^^^^^^

const stylesheet: CSSStyleSheet;
>stylesheet : CSSStyleSheet
> : ^^^^^^^^^^^^^

export default stylesheet;
>stylesheet : CSSStyleSheet
> : ^^^^^^^^^^^^^
}

declare module "*.json" with { type: "json" } {
>"*.json" : typeof import("*.json")
> : ^^^^^^^^^^^^^^^^^^^^^^^

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")
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^

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")
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^

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 {};


7 changes: 4 additions & 3 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5477,6 +5477,7 @@ declare namespace ts {
readonly modifiers?: NodeArray<ModifierLike>;
readonly name: ModuleName;
readonly body?: ModuleBody | JSDocNamespaceDeclaration;
readonly withClause?: ImportAttributes;
}
type NamespaceBody = ModuleBlock | NamespaceDeclaration;
interface NamespaceDeclaration extends ModuleDeclaration {
Expand Down Expand Up @@ -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<ImportAttribute>;
readonly multiLine?: boolean;
}
Expand Down Expand Up @@ -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;
Expand Down
Loading
Loading