mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(compiler-cli): update ast factories to account for type nodes
Updates the Babel and TypeScript AST factories to account to produce type nodes.
This commit is contained in:
committed by
Matthew Beck (Berry)
parent
1639fc565b
commit
ed9750d6d7
@@ -11,8 +11,10 @@ import {assert} from '../../../../linker';
|
||||
import {
|
||||
AstFactory,
|
||||
BinaryOperator,
|
||||
BuiltInType,
|
||||
LeadingComment,
|
||||
ObjectLiteralProperty,
|
||||
Parameter,
|
||||
SourceMapRange,
|
||||
TemplateLiteral,
|
||||
VariableDeclarationType,
|
||||
@@ -104,40 +106,40 @@ export class BabelAstFactory implements AstFactory<
|
||||
|
||||
createFunctionDeclaration(
|
||||
functionName: string,
|
||||
parameters: string[],
|
||||
parameters: Parameter<t.TSType>[],
|
||||
body: t.Statement,
|
||||
): t.Statement {
|
||||
assert(body, t.isBlockStatement, 'a block');
|
||||
return t.functionDeclaration(
|
||||
t.identifier(functionName),
|
||||
parameters.map((param) => t.identifier(param)),
|
||||
parameters.map((param) => identifierWithType(param.name, param.type)),
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
createArrowFunctionExpression(
|
||||
parameters: string[],
|
||||
parameters: Parameter<t.TSType>[],
|
||||
body: t.Statement | t.Expression,
|
||||
): t.Expression {
|
||||
if (t.isStatement(body)) {
|
||||
assert(body, t.isBlockStatement, 'a block');
|
||||
}
|
||||
return t.arrowFunctionExpression(
|
||||
parameters.map((param) => t.identifier(param)),
|
||||
parameters.map((param) => identifierWithType(param.name, param.type)),
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
createFunctionExpression(
|
||||
functionName: string | null,
|
||||
parameters: string[],
|
||||
parameters: Parameter<t.TSType>[],
|
||||
body: t.Statement,
|
||||
): t.Expression {
|
||||
assert(body, t.isBlockStatement, 'a block');
|
||||
const name = functionName !== null ? t.identifier(functionName) : null;
|
||||
return t.functionExpression(
|
||||
name,
|
||||
parameters.map((param) => t.identifier(param)),
|
||||
parameters.map((param) => identifierWithType(param.name, param.type)),
|
||||
body,
|
||||
);
|
||||
}
|
||||
@@ -228,10 +230,11 @@ export class BabelAstFactory implements AstFactory<
|
||||
createVariableDeclaration(
|
||||
variableName: string,
|
||||
initializer: t.Expression | null,
|
||||
type: VariableDeclarationType,
|
||||
variableType: VariableDeclarationType,
|
||||
type: t.TSType | null,
|
||||
): t.Statement {
|
||||
return t.variableDeclaration(type, [
|
||||
t.variableDeclarator(t.identifier(variableName), initializer),
|
||||
return t.variableDeclaration(variableType, [
|
||||
t.variableDeclarator(identifierWithType(variableName, type), initializer),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -265,6 +268,79 @@ export class BabelAstFactory implements AstFactory<
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
createBuiltInType(type: BuiltInType): t.TSType {
|
||||
switch (type) {
|
||||
case 'any':
|
||||
return t.tsAnyKeyword();
|
||||
case 'boolean':
|
||||
return t.tsBooleanKeyword();
|
||||
case 'number':
|
||||
return t.tsNumberKeyword();
|
||||
case 'string':
|
||||
return t.tsStringKeyword();
|
||||
case 'function':
|
||||
return t.tsTypeReference(t.identifier('Function'));
|
||||
case 'never':
|
||||
return t.tsNeverKeyword();
|
||||
case 'unknown':
|
||||
return t.tsUnknownKeyword();
|
||||
}
|
||||
}
|
||||
|
||||
createExpressionType(expression: t.Expression, typeParams: t.TSType[] | null): t.TSType {
|
||||
const typeName = getEntityTypeFromExpression(expression);
|
||||
return t.tsTypeReference(
|
||||
typeName,
|
||||
typeParams ? t.tsTypeParameterInstantiation(typeParams) : null,
|
||||
);
|
||||
}
|
||||
|
||||
createArrayType(elementType: t.TSType): t.TSType {
|
||||
return t.tsArrayType(elementType);
|
||||
}
|
||||
|
||||
createMapType(valueType: t.TSType): t.TSType {
|
||||
const keySignature = identifierWithType('key', this.createBuiltInType('string'));
|
||||
return t.tsTypeLiteral([t.tsIndexSignature([keySignature], t.tsTypeAnnotation(valueType))]);
|
||||
}
|
||||
|
||||
transplantType(type: t.TSType): t.TSType {
|
||||
if (t.isNode(type) && t.isTSType(type)) {
|
||||
return type;
|
||||
}
|
||||
throw new Error('Attempting to transplant a type node from a non-Babel AST: ' + type);
|
||||
}
|
||||
}
|
||||
|
||||
function getEntityTypeFromExpression(expression: t.Expression): t.Identifier | t.TSQualifiedName {
|
||||
if (t.isIdentifier(expression)) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(expression)) {
|
||||
const left = getEntityTypeFromExpression(expression.object);
|
||||
|
||||
if (!t.isIdentifier(expression.property)) {
|
||||
throw new Error(
|
||||
`Unsupported property access for type reference: ${expression.property.type}`,
|
||||
);
|
||||
}
|
||||
|
||||
return t.tsQualifiedName(left, expression.property);
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported expression for type reference: ${expression.type}`);
|
||||
}
|
||||
|
||||
function identifierWithType(name: string, type: t.TSType | null): t.Identifier {
|
||||
const node = t.identifier(name);
|
||||
|
||||
if (type !== null) {
|
||||
node.typeAnnotation = t.tsTypeAnnotation(type);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function isLExpression(expr: t.Expression): expr is Extract<t.LVal, t.Expression> {
|
||||
|
||||
@@ -149,9 +149,16 @@ describe('BabelAstFactory', () => {
|
||||
describe('createFunctionDeclaration()', () => {
|
||||
it('should create a function declaration node with the given name, parameters and body statements', () => {
|
||||
const stmts = statement.ast`{x = 10; y = 20;}`;
|
||||
const fn = factory.createFunctionDeclaration('foo', ['arg1', 'arg2'], stmts);
|
||||
const fn = factory.createFunctionDeclaration(
|
||||
'foo',
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
stmts,
|
||||
);
|
||||
expect(generate(fn).code).toEqual(
|
||||
['function foo(arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
['function foo(arg1, arg2: number) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -159,18 +166,32 @@ describe('BabelAstFactory', () => {
|
||||
describe('createFunctionExpression()', () => {
|
||||
it('should create a function expression node with the given name, parameters and body statements', () => {
|
||||
const stmts = statement.ast`{x = 10; y = 20;}`;
|
||||
const fn = factory.createFunctionExpression('foo', ['arg1', 'arg2'], stmts);
|
||||
const fn = factory.createFunctionExpression(
|
||||
'foo',
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
stmts,
|
||||
);
|
||||
expect(t.isStatement(fn)).toBe(false);
|
||||
expect(generate(fn).code).toEqual(
|
||||
['function foo(arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
['function foo(arg1, arg2: number) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should create an anonymous function expression node if the name is null', () => {
|
||||
const stmts = statement.ast`{x = 10; y = 20;}`;
|
||||
const fn = factory.createFunctionExpression(null, ['arg1', 'arg2'], stmts);
|
||||
const fn = factory.createFunctionExpression(
|
||||
null,
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
stmts,
|
||||
);
|
||||
expect(generate(fn).code).toEqual(
|
||||
['function (arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
['function (arg1, arg2: number) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -178,8 +199,14 @@ describe('BabelAstFactory', () => {
|
||||
describe('createArrowFunctionExpression()', () => {
|
||||
it('should create an arrow function with an implicit return if a single statement is provided', () => {
|
||||
const expr = expression.ast`arg2 + arg1`;
|
||||
const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], expr);
|
||||
expect(generate(fn).code).toEqual('(arg1, arg2) => arg2 + arg1');
|
||||
const fn = factory.createArrowFunctionExpression(
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
expr,
|
||||
);
|
||||
expect(generate(fn).code).toEqual('(arg1, arg2: number) => arg2 + arg1');
|
||||
});
|
||||
|
||||
it('should create an arrow function with an implicit return object literal', () => {
|
||||
@@ -190,9 +217,15 @@ describe('BabelAstFactory', () => {
|
||||
|
||||
it('should create an arrow function with a body when an array of statements is provided', () => {
|
||||
const stmts = statement.ast`{x = 10; y = 20; return x + y;}`;
|
||||
const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], stmts);
|
||||
const fn = factory.createArrowFunctionExpression(
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
stmts,
|
||||
);
|
||||
expect(generate(fn).code).toEqual(
|
||||
['(arg1, arg2) => {', ' x = 10;', ' y = 20;', ' return x + y;', '}'].join('\n'),
|
||||
['(arg1, arg2: number) => {', ' x = 10;', ' y = 20;', ' return x + y;', '}'].join('\n'),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -378,26 +411,37 @@ describe('BabelAstFactory', () => {
|
||||
describe('createVariableDeclaration()', () => {
|
||||
it('should create a variable declaration statement node for the given variable name and initializer', () => {
|
||||
const initializer = expression.ast`42`;
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'let');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'let', null);
|
||||
expect(generate(varDecl).code).toEqual('let foo = 42;');
|
||||
});
|
||||
|
||||
it('should create a constant declaration statement node for the given variable name and initializer', () => {
|
||||
const initializer = expression.ast`42`;
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'const');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'const', null);
|
||||
expect(generate(varDecl).code).toEqual('const foo = 42;');
|
||||
});
|
||||
|
||||
it('should create a downleveled variable declaration statement node for the given variable name and initializer', () => {
|
||||
const initializer = expression.ast`42`;
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'var');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'var', null);
|
||||
expect(generate(varDecl).code).toEqual('var foo = 42;');
|
||||
});
|
||||
|
||||
it('should create an uninitialized variable declaration statement node for the given variable name and a null initializer', () => {
|
||||
const varDecl = factory.createVariableDeclaration('foo', null, 'let');
|
||||
const varDecl = factory.createVariableDeclaration('foo', null, 'let', null);
|
||||
expect(generate(varDecl).code).toEqual('let foo;');
|
||||
});
|
||||
|
||||
it('should create a variable declaration with a type', () => {
|
||||
const initializer = expression.ast`42`;
|
||||
const varDecl = factory.createVariableDeclaration(
|
||||
'foo',
|
||||
initializer,
|
||||
'let',
|
||||
factory.createBuiltInType('number'),
|
||||
);
|
||||
expect(generate(varDecl).code).toEqual('let foo: number = 42;');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createRegularExpressionLiteral()', () => {
|
||||
@@ -429,6 +473,55 @@ describe('BabelAstFactory', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBuiltInType()', () => {
|
||||
it('should create type annotations for built in types', () => {
|
||||
expect(generate(factory.createBuiltInType('any')).code).toEqual('any');
|
||||
expect(generate(factory.createBuiltInType('boolean')).code).toEqual('boolean');
|
||||
expect(generate(factory.createBuiltInType('number')).code).toEqual('number');
|
||||
expect(generate(factory.createBuiltInType('string')).code).toEqual('string');
|
||||
expect(generate(factory.createBuiltInType('never')).code).toEqual('never');
|
||||
expect(generate(factory.createBuiltInType('unknown')).code).toEqual('unknown');
|
||||
expect(generate(factory.createBuiltInType('function')).code).toEqual('Function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createExpressionType()', () => {
|
||||
it('should create a generic type annotation for an identifier', () => {
|
||||
const id = factory.createIdentifier('MyType');
|
||||
const type = factory.createExpressionType(id, null);
|
||||
expect(generate(type).code).toEqual('MyType');
|
||||
});
|
||||
|
||||
it('should create a generic type annotation for property access', () => {
|
||||
const expr = factory.createPropertyAccess(factory.createIdentifier('ns'), 'MyType');
|
||||
const type = factory.createExpressionType(expr, null);
|
||||
expect(generate(type).code).toEqual('ns.MyType');
|
||||
});
|
||||
|
||||
it('should create a generic type annotation with type parameters', () => {
|
||||
const id = factory.createIdentifier('MyType');
|
||||
const typeParam = factory.createBuiltInType('string');
|
||||
const type = factory.createExpressionType(id, [typeParam]);
|
||||
expect(generate(type).code).toEqual('MyType<string>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createArrayType()', () => {
|
||||
it('should create an array type annotation', () => {
|
||||
const elementType = factory.createBuiltInType('string');
|
||||
const type = factory.createArrayType(elementType);
|
||||
expect(generate(type).code).toEqual('string[]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createMapType()', () => {
|
||||
it('should create an object type with an indexer', () => {
|
||||
const valueType = factory.createBuiltInType('number');
|
||||
const type = factory.createMapType(valueType);
|
||||
expect(generate(type).code).toEqual('{\n [key: string]: number;\n}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSourceMapRange()', () => {
|
||||
it('should attach the `sourceMapRange` to the given `node`', () => {
|
||||
const expr = expression.ast`42`;
|
||||
|
||||
@@ -10,8 +10,10 @@ import ts from 'typescript';
|
||||
import {
|
||||
AstFactory,
|
||||
BinaryOperator,
|
||||
BuiltInType,
|
||||
LeadingComment,
|
||||
ObjectLiteralProperty,
|
||||
Parameter,
|
||||
SourceMapRange,
|
||||
TemplateLiteral,
|
||||
UnaryOperator,
|
||||
@@ -160,7 +162,7 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
|
||||
createFunctionDeclaration(
|
||||
functionName: string,
|
||||
parameters: string[],
|
||||
parameters: Parameter<ts.TypeNode>[],
|
||||
body: ts.Statement,
|
||||
): ts.Statement {
|
||||
if (!ts.isBlock(body)) {
|
||||
@@ -171,7 +173,7 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
undefined,
|
||||
functionName,
|
||||
undefined,
|
||||
parameters.map((param) => ts.factory.createParameterDeclaration(undefined, undefined, param)),
|
||||
parameters.map((param) => this.createParameter(param)),
|
||||
undefined,
|
||||
body,
|
||||
);
|
||||
@@ -179,7 +181,7 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
|
||||
createFunctionExpression(
|
||||
functionName: string | null,
|
||||
parameters: string[],
|
||||
parameters: Parameter<ts.TypeNode>[],
|
||||
body: ts.Statement,
|
||||
): ts.Expression {
|
||||
if (!ts.isBlock(body)) {
|
||||
@@ -190,14 +192,14 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
undefined,
|
||||
functionName ?? undefined,
|
||||
undefined,
|
||||
parameters.map((param) => ts.factory.createParameterDeclaration(undefined, undefined, param)),
|
||||
parameters.map((param) => this.createParameter(param)),
|
||||
undefined,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
createArrowFunctionExpression(
|
||||
parameters: string[],
|
||||
parameters: Parameter<ts.TypeNode>[],
|
||||
body: ts.Statement | ts.Expression,
|
||||
): ts.Expression {
|
||||
if (ts.isStatement(body) && !ts.isBlock(body)) {
|
||||
@@ -207,13 +209,23 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
return ts.factory.createArrowFunction(
|
||||
undefined,
|
||||
undefined,
|
||||
parameters.map((param) => ts.factory.createParameterDeclaration(undefined, undefined, param)),
|
||||
parameters.map((param) => this.createParameter(param)),
|
||||
undefined,
|
||||
undefined,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
private createParameter(param: Parameter<ts.TypeNode>): ts.ParameterDeclaration {
|
||||
return ts.factory.createParameterDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
param.name,
|
||||
undefined,
|
||||
param.type ?? undefined,
|
||||
);
|
||||
}
|
||||
|
||||
createIdentifier = ts.factory.createIdentifier;
|
||||
|
||||
createIfStatement(
|
||||
@@ -330,7 +342,8 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
createVariableDeclaration(
|
||||
variableName: string,
|
||||
initializer: ts.Expression | null,
|
||||
type: VariableDeclarationType,
|
||||
variableType: VariableDeclarationType,
|
||||
type: ts.TypeNode | null,
|
||||
): ts.Statement {
|
||||
return ts.factory.createVariableStatement(
|
||||
undefined,
|
||||
@@ -339,11 +352,11 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
ts.factory.createVariableDeclaration(
|
||||
variableName,
|
||||
undefined,
|
||||
undefined,
|
||||
type ?? undefined,
|
||||
initializer ?? undefined,
|
||||
),
|
||||
],
|
||||
this.VAR_TYPES[type],
|
||||
this.VAR_TYPES[variableType],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -372,6 +385,63 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
createBuiltInType(type: BuiltInType): ts.TypeNode {
|
||||
switch (type) {
|
||||
case 'any':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
|
||||
case 'boolean':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
||||
case 'number':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
||||
case 'string':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
||||
case 'function':
|
||||
return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Function'));
|
||||
case 'never':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword);
|
||||
case 'unknown':
|
||||
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
||||
}
|
||||
}
|
||||
|
||||
createExpressionType(expression: ts.Expression, typeParams: ts.TypeNode[] | null): ts.TypeNode {
|
||||
const typeName = getEntityTypeFromExpression(expression);
|
||||
return ts.factory.createTypeReferenceNode(typeName, typeParams ?? undefined);
|
||||
}
|
||||
|
||||
createArrayType(elementType: ts.TypeNode): ts.TypeNode {
|
||||
return ts.factory.createArrayTypeNode(elementType);
|
||||
}
|
||||
|
||||
createMapType(valueType: ts.TypeNode): ts.TypeNode {
|
||||
return ts.factory.createTypeLiteralNode([
|
||||
ts.factory.createIndexSignature(
|
||||
undefined,
|
||||
[
|
||||
ts.factory.createParameterDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
'key',
|
||||
undefined,
|
||||
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
||||
),
|
||||
],
|
||||
valueType,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
transplantType(type: ts.TypeNode): ts.TypeNode {
|
||||
if (
|
||||
typeof type.kind === 'number' &&
|
||||
typeof type.getSourceFile === 'function' &&
|
||||
ts.isTypeNode(type)
|
||||
) {
|
||||
return type;
|
||||
}
|
||||
throw new Error('Attempting to transplant a type node from a non-TypeScript AST: ' + type);
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: Use this in place of `ts.createTemplateMiddle()`.
|
||||
@@ -418,3 +488,17 @@ export function attachComments(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEntityTypeFromExpression(expression: ts.Expression): ts.EntityName {
|
||||
if (ts.isIdentifier(expression)) {
|
||||
return expression;
|
||||
}
|
||||
if (ts.isPropertyAccessExpression(expression)) {
|
||||
const left = getEntityTypeFromExpression(expression.expression);
|
||||
if (!ts.isIdentifier(expression.name)) {
|
||||
throw new Error(`Unsupported property access for type reference: ${expression.name.text}`);
|
||||
}
|
||||
return ts.factory.createQualifiedName(left, expression.name);
|
||||
}
|
||||
throw new Error(`Unsupported expression for type reference: ${ts.SyntaxKind[expression.kind]}`);
|
||||
}
|
||||
|
||||
@@ -178,8 +178,15 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [body],
|
||||
generate,
|
||||
} = setupStatements('{x = 10; y = 20;}');
|
||||
const fn = factory.createFunctionDeclaration('foo', ['arg1', 'arg2'], body);
|
||||
expect(generate(fn)).toEqual('function foo(arg1, arg2) { x = 10; y = 20; }');
|
||||
const fn = factory.createFunctionDeclaration(
|
||||
'foo',
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
body,
|
||||
);
|
||||
expect(generate(fn)).toEqual('function foo(arg1, arg2: number) { x = 10; y = 20; }');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -189,9 +196,16 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [body],
|
||||
generate,
|
||||
} = setupStatements('{x = 10; y = 20;}');
|
||||
const fn = factory.createFunctionExpression('foo', ['arg1', 'arg2'], body);
|
||||
const fn = factory.createFunctionExpression(
|
||||
'foo',
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
body,
|
||||
);
|
||||
expect(ts.isExpressionStatement(fn)).toBe(false);
|
||||
expect(generate(fn)).toEqual('function foo(arg1, arg2) { x = 10; y = 20; }');
|
||||
expect(generate(fn)).toEqual('function foo(arg1, arg2: number) { x = 10; y = 20; }');
|
||||
});
|
||||
|
||||
it('should create an anonymous function expression node if the name is null', () => {
|
||||
@@ -199,8 +213,15 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [body],
|
||||
generate,
|
||||
} = setupStatements('{x = 10; y = 20;}');
|
||||
const fn = factory.createFunctionExpression(null, ['arg1', 'arg2'], body);
|
||||
expect(generate(fn)).toEqual('function (arg1, arg2) { x = 10; y = 20; }');
|
||||
const fn = factory.createFunctionExpression(
|
||||
null,
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
body,
|
||||
);
|
||||
expect(generate(fn)).toEqual('function (arg1, arg2: number) { x = 10; y = 20; }');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -242,8 +263,14 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [body],
|
||||
generate,
|
||||
} = setupExpressions('arg2 + arg1');
|
||||
const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], body);
|
||||
expect(generate(fn)).toEqual('(arg1, arg2) => arg2 + arg1');
|
||||
const fn = factory.createArrowFunctionExpression(
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
body,
|
||||
);
|
||||
expect(generate(fn)).toEqual('(arg1, arg2: number) => arg2 + arg1');
|
||||
});
|
||||
|
||||
it('should create an arrow function with an implicit return object literal', () => {
|
||||
@@ -260,8 +287,14 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [body],
|
||||
generate,
|
||||
} = setupStatements('{x = 10; y = 20; return x + y;}');
|
||||
const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], body);
|
||||
expect(generate(fn)).toEqual('(arg1, arg2) => { x = 10; y = 20; return x + y; }');
|
||||
const fn = factory.createArrowFunctionExpression(
|
||||
[
|
||||
{name: 'arg1', type: null},
|
||||
{name: 'arg2', type: factory.createBuiltInType('number')},
|
||||
],
|
||||
body,
|
||||
);
|
||||
expect(generate(fn)).toEqual('(arg1, arg2: number) => { x = 10; y = 20; return x + y; }');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -447,7 +480,7 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [initializer],
|
||||
generate,
|
||||
} = setupExpressions(`42`);
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'let');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'let', null);
|
||||
expect(generate(varDecl)).toEqual('let foo = 42;');
|
||||
});
|
||||
|
||||
@@ -456,7 +489,7 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [initializer],
|
||||
generate,
|
||||
} = setupExpressions(`42`);
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'const');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'const', null);
|
||||
expect(generate(varDecl)).toEqual('const foo = 42;');
|
||||
});
|
||||
|
||||
@@ -465,15 +498,29 @@ describe('TypeScriptAstFactory', () => {
|
||||
items: [initializer],
|
||||
generate,
|
||||
} = setupExpressions(`42`);
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'var');
|
||||
const varDecl = factory.createVariableDeclaration('foo', initializer, 'var', null);
|
||||
expect(generate(varDecl)).toEqual('var foo = 42;');
|
||||
});
|
||||
|
||||
it('should create an uninitialized variable declaration statement node for the given variable name and a null initializer', () => {
|
||||
const {generate} = setupStatements();
|
||||
const varDecl = factory.createVariableDeclaration('foo', null, 'let');
|
||||
const varDecl = factory.createVariableDeclaration('foo', null, 'let', null);
|
||||
expect(generate(varDecl)).toEqual('let foo;');
|
||||
});
|
||||
|
||||
it('should create a variable declaration with a type', () => {
|
||||
const {
|
||||
items: [initializer],
|
||||
generate,
|
||||
} = setupExpressions(`42`);
|
||||
const varDecl = factory.createVariableDeclaration(
|
||||
'foo',
|
||||
initializer,
|
||||
'let',
|
||||
factory.createBuiltInType('number'),
|
||||
);
|
||||
expect(generate(varDecl)).toEqual('let foo: number = 42;');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createRegularExpressionLiteral()', () => {
|
||||
@@ -509,6 +556,62 @@ describe('TypeScriptAstFactory', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBuiltInType()', () => {
|
||||
it('should create keyword type nodes for simple types', () => {
|
||||
const {generate} = setupStatements();
|
||||
expect(generate(factory.createBuiltInType('any'))).toEqual('any');
|
||||
expect(generate(factory.createBuiltInType('boolean'))).toEqual('boolean');
|
||||
expect(generate(factory.createBuiltInType('number'))).toEqual('number');
|
||||
expect(generate(factory.createBuiltInType('string'))).toEqual('string');
|
||||
expect(generate(factory.createBuiltInType('never'))).toEqual('never');
|
||||
expect(generate(factory.createBuiltInType('unknown'))).toEqual('unknown');
|
||||
});
|
||||
|
||||
it('should create a type reference for "function"', () => {
|
||||
const {generate} = setupStatements();
|
||||
expect(generate(factory.createBuiltInType('function'))).toEqual('Function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createExpressionType()', () => {
|
||||
it('should create a type reference for an identifier', () => {
|
||||
const {items, generate} = setupExpressions('MyType');
|
||||
const type = factory.createExpressionType(items[0], null);
|
||||
expect(generate(type)).toEqual('MyType');
|
||||
});
|
||||
|
||||
it('should create a type reference for a property access', () => {
|
||||
const {items, generate} = setupExpressions('ns.MyType');
|
||||
const type = factory.createExpressionType(items[0], null);
|
||||
expect(generate(type)).toEqual('ns.MyType');
|
||||
});
|
||||
|
||||
it('should create a type reference with type parameters', () => {
|
||||
const {items, generate} = setupExpressions('MyType');
|
||||
const typeParam = factory.createBuiltInType('string');
|
||||
const type = factory.createExpressionType(items[0], [typeParam]);
|
||||
expect(generate(type)).toEqual('MyType<string>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createArrayType()', () => {
|
||||
it('should create an array type node', () => {
|
||||
const {generate} = setupStatements();
|
||||
const elementType = factory.createBuiltInType('string');
|
||||
const type = factory.createArrayType(elementType);
|
||||
expect(generate(type)).toEqual('string[]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createMapType()', () => {
|
||||
it('should create a type literal with an index signature', () => {
|
||||
const {generate} = setupStatements();
|
||||
const valueType = factory.createBuiltInType('number');
|
||||
const type = factory.createMapType(valueType);
|
||||
expect(generate(type)).toEqual('{\n [key: string]: number;\n}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSourceMapRange()', () => {
|
||||
it('should attach the `sourceMapRange` to the given `node`', () => {
|
||||
const {
|
||||
|
||||
Reference in New Issue
Block a user