test(compiler): tests for ast transform
This commit is contained in:
parent
10c1a2b332
commit
5f49018601
@ -12,7 +12,7 @@ import {
|
||||
AttributeNode
|
||||
} from '../src/ast'
|
||||
|
||||
describe('base parser', () => {
|
||||
describe('compiler: parse', () => {
|
||||
describe('Text', () => {
|
||||
test('simple text', () => {
|
||||
const ast = parse('some text')
|
||||
|
128
packages/compiler-core/__tests__/transform.spec.ts
Normal file
128
packages/compiler-core/__tests__/transform.spec.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import { parse } from '../src/parse'
|
||||
import { transform, Transform } from '../src/transform'
|
||||
import { ElementNode, NodeTypes } from '../src/ast'
|
||||
import { ErrorCodes, createCompilerError } from '../src/errors'
|
||||
|
||||
describe('compiler: transform', () => {
|
||||
test('context state', () => {
|
||||
const ast = parse(`<div>hello {{ world }}</div>`)
|
||||
|
||||
// manually store call arguments because context is mutable and shared
|
||||
// across calls
|
||||
const calls: any[] = []
|
||||
const plugin: Transform = (node, context) => {
|
||||
calls.push([node, Object.assign({}, context)])
|
||||
}
|
||||
|
||||
transform(ast, {
|
||||
transforms: [plugin]
|
||||
})
|
||||
|
||||
const div = ast.children[0] as ElementNode
|
||||
expect(calls.length).toBe(3)
|
||||
expect(calls[0]).toMatchObject([
|
||||
div,
|
||||
{
|
||||
parent: ast,
|
||||
ancestors: [ast],
|
||||
childIndex: 0
|
||||
}
|
||||
])
|
||||
expect(calls[1]).toMatchObject([
|
||||
div.children[0],
|
||||
{
|
||||
parent: div,
|
||||
ancestors: [ast, div],
|
||||
childIndex: 0
|
||||
}
|
||||
])
|
||||
expect(calls[2]).toMatchObject([
|
||||
div.children[1],
|
||||
{
|
||||
parent: div,
|
||||
ancestors: [ast, div],
|
||||
childIndex: 1
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
test('context.replaceNode', () => {
|
||||
const ast = parse(`<div/><span/>`)
|
||||
const plugin: Transform = (node, context) => {
|
||||
if (node.type === NodeTypes.ELEMENT && node.tag === 'div') {
|
||||
// change the node to <p>
|
||||
context.replaceNode(
|
||||
Object.assign({}, node, {
|
||||
tag: 'p',
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.TEXT,
|
||||
content: 'hello',
|
||||
isEmpty: false
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
const spy = jest.fn(plugin)
|
||||
transform(ast, {
|
||||
transforms: [spy]
|
||||
})
|
||||
|
||||
expect(ast.children.length).toBe(2)
|
||||
const newElement = ast.children[0] as ElementNode
|
||||
expect(newElement.tag).toBe('p')
|
||||
expect(spy).toHaveBeenCalledTimes(3)
|
||||
// should traverse the children of replaced node
|
||||
expect(spy.mock.calls[1][0]).toBe(newElement.children[0])
|
||||
// should traverse the node after the replaced node
|
||||
expect(spy.mock.calls[2][0]).toBe(ast.children[1])
|
||||
})
|
||||
|
||||
test('context.removeNode', () => {
|
||||
const ast = parse(`<span/><div/><span/>`)
|
||||
const c1 = ast.children[0]
|
||||
const c2 = ast.children[2]
|
||||
|
||||
const plugin: Transform = (node, context) => {
|
||||
if (node.type === NodeTypes.ELEMENT && node.tag === 'div') {
|
||||
context.removeNode()
|
||||
}
|
||||
}
|
||||
const spy = jest.fn(plugin)
|
||||
transform(ast, {
|
||||
transforms: [spy]
|
||||
})
|
||||
|
||||
expect(ast.children.length).toBe(2)
|
||||
expect(ast.children[0]).toBe(c1)
|
||||
expect(ast.children[1]).toBe(c2)
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(3)
|
||||
// should traverse nodes around removed
|
||||
expect(spy.mock.calls[0][0]).toBe(c1)
|
||||
expect(spy.mock.calls[2][0]).toBe(c2)
|
||||
})
|
||||
|
||||
test('onError option', () => {
|
||||
const ast = parse(`<div/>`)
|
||||
const loc = ast.children[0].loc.start
|
||||
const plugin: Transform = (node, context) => {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_INVALID_END_TAG, node.loc.start)
|
||||
)
|
||||
}
|
||||
const spy = jest.fn()
|
||||
transform(ast, {
|
||||
transforms: [plugin],
|
||||
onError: spy
|
||||
})
|
||||
expect(spy.mock.calls[0]).toMatchObject([
|
||||
{
|
||||
code: ErrorCodes.X_INVALID_END_TAG,
|
||||
loc
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
@ -46,9 +46,12 @@ function createTransformContext(
|
||||
},
|
||||
...options,
|
||||
parent: root,
|
||||
ancestors: [root],
|
||||
ancestors: [],
|
||||
childIndex: 0,
|
||||
replaceNode(node) {
|
||||
if (__DEV__ && context.nodeRemoved) {
|
||||
throw new Error(`node being replaced is already removed`)
|
||||
}
|
||||
context.parent.children[context.childIndex] = node
|
||||
},
|
||||
removeNode() {
|
||||
@ -85,9 +88,9 @@ function traverseNode(
|
||||
// apply transform plugins
|
||||
const transforms = context.transforms
|
||||
for (let i = 0; i < transforms.length; i++) {
|
||||
const transform = transforms[i]
|
||||
const plugin = transforms[i]
|
||||
context.nodeRemoved = false
|
||||
transform(node, context)
|
||||
plugin(node, context)
|
||||
if (context.nodeRemoved) {
|
||||
return
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user