diff --git a/src/interfaces/nodes/IFunctionNode.d.ts b/src/interfaces/nodes/IFunctionNode.d.ts index 50ed7d98..9665db0b 100644 --- a/src/interfaces/nodes/IFunctionNode.d.ts +++ b/src/interfaces/nodes/IFunctionNode.d.ts @@ -1,10 +1,11 @@ +import { IBlockStatementNode } from "./IBlockStatementNode"; import { IIdentifierNode } from "./IIdentifierNode"; import { INode } from "./INode"; export interface IFunctionNode extends INode { id: IIdentifierNode; params: IIdentifierNode[]; - body: INode[]; + body: IBlockStatementNode; generator: boolean; expression: boolean; } diff --git a/src/types/TBlockScopeNode.d.ts b/src/types/TBlockScopeNode.d.ts index 6723bc78..28968cc7 100644 --- a/src/types/TBlockScopeNode.d.ts +++ b/src/types/TBlockScopeNode.d.ts @@ -1,6 +1,5 @@ import { IBlockStatementNode } from "../interfaces/nodes/IBlockStatementNode"; import { ICatchClauseNode } from "../interfaces/nodes/ICatchClauseNode"; -import { IFunctionNode } from "../interfaces/nodes/IFunctionNode"; import { IProgramNode } from "../interfaces/nodes/IProgramNode"; -export type TBlockScopeNode = IBlockStatementNode|ICatchClauseNode|IFunctionNode|IProgramNode; \ No newline at end of file +export type TBlockScopeNode = IBlockStatementNode|ICatchClauseNode|IProgramNode; \ No newline at end of file diff --git a/test/NodeUtils.spec.ts b/test/NodeUtils.spec.ts index 51a837f3..73611ed5 100644 --- a/test/NodeUtils.spec.ts +++ b/test/NodeUtils.spec.ts @@ -1,10 +1,12 @@ import { IBlockStatementNode } from "../src/interfaces/nodes/IBlockStatementNode"; import { IIdentifierNode } from "../src/interfaces/nodes/IIdentifierNode"; import { ILiteralNode } from "../src/interfaces/nodes/ILiteralNode"; +import { IProgramNode } from "../src/interfaces/nodes/IProgramNode"; import { NodeType } from "../src/enums/NodeType"; import { NodeUtils } from '../src/NodeUtils'; +import {IFunctionDeclarationNode} from "../src/interfaces/nodes/IFunctionDeclarationNode"; let assert: any = require('chai').assert; @@ -70,14 +72,14 @@ describe('NodeUtils', () => { }; literalNode = { - type: NodeType.Identifier, + type: NodeType.Literal, value: 'string', raw: `'string'`, 'x-verbatim-property': `'string'` }; blockStatementNode = { - type: NodeType.Literal, + type: NodeType.BlockStatement, body: [ identifierNode, literalNode @@ -98,4 +100,178 @@ describe('NodeUtils', () => { assert.deepEqual(NodeUtils.getBlockScopeNodeByIndex(identifierNode, 1), identifierNode); }); }); + + describe('getBlockScopeOfNode (node: INode, depth: number = 0): TBlockScopeNode', () => { + let blockStatementNode: IBlockStatementNode, + identifierNode: IIdentifierNode, + functionDeclarationNode: IFunctionDeclarationNode, + literalNode: ILiteralNode, + programNode: IProgramNode; + + beforeEach(() => { + identifierNode = { + type: NodeType.Identifier, + name: 'identifier', + }; + + literalNode = { + type: NodeType.Literal, + value: 'string', + raw: `'string'`, + 'x-verbatim-property': `'string'` + }; + + blockStatementNode = { + type: NodeType.BlockStatement, + body: [ + identifierNode, + literalNode + ] + }; + + functionDeclarationNode = { + type: NodeType.FunctionDeclaration, + id: { + type: NodeType.Identifier, + name: 'test' + }, + params: [], + body: blockStatementNode, + generator: false, + expression: false + }; + + programNode = { + type: NodeType.Program, + body: [functionDeclarationNode] + }; + + programNode['parentNode'] = programNode; + functionDeclarationNode['parentNode'] = programNode; + blockStatementNode['parentNode'] = functionDeclarationNode; + identifierNode['parentNode'] = blockStatementNode; + literalNode['parentNode'] = blockStatementNode; + }); + + it('should return block-scope node for given node', () => { + assert.deepEqual(NodeUtils.getBlockScopeOfNode(identifierNode), blockStatementNode); + assert.deepEqual(NodeUtils.getBlockScopeOfNode(identifierNode, 1), programNode); + assert.deepEqual(NodeUtils.getBlockScopeOfNode(functionDeclarationNode), programNode); + assert.deepEqual(NodeUtils.getBlockScopeOfNode(programNode), programNode); + }); + }); + + describe('insertNodeAtIndex (blockScopeBody: INode[], node: INode, index: number): void', () => { + let blockStatementNode: IBlockStatementNode, + expectedBlockStatementNode: IBlockStatementNode, + identifierNode: IIdentifierNode, + literalNode: ILiteralNode; + + beforeEach(() => { + identifierNode = { + type: NodeType.Identifier, + name: 'identifier' + }; + + literalNode = { + type: NodeType.Literal, + value: 'string', + raw: `'string'`, + 'x-verbatim-property': `'string'` + }; + + blockStatementNode = { + type: NodeType.BlockStatement, + body: [ + identifierNode + ] + }; + + expectedBlockStatementNode = Object.assign({}, blockStatementNode); + expectedBlockStatementNode['body'].push(literalNode); + + NodeUtils.insertNodeAtIndex(blockStatementNode.body, literalNode, 1); + }); + + it('should insert given node in block-scope body at index', () => { + assert.deepEqual(blockStatementNode, expectedBlockStatementNode); + }); + }); + + describe('parentize (node: INode): void', () => { + let blockStatementNode: IBlockStatementNode, + identifierNode: IIdentifierNode, + literalNode: ILiteralNode, + programNode: IProgramNode; + + beforeEach(() => { + identifierNode = { + type: NodeType.Identifier, + name: 'identifier' + }; + + literalNode = { + type: NodeType.Literal, + value: 'string', + raw: `'string'`, + 'x-verbatim-property': `'string'` + }; + + blockStatementNode = { + type: NodeType.BlockStatement, + body: [ + identifierNode, + literalNode + ] + }; + + programNode = { + type: NodeType.Program, + body: [blockStatementNode] + }; + + NodeUtils.parentize(blockStatementNode); + }); + + it('should parentize given AST-tree', () => { + assert.deepEqual(blockStatementNode['parentNode'], programNode); + assert.deepEqual(identifierNode['parentNode'], blockStatementNode); + assert.deepEqual(literalNode['parentNode'], blockStatementNode); + }); + }); + + describe('prependNode (blockScopeBody: INode[], node: INode): void', () => { + let blockStatementNode: IBlockStatementNode, + expectedBlockStatementNode: IBlockStatementNode, + identifierNode: IIdentifierNode, + literalNode: ILiteralNode; + + beforeEach(() => { + identifierNode = { + type: NodeType.Identifier, + name: 'identifier' + }; + + literalNode = { + type: NodeType.Literal, + value: 'string', + raw: `'string'`, + 'x-verbatim-property': `'string'` + }; + + blockStatementNode = { + type: NodeType.Literal, + body: [identifierNode] + }; + + expectedBlockStatementNode = Object.assign({}, blockStatementNode); + expectedBlockStatementNode['body'].unshift(literalNode); + + NodeUtils.prependNode(blockStatementNode.body, literalNode) + }); + + it('should prepend given node to a `BlockStatement` node body', () => { + assert.deepEqual(blockStatementNode, expectedBlockStatementNode); + }); + }); }); \ No newline at end of file