🤖 Merge PR #64628 @types/babel__traverse: align type definitions closer to Babel source by @nullableVoidPtr

* @types/babel__traverse: align type definitions closer to Babel source

* bump required TS version and /types dependency
* define internal traverse functions like `cheap`
* narrow internal visitor functions
* define cache namespace
* better define TraverseOptions
* include more properties and documentation under `Scope`, `Binding`, `NodePath`
* narrow return types for `NodePath#get` where possible
* narrow `NodePath#parentPath` and modification methods' return types
* narrow `TraversalContext` properties
* define `VirtualTypeAliases`

* @types/babel__core: bump typescript version to align with downstream dependencies

* Revert "@types/babel__core: bump typescript version to align with downstream dependencies"

This reverts commit d412ba5b55b39db0d26bc11092a2c2ae5f7fbf76.

* @types/babel__traverse: add TS4.3 fallback and fix NodePath#parentPath

* @types/babel__core: remove minimum TypeScript version required

* @types/babel__traverse: remove myself from codeowners

* @types/babel__traverse: simplify union type on narrowed NodePath#parentPath

* @types/babel__traverse: fix introspection has-key functions and exploded visitor type

* @types/babel__core: fix lint issue

* @types/babel__traverse: remove parentPath narrowing

* @types/babel__traverse: revert NodePath#get and NodePath#parent and NodePath#parentPath

* @types/babel__traverse: minor fixes

* narrow cache WeakMaps
* define shouldSkip option
* narrow NodePath#labels
* narrow NodePath#skipKeys
* narrow parameters to NodePath#replaceWithSourceString
* remove unneeded type param on NodePath#replaceExpressionWithStatements
* deprecate NodePath#isBlacklisted
This commit is contained in:
Avery
2023-05-26 03:55:02 +10:00
committed by GitHub
parent b584b38d1b
commit 5c92dccdca
8 changed files with 2961 additions and 691 deletions

View File

@@ -6,7 +6,6 @@
// Jessica Franco <https://github.com/Jessidhia>
// Ifiok Jr. <https://github.com/ifiokjr>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 3.4
import { GeneratorOptions } from '@babel/generator';
import { ParserOptions } from '@babel/parser';

View File

