Skip to content

feat(ast-spec): tighter types and documentation for declaration/* #9211

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 8 commits into from
Jun 23, 2024
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
2 changes: 1 addition & 1 deletion packages/ast-spec/src/base/FunctionBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface FunctionBase extends BaseNode {
/**
* The body of the function.
* - For an `ArrowFunctionExpression` this may be an `Expression` or `BlockStatement`.
* - For a `FunctionDeclaration` or `FunctionExpression` this is always a `BlockStatement.
* - For a `FunctionDeclaration` or `FunctionExpression` this is always a `BlockStatement`.
* - For a `TSDeclareFunction` this is always `undefined`.
* - For a `TSEmptyBodyFunctionExpression` this is always `null`.
*/
Expand Down
12 changes: 12 additions & 0 deletions packages/ast-spec/src/declaration/ClassDeclaration/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,22 @@ interface ClassDeclarationBase extends ClassBase {
type: AST_NODE_TYPES.ClassDeclaration;
}

/**
* A normal class declaration:
* ```
* class A {}
* ```
*/
export interface ClassDeclarationWithName extends ClassDeclarationBase {
id: Identifier;
}

/**
* Default-exported class declarations have optional names:
* ```
* export default class {}
* ```
*/
export interface ClassDeclarationWithOptionalName extends ClassDeclarationBase {
id: Identifier | null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,23 @@ export interface ExportAllDeclaration extends BaseNode {
* ```
* export * from 'mod' assert { type: 'json' };
* ```
* @deprecated -- Replaced with {@link `attributes`}.
* @deprecated Replaced with {@link `attributes`}.
*/
assertions: ImportAttribute[];
/**
* The attributes declared for the export.
* ```
* export * from 'mod' assert { type: 'json' };
* export * from 'mod' with { type: 'json' };
* ```
*/
attributes: ImportAttribute[];
/**
* The name for the exported items. `null` if no name is assigned.
* The name for the exported items (`as X`). `null` if no name is assigned.
*/
exported: Identifier | null;
/**
* The kind of the export.
*/
// TODO(#1852) - breaking change remove this because it is a semantic error to have it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS now allows export type * from

exportKind: ExportKind;
/**
* The source module being exported from.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
import type { DefaultExportDeclarations } from '../../unions/ExportDeclaration';
import type { ExportKind } from '../ExportAndImportKind';

export interface ExportDefaultDeclaration extends BaseNode {
type: AST_NODE_TYPES.ExportDefaultDeclaration;
Expand All @@ -10,7 +9,7 @@ export interface ExportDefaultDeclaration extends BaseNode {
*/
declaration: DefaultExportDeclarations;
/**
* The kind of the export.
* The kind of the export. Always `value` for default exports.
*/
exportKind: ExportKind;
exportKind: 'value';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tightened: export type default is not legal

}
36 changes: 23 additions & 13 deletions packages/ast-spec/src/declaration/ExportNamedDeclaration/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface ExportNamedDeclarationBase extends BaseNode {
/**
* The attributes declared for the export.
* ```
* export { foo } from 'mod' assert { type: 'json' };
* export { foo } from 'mod' with { type: 'json' };
* ```
* This will be an empty array if `source` is `null`
*/
Expand Down Expand Up @@ -51,6 +51,13 @@ interface ExportNamedDeclarationBase extends BaseNode {
specifiers: ExportSpecifier[];
}

/**
* Exporting names from the current module.
* ```
* export {};
* export { a, b };
* ```
*/
export interface ExportNamedDeclarationWithoutSourceWithMultiple
extends ExportNamedDeclarationBase {
/**
Expand All @@ -64,9 +71,14 @@ export interface ExportNamedDeclarationWithoutSourceWithMultiple
attributes: ImportAttribute[];
declaration: null;
source: null;
specifiers: ExportSpecifier[];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removals here are not breaking because these properties are already declared on the base

}

/**
* Exporting a single named declaration.
* ```
* export const x = 1;
* ```
*/
export interface ExportNamedDeclarationWithoutSourceWithSingle
extends ExportNamedDeclarationBase {
/**
Expand All @@ -80,24 +92,22 @@ export interface ExportNamedDeclarationWithoutSourceWithSingle
attributes: ImportAttribute[];
declaration: NamedExportDeclarations;
source: null;
// This will always be an empty array.
/**
* This will always be an empty array.
*/
specifiers: ExportSpecifier[];
}

/**
* Export names from another module.
* ```
* export { a, b } from 'mod';
* ```
*/
export interface ExportNamedDeclarationWithSource
extends ExportNamedDeclarationBase {
/**
* This will always be an empty array.
* @deprecated Replaced with {@link `attributes`}.
*/
assertions: ImportAttribute[];
/**
* This will always be an empty array.
*/
attributes: ImportAttribute[];
declaration: null;
source: StringLiteral;
specifiers: ExportSpecifier[];
}

export type ExportNamedDeclaration =
Expand Down
12 changes: 12 additions & 0 deletions packages/ast-spec/src/declaration/FunctionDeclaration/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,22 @@ interface FunctionDeclarationBase extends FunctionBase {
expression: false;
}

/**
* A normal function declaration:
* ```
* function f() {}
* ```
*/
export interface FunctionDeclarationWithName extends FunctionDeclarationBase {
id: Identifier;
}

/**
* Default-exported function declarations have optional names:
* ```
* export default function () {}
* ```
*/
export interface FunctionDeclarationWithOptionalName
extends FunctionDeclarationBase {
id: Identifier | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface ImportDeclaration extends BaseNode {
* ```
* import * from 'mod' assert { type: 'json' };
* ```
* @deprecated -- Replaced with {@link `attributes`}.
* @deprecated Replaced with {@link `attributes`}.
*/
assertions: ImportAttribute[];
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
import type { Identifier } from '../../expression/Identifier/spec';
import type { TSExternalModuleReference } from '../../special/TSExternalModuleReference/spec';
import type { EntityName } from '../../unions/EntityName';
import type { TSQualifiedName } from '../../type/TSQualifiedName/spec';
import type { ImportKind } from '../ExportAndImportKind';

export interface TSImportEqualsDeclaration extends BaseNode {
interface TSImportEqualsDeclarationBase extends BaseNode {
type: AST_NODE_TYPES.TSImportEqualsDeclaration;
/**
* The locally imported name
* The locally imported name.
*/
id: Identifier;
/**
Expand All @@ -19,7 +19,45 @@ export interface TSImportEqualsDeclaration extends BaseNode {
* import F3 = require('mod');
* ```
*/
moduleReference: EntityName | TSExternalModuleReference;
// TODO(#1852) - breaking change remove this as it is invalid
moduleReference: Identifier | TSExternalModuleReference | TSQualifiedName;
/**
* The kind of the import. Always `'value'` unless `moduleReference` is a
* `TSExternalModuleReference`.
*/
importKind: ImportKind;
}

export interface TSImportEqualsNamespaceDeclaration
extends TSImportEqualsDeclarationBase {
/**
* The value being aliased.
* ```
* import F1 = A;
* import F2 = A.B.C;
* ```
*/
moduleReference: Identifier | TSQualifiedName;
/**
* The kind of the import.
*/
importKind: 'value';
}

export interface TSImportEqualsRequireDeclaration
extends TSImportEqualsDeclarationBase {
/**
* The value being aliased.
* ```
* import F3 = require('mod');
* ```
*/
moduleReference: TSExternalModuleReference;
/**
* The kind of the import.
*/
importKind: ImportKind;
}

export type TSImportEqualsDeclaration =
| TSImportEqualsNamespaceDeclaration
| TSImportEqualsRequireDeclaration;
Comment on lines +61 to +63
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to union

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface TSInterfaceDeclaration extends BaseNode {
*/
body: TSInterfaceBody;
/**
* Whether the interface was `declare`d, `undefined` otherwise
* Whether the interface was `declare`d
*/
declare: boolean;
/**
Expand All @@ -24,7 +24,8 @@ export interface TSInterfaceDeclaration extends BaseNode {
*/
id: Identifier;
/**
* The generic type parameters declared for the interface.
* The generic type parameters declared for the interface. Empty declaration
* (`<>`) is different from no declaration.
*/
typeParameters: TSTypeParameterDeclaration | undefined;
}
57 changes: 36 additions & 21 deletions packages/ast-spec/src/declaration/TSModuleDeclaration/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ interface TSModuleDeclarationBase extends BaseNode {
/**
* The body of the module.
* This can only be `undefined` for the code `declare module 'mod';`
* This will be a `TSModuleDeclaration` if the name is "nested" (`Foo.Bar`).
*/
body?: TSModuleBlock;
/**
* Whether this is a global declaration
* ```
* declare global {}
* ```
*
* @deprecated Use {@link kind} instead
*/
// TODO - remove this in the next major (we have `.kind` now)
global: boolean;
Expand All @@ -50,64 +48,81 @@ interface TSModuleDeclarationBase extends BaseNode {
* module 'foo' {}
* ^^^^^^
*
* declare global {}
* ^^^^^^
* global {}
* ^^^^^^
* ```
*/
kind: TSModuleDeclarationKind;
}

export interface TSModuleDeclarationNamespace extends TSModuleDeclarationBase {
kind: 'namespace';
// namespaces cannot have literal IDs
id: Identifier | TSQualifiedName;
// namespaces must always have a body
body: TSModuleBlock;
}

export interface TSModuleDeclarationGlobal extends TSModuleDeclarationBase {
kind: 'global';
// cannot have a nested namespace for global module augmentation
// cannot have `declare global;`
body: TSModuleBlock;
// this will always be an Identifier with name `global`
/**
* This will always be an Identifier with name `global`
*/
id: Identifier;
body: TSModuleBlock;
}

interface TSModuleDeclarationModuleBase extends TSModuleDeclarationBase {
kind: 'module';
}

export type TSModuleDeclarationModule =
| TSModuleDeclarationModuleWithIdentifierId
| TSModuleDeclarationModuleWithStringId;
export type TSModuleDeclarationModuleWithStringId =
| TSModuleDeclarationModuleWithStringIdDeclared
| TSModuleDeclarationModuleWithStringIdNotDeclared;
/**
* A string module declaration that is not declared:
* ```
* module 'foo' {}
* ```
*/
export interface TSModuleDeclarationModuleWithStringIdNotDeclared
extends TSModuleDeclarationModuleBase {
kind: 'module';
id: StringLiteral;
declare: false;
// cannot have nested namespaces with a string ID, must have a body
body: TSModuleBlock;
}
/**
* A string module declaration that is declared:
* ```
* declare module 'foo' {}
* declare module 'foo';
* ```
*/
export interface TSModuleDeclarationModuleWithStringIdDeclared
extends TSModuleDeclarationModuleBase {
kind: 'module';
id: StringLiteral;
declare: true;
// cannot have nested namespaces with a string ID, might not have a body
body?: TSModuleBlock;
}
/**
* The legacy module declaration, replaced with namespace declarations.
* ```
* module A {}
* ```
*/
export interface TSModuleDeclarationModuleWithIdentifierId
extends TSModuleDeclarationModuleBase {
kind: 'module';
id: Identifier;
// modules with an Identifier must always have a body
// TODO: we emit the wrong AST for `module A.B {}`
// https://github.com/typescript-eslint/typescript-eslint/pull/6272 only fixed namespaces
// Maybe not worth fixing since it's legacy
Comment on lines +114 to +116
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth pointing out

body: TSModuleBlock;
}

export type TSModuleDeclarationModuleWithStringId =
| TSModuleDeclarationModuleWithStringIdDeclared
| TSModuleDeclarationModuleWithStringIdNotDeclared;
export type TSModuleDeclarationModule =
| TSModuleDeclarationModuleWithIdentifierId
| TSModuleDeclarationModuleWithStringId;
export type TSModuleDeclaration =
| TSModuleDeclarationGlobal
| TSModuleDeclarationModule
Expand Down
Loading
Loading