@@ -1,4 +1,4 @@
import traverse, { Binding, Hub, NodePath, Visitor, visitors } from '@babel/traverse';
import traverse, { Binding, Hub, NodePath, TraverseOptions, Visitor, visitors } from '@babel/traverse';
import * as t from '@babel/types';
// Examples from: https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md
@@ -23,6 +23,9 @@ const MyVisitor2: Visitor = {
path.parentPath; // $ExpectType NodePath<Node>
console.log('Visiting: ' + path.node.name);
},
ArrayExpression(path) {
path.get('elements'); // $ExpectType NodePath<SpreadElement | Expression | null>[]
},
Program(path) {
path.parentPath; // $ExpectType null
},
@@ -99,10 +102,14 @@ const v1: Visitor = {
return a + b;
}`);
// $ExpectType [NodePath<ExpressionStatement>]
path.get('body').unshiftContainer('body', t.expressionStatement(t.stringLiteral('Start of function')));
// $ExpectType [NodePath<ExpressionStatement>]
path.get('body').pushContainer('body', t.expressionStatement(t.stringLiteral('End of function')));
// $ExpectType [NodePath<ExpressionStatement>]
path.insertBefore(t.expressionStatement(t.stringLiteral("Because I'm easy come, easy go.")));
// $ExpectType [NodePath<ExpressionStatement>]
path.insertAfter(t.expressionStatement(t.stringLiteral('A little high, little low.')));
path.remove();
@@ -143,9 +150,9 @@ const v1: Visitor = {
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
@@ -169,41 +176,21 @@ const v1: Visitor = {
newPath;
}
},
Program(path) {
path.type; // $ExpectType "Program"
SequenceExpression(path) {
path.type; // $ExpectType "SequenceExpression"
{
const [newPath] = path.unshiftContainer('body', t.stringLiteral('hello'));
const [newPath] = path.unshiftContainer('expressions', t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
{
const [newPath] = path.pushContainer('body', t.stringLiteral('hello'));
const [newPath] = path.pushContainer('expressions', t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
{
const [stringPath, booleanPath] = path.unshiftContainer('body', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.pushContainer('body', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral | StringLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.unshiftContainer<[t.StringLiteral, t.BooleanLiteral]>('body', [
const [stringPath, booleanPath] = path.unshiftContainer('expressions', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
@@ -213,7 +200,7 @@ const v1: Visitor = {
booleanPath;
}
{
const [stringPath, booleanPath] = path.pushContainer<[t.StringLiteral, t.BooleanLiteral]>('body', [
const [stringPath, booleanPath] = path.pushContainer('expressions', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
@@ -222,6 +209,28 @@ const v1: Visitor = {
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.unshiftContainer<
t.SequenceExpression,
'expressions',
[t.StringLiteral, t.BooleanLiteral]
>('expressions', [t.stringLiteral('hello'), t.booleanLiteral(false)]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.pushContainer<
t.SequenceExpression,
'expressions',
[t.StringLiteral, t.BooleanLiteral]
>('expressions', [t.stringLiteral('hello'), t.booleanLiteral(false)]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
},
};
@@ -244,7 +253,7 @@ interface SomeVisitorState {
someState: string;
}
const VisitorStateTest: Visitor<SomeVisitorState> = {
const VisitorStateTest: TraverseOptions<SomeVisitorState> = {
enter(path, state) {
let actualType = path.type;
const expectedType: t.Node['type'] = actualType;
@@ -334,18 +343,23 @@ function testNullishPath(
) {
nullPath.type; // $ExpectType undefined
undefinedPath.type; // $ExpectType undefined
unknownPath.type; // $ExpectType string | undefined
unknownPath.type; // $ExpectAssignable t.Node['type'] | undefined
let actualType = optionalPath.type;
const expectedType: t.Node['type'] | undefined = actualType;
actualType = expectedType;
}
const visitorWithDenylist: Visitor = {
function testEnsureBlock(path: NodePath<t.ArrowFunctionExpression>) {
path.ensureBlock();
path.node.body; // $ExpectType BlockStatement
}
const optionsWithDenylist: TraverseOptions = {
denylist: ['TypeAnnotation'],
};
const visitorWithInvalidDenylist: Visitor = {
const optionsWithInvalidDenylist: TraverseOptions = {
// @ts-expect-error
denylist: ['SomeRandomType'],
};
@@ -386,6 +400,17 @@ const newPath = NodePath.get({
newPath; // $ExpectType NodePath<Program>
const program: t.Program = {} as any;
// $ExpectType NodePath<Statement>
NodePath.get({
hub: {} as any,
parentPath: null,
parent: program,
container: program,
listKey: 'body',
key: 0,
});
const binding = new Binding({
identifier: {} as any,
scope: {} as any,

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,10 @@
{
"private": true,
"dependencies": {
"@babel/types": "^7.3.0"
"@babel/types": "^7.20.7"
},
"types": "index",
"typesVersions": {
"<=4.3": { "*": ["ts4.3/*"] }
}
}

View File

@@ -0,0 +1,466 @@
import traverse, { Binding, Hub, NodePath, TraverseOptions, Visitor, visitors } from '@babel/traverse';
import * as t from '@babel/types';
// Examples from: https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md
const MyVisitor: Visitor = {
Identifier: {
enter(path) {
path.type; // $ExpectType "Identifier"
const x: NodePath<t.Identifier> = path;
console.log('Entered!');
},
exit(path) {
path.type; // $ExpectType "Identifier"
const x: NodePath<t.Identifier> = path;
console.log('Exited!');
},
},
};
const MyVisitor2: Visitor = {
Identifier(path) {
path.type; // $ExpectType "Identifier"
path.parentPath; // $ExpectType NodePath<Node>
console.log('Visiting: ' + path.node.name);
},
ArrayExpression(path) {
path.get('elements'); // $ExpectType NodePath<SpreadElement | Expression | null>[]
},
Program(path) {
path.parentPath; // $ExpectType null
},
};
// Example from https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#babel-traverse
declare const ast: t.Node;
traverse(ast, {
enter(path) {
let actualType = path.type;
const expectedType: t.Node['type'] = actualType;
actualType = ast.type;
const node = path.node;
if (t.isIdentifier(node) && node.name === 'n') {
node.name = 'x';
}
},
});
// Examples from https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#writing-your-first-babel-plugin
const v1: Visitor = {
BinaryExpression(path) {
path.type; // $ExpectType "BinaryExpression"
if (t.isIdentifier(path.node.left)) {
// ...
}
// $ExpectType [NodePath<BinaryExpression>]
path.replaceWith(t.binaryExpression('**', path.node.left, t.numericLiteral(2)));
path.parentPath.replaceWith(
t.expressionStatement(t.stringLiteral("Anyway the wind blows, doesn't really matter to me, to me.")),
);
// $ExpectType [NodePath<BinaryExpression>]
path.replaceInline(t.binaryExpression('**', path.node.left, t.numericLiteral(2)));
// $ExpectType [NodePath<Node>]
path.replaceWithSourceString('3 * 4') as [NodePath];
// $ExpectType [NodePath<BinaryExpression>, NodePath<ExpressionStatement>]
path.replaceInline([
t.binaryExpression('**', path.node.left, t.numericLiteral(2)),
t.expressionStatement(t.stringLiteral("Anyway the wind blows, doesn't really matter to me, to me.")),
] as const);
path.parentPath.remove();
},
Identifier(path) {
path.type; // $ExpectType "Identifier"
if (path.isReferencedIdentifier()) {
// ...
}
if (t.isQualifiedTypeIdentifier(path.node, path.parent)) {
// ...
}
},
ReturnStatement(path) {
path.type; // $ExpectType "ReturnStatement"
// $ExpectType [NodePath<ExpressionStatement>, NodePath<ExpressionStatement>, NodePath<ExpressionStatement>]
path.replaceWithMultiple([
t.expressionStatement(t.stringLiteral('Is this the real life?')),
t.expressionStatement(t.stringLiteral('Is this just fantasy?')),
t.expressionStatement(t.stringLiteral('(Enjoy singing the rest of the song in your head)')),
] as const);
},
FunctionDeclaration(path, state) {
path.type; // $ExpectType "FunctionDeclaration"
path.replaceWithSourceString(`function add(a, b) {
return a + b;
}`);
// $ExpectType [NodePath<ExpressionStatement>]
path.get('body').unshiftContainer('body', t.expressionStatement(t.stringLiteral('Start of function')));
// $ExpectType [NodePath<ExpressionStatement>]
path.get('body').pushContainer('body', t.expressionStatement(t.stringLiteral('End of function')));
// $ExpectType [NodePath<ExpressionStatement>]
path.insertBefore(t.expressionStatement(t.stringLiteral("Because I'm easy come, easy go.")));
// $ExpectType [NodePath<ExpressionStatement>]
path.insertAfter(t.expressionStatement(t.stringLiteral('A little high, little low.')));
path.remove();
if (path.scope.hasBinding('n')) {
// ...
}
if (path.scope.hasOwnBinding('n')) {
// ...
}
const id1 = path.scope.generateUidIdentifier('uid');
id1.type;
id1.name;
const id2 = path.scope.generateUidIdentifier('uid');
id2.type;
id2.name;
const id = path.scope.generateUidIdentifierBasedOnNode(path.node.id!);
path.remove();
path.scope.parent.push({ id });
path.scope.parent.push({ id, init: t.stringLiteral('foo'), kind: 'const' });
path.scope.rename('n', 'x');
path.scope.rename('n');
path.scope.crawl();
// @ts-expect-error
path.pushContainer('returnType', t.stringLiteral('hello'));
// @ts-expect-error
path.unshiftContainer('returnType', t.stringLiteral('hello'));
},
ExportDefaultDeclaration(path) {
path.type; // $ExpectType "ExportDefaultDeclaration"
{
const [stringPath, booleanPath] = path.replaceWithMultiple([
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.replaceWithMultiple<[t.StringLiteral, t.BooleanLiteral]>([
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [newPath] = path.insertBefore(t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
{
const [newPath] = path.insertAfter(t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
},
SequenceExpression(path) {
path.type; // $ExpectType "SequenceExpression"
{
const [newPath] = path.unshiftContainer('expressions', t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
{
const [newPath] = path.pushContainer('expressions', t.stringLiteral('hello'));
// $ExpectType NodePath<StringLiteral>
newPath;
}
{
const [stringPath, booleanPath] = path.unshiftContainer('expressions', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.pushContainer('expressions', [
t.stringLiteral('hello'),
t.booleanLiteral(false),
]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.unshiftContainer<
t.SequenceExpression,
'expressions',
[t.StringLiteral, t.BooleanLiteral]
>('expressions', [t.stringLiteral('hello'), t.booleanLiteral(false)]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
{
const [stringPath, booleanPath] = path.pushContainer<
t.SequenceExpression,
'expressions',
[t.StringLiteral, t.BooleanLiteral]
>('expressions', [t.stringLiteral('hello'), t.booleanLiteral(false)]);
// $ExpectType NodePath<StringLiteral>
stringPath;
// $ExpectType NodePath<BooleanLiteral>
booleanPath;
}
},
};
// Binding.kind
const BindingKindTest: Visitor = {
Identifier(path) {
path.type; // $ExpectType "Identifier"
const kind = path.scope.getBinding('str')!.kind;
kind === 'module';
kind === 'const';
kind === 'let';
kind === 'var';
// @ts-expect-error
kind === 'anythingElse';
},
};
interface SomeVisitorState {
someState: string;
}
const VisitorStateTest: TraverseOptions<SomeVisitorState> = {
enter(path, state) {
let actualType = path.type;
const expectedType: t.Node['type'] = actualType;
actualType = ast.type;
// $ExpectType SomeVisitorState
state;
// $ExpectType SomeVisitorState
this;
},
exit(path, state) {
let actualType = path.type;
const expectedType: t.Node['type'] = actualType;
actualType = ast.type;
// $ExpectType SomeVisitorState
state;
// $ExpectType SomeVisitorState
this;
},
Identifier(path, state) {
path.type; // $ExpectType "Identifier"
// $ExpectType SomeVisitorState
state;
// $ExpectType SomeVisitorState
this;
},
FunctionDeclaration: {
enter(path, state) {
path.type; // $ExpectType "FunctionDeclaration"
// $ExpectType SomeVisitorState
state;
// $ExpectType SomeVisitorState
this;
},
exit(path, state) {
path.type; // $ExpectType "FunctionDeclaration"
// $ExpectType SomeVisitorState
state;
// $ExpectType SomeVisitorState
this;
},
},
};
traverse(ast, VisitorStateTest, undefined, { someState: 'test' });
const VisitorAliasTest: Visitor = {
Function() {},
Expression() {},
};
const hub = new Hub();
// $ExpectType string | undefined
hub.getCode();
declare const astExpression: t.Expression;
traverse.visitors; // $ExpectType typeof visitors
// $ExpectType Visitor<unknown>
visitors.merge([
{
Expression(path) {
let actualType = path.type;
const expectedType: t.Expression['type'] = actualType;
actualType = astExpression.type;
},
},
{
Expression(path) {
let actualType = path.type;
const expectedType: t.Expression['type'] = actualType;
actualType = astExpression.type;
},
},
]);
function testNullishPath(
optionalPath: NodePath<t.Node | null>,
nullPath: NodePath<null>,
undefinedPath: NodePath<undefined>,
unknownPath: NodePath<unknown>,
) {
nullPath.type; // $ExpectType undefined
undefinedPath.type; // $ExpectType undefined
unknownPath.type; // $ExpectAssignable t.Node['type'] | undefined
let actualType = optionalPath.type;
const expectedType: t.Node['type'] | undefined = actualType;
actualType = expectedType;
}
function testEnsureBlock(path: NodePath<t.ArrowFunctionExpression>) {
path.ensureBlock();
path.node.body; // $ExpectType BlockStatement
}
const optionsWithDenylist: TraverseOptions = {
denylist: ['TypeAnnotation'],
};
const optionsWithInvalidDenylist: TraverseOptions = {
// @ts-expect-error
denylist: ['SomeRandomType'],
};
const objectTypeAnnotation: NodePath<t.ObjectTypeAnnotation> = new NodePath<t.ObjectTypeAnnotation>(
null as any,
{} as any,
);
objectTypeAnnotation.get('indexers'); // $ExpectType NodePathResult<ObjectTypeIndexer[] | undefined>
// Test that NodePath can be narrowed from union to single type
const path: NodePath<t.ExportDefaultDeclaration | t.ExportNamedDeclaration> = new NodePath<t.ExportNamedDeclaration>(
null as any,
{} as any,
);
if (path.isExportNamedDeclaration()) {
path.type; // $ExpectType "ExportNamedDeclaration"
}
const nullPath: NodePath<t.Identifier | undefined> = new NodePath<t.Identifier | undefined>(null as any, {} as any);
nullPath.type; // $ExpectType "Identifier" | undefined
if (nullPath.hasNode()) {
nullPath.type; // $ExpectType "Identifier"
}
const file: t.File = {} as any;
const newPath = NodePath.get({
hub: {} as any,
parentPath: null,
parent: file,
container: file,
key: 'program',
}).setContext();
newPath; // $ExpectType NodePath<Program>
const program: t.Program = {} as any;
// $ExpectType NodePath<Statement>
NodePath.get({
hub: {} as any,
parentPath: null,
parent: program,
container: program,
listKey: 'body',
key: 0,
});
const binding = new Binding({
identifier: {} as any,
scope: {} as any,
path: {} as any,
kind: 'unknown',
});
binding.setValue('value');
binding.deopValue();
binding.clearValue();
binding.reassign(newPath.get('body')[0]);
binding.reference(newPath.get('body')[0]);
binding.dereference();
newPath.scope.checkBlockScopedCollisions(binding, 'local', 'name', {});
const booleanVar: boolean = true as boolean;
const identifier = newPath.getBindingIdentifiers();
identifier; // $ExpectType Record<string, Identifier>
const identifierFalse = newPath.getBindingIdentifiers(false);
identifierFalse; // $ExpectType Record<string, Identifier>
const identifierTrue = newPath.getBindingIdentifiers(true);
identifierTrue; // $ExpectType Record<string, Identifier[]>
const identifierBoolean = newPath.getBindingIdentifiers(booleanVar);
identifierBoolean; // $ExpectType Record<string, Identifier | Identifier[]>
const outerIdentifier = newPath.getOuterBindingIdentifiers();
outerIdentifier; // $ExpectType Record<string, Identifier>
const outerIdentifierFalse = newPath.getOuterBindingIdentifiers(false);
outerIdentifierFalse; // $ExpectType Record<string, Identifier>
const outerIdentifierTrue = newPath.getOuterBindingIdentifiers(true);
outerIdentifierTrue; // $ExpectType Record<string, Identifier[]>
const outerIdentifierBoolean = newPath.getOuterBindingIdentifiers(booleanVar);
outerIdentifierBoolean; // $ExpectType Record<string, Identifier | Identifier[]>
const identifierPath = newPath.getBindingIdentifierPaths();
identifierPath; // $ExpectType Record<string, NodePath<Identifier>>
const identifierPathFalse = newPath.getBindingIdentifierPaths(false);
identifierPathFalse; // $ExpectType Record<string, NodePath<Identifier>>
const identifierPathTrue = newPath.getBindingIdentifierPaths(true);
identifierPathTrue; // $ExpectType Record<string, NodePath<Identifier>[]>
const identifierPathBoolean = newPath.getBindingIdentifierPaths(booleanVar);
identifierPathBoolean; // $ExpectType Record<string, NodePath<Identifier> | NodePath<Identifier>[]>
const outerIdentifierPath = newPath.getOuterBindingIdentifierPaths();
outerIdentifierPath; // $ExpectType Record<string, NodePath<Identifier>>
const outerIdentifierPathFalse = newPath.getOuterBindingIdentifierPaths(false);
outerIdentifierPathFalse; // $ExpectType Record<string, NodePath<Identifier>>
const outerIdentifierPathTrue = newPath.getOuterBindingIdentifierPaths(true);
outerIdentifierPathTrue; // $ExpectType Record<string, NodePath<Identifier>[]>
const outerIdentifierPathBoolean = newPath.getOuterBindingIdentifierPaths(booleanVar);
outerIdentifierPathBoolean; // $ExpectType Record<string, NodePath<Identifier> | NodePath<Identifier>[]>

1464
types/babel__traverse/ts4.3/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"dom",
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../../",
"typeRoots": [
"../../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"@babel/*": [
"babel__*"
]
}
},
"files": [
"index.d.ts",
"babel__traverse-tests.ts"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "@definitelytyped/dtslint/dt.json" }