test(compiler): transformIf
This commit is contained in:
parent
81fd694dd7
commit
2b4f06b24c
257
packages/compiler-core/__tests__/directives/vIf.spec.ts
Normal file
257
packages/compiler-core/__tests__/directives/vIf.spec.ts
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
import { parse } from '../../src/parse'
|
||||||
|
import { transform } from '../../src/transform'
|
||||||
|
import { transformIf } from '../../src/directives/vIf'
|
||||||
|
import {
|
||||||
|
IfNode,
|
||||||
|
NodeTypes,
|
||||||
|
ElementNode,
|
||||||
|
TextNode,
|
||||||
|
CommentNode
|
||||||
|
} from '../../src/ast'
|
||||||
|
import { ErrorCodes } from '../../src/errors'
|
||||||
|
|
||||||
|
describe('compiler: v-if', () => {
|
||||||
|
describe('transform', () => {
|
||||||
|
test('basic v-if', () => {
|
||||||
|
const ast = parse(`<div v-if="ok"/>`)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(1)
|
||||||
|
expect(node.branches[0].condition!.content).toBe(`ok`)
|
||||||
|
expect(node.branches[0].children.length).toBe(1)
|
||||||
|
expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((node.branches[0].children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('template v-if', () => {
|
||||||
|
const ast = parse(`<template v-if="ok"><div/>hello<p/></template>`)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(1)
|
||||||
|
expect(node.branches[0].condition!.content).toBe(`ok`)
|
||||||
|
expect(node.branches[0].children.length).toBe(3)
|
||||||
|
expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((node.branches[0].children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
expect(node.branches[0].children[1].type).toBe(NodeTypes.TEXT)
|
||||||
|
expect((node.branches[0].children[1] as TextNode).content).toBe(`hello`)
|
||||||
|
expect(node.branches[0].children[2].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((node.branches[0].children[2] as ElementNode).tag).toBe(`p`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('v-if + v-else', () => {
|
||||||
|
const ast = parse(`<div v-if="ok"/><p v-else/>`)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
// should fold branches
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(2)
|
||||||
|
|
||||||
|
const b1 = node.branches[0]
|
||||||
|
expect(b1.condition!.content).toBe(`ok`)
|
||||||
|
expect(b1.children.length).toBe(1)
|
||||||
|
expect(b1.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b1.children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
|
||||||
|
const b2 = node.branches[1]
|
||||||
|
expect(b2.condition).toBeUndefined()
|
||||||
|
expect(b2.children.length).toBe(1)
|
||||||
|
expect(b2.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b2.children[0] as ElementNode).tag).toBe(`p`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('v-if + v-else-if', () => {
|
||||||
|
const ast = parse(`<div v-if="ok"/><p v-else-if="orNot"/>`)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
// should fold branches
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(2)
|
||||||
|
|
||||||
|
const b1 = node.branches[0]
|
||||||
|
expect(b1.condition!.content).toBe(`ok`)
|
||||||
|
expect(b1.children.length).toBe(1)
|
||||||
|
expect(b1.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b1.children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
|
||||||
|
const b2 = node.branches[1]
|
||||||
|
expect(b2.condition!.content).toBe(`orNot`)
|
||||||
|
expect(b2.children.length).toBe(1)
|
||||||
|
expect(b2.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b2.children[0] as ElementNode).tag).toBe(`p`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('v-if + v-else-if + v-else', () => {
|
||||||
|
const ast = parse(
|
||||||
|
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
|
||||||
|
)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
// should fold branches
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(3)
|
||||||
|
|
||||||
|
const b1 = node.branches[0]
|
||||||
|
expect(b1.condition!.content).toBe(`ok`)
|
||||||
|
expect(b1.children.length).toBe(1)
|
||||||
|
expect(b1.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b1.children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
|
||||||
|
const b2 = node.branches[1]
|
||||||
|
expect(b2.condition!.content).toBe(`orNot`)
|
||||||
|
expect(b2.children.length).toBe(1)
|
||||||
|
expect(b2.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b2.children[0] as ElementNode).tag).toBe(`p`)
|
||||||
|
|
||||||
|
const b3 = node.branches[2]
|
||||||
|
expect(b3.condition).toBeUndefined()
|
||||||
|
expect(b3.children.length).toBe(1)
|
||||||
|
expect(b3.children[0].type).toBe(NodeTypes.TEXT)
|
||||||
|
expect((b3.children[0] as TextNode).content).toBe(`fine`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('comment between branches', () => {
|
||||||
|
const ast = parse(`
|
||||||
|
<div v-if="ok"/>
|
||||||
|
<!--foo-->
|
||||||
|
<p v-else-if="orNot"/>
|
||||||
|
<!--bar-->
|
||||||
|
<template v-else>fine</template>
|
||||||
|
`)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf]
|
||||||
|
})
|
||||||
|
// should fold branches
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
|
||||||
|
const node = ast.children[0] as IfNode
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches.length).toBe(3)
|
||||||
|
|
||||||
|
const b1 = node.branches[0]
|
||||||
|
expect(b1.condition!.content).toBe(`ok`)
|
||||||
|
expect(b1.children.length).toBe(1)
|
||||||
|
expect(b1.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b1.children[0] as ElementNode).tag).toBe(`div`)
|
||||||
|
|
||||||
|
const b2 = node.branches[1]
|
||||||
|
expect(b2.condition!.content).toBe(`orNot`)
|
||||||
|
expect(b2.children.length).toBe(2)
|
||||||
|
expect(b2.children[0].type).toBe(NodeTypes.COMMENT)
|
||||||
|
expect((b2.children[0] as CommentNode).content).toBe(`foo`)
|
||||||
|
expect(b2.children[1].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect((b2.children[1] as ElementNode).tag).toBe(`p`)
|
||||||
|
|
||||||
|
const b3 = node.branches[2]
|
||||||
|
expect(b3.condition).toBeUndefined()
|
||||||
|
expect(b3.children.length).toBe(2)
|
||||||
|
expect(b3.children[0].type).toBe(NodeTypes.COMMENT)
|
||||||
|
expect((b3.children[0] as CommentNode).content).toBe(`bar`)
|
||||||
|
expect(b3.children[1].type).toBe(NodeTypes.TEXT)
|
||||||
|
expect((b3.children[1] as TextNode).content).toBe(`fine`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('error on v-else missing adjacent v-if', () => {
|
||||||
|
const ast = parse(`<div v-else/>`)
|
||||||
|
const spy = jest.fn()
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy
|
||||||
|
})
|
||||||
|
expect(spy.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: ast.children[0].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const ast2 = parse(`<div/><div v-else/>`)
|
||||||
|
const spy2 = jest.fn()
|
||||||
|
transform(ast2, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy2
|
||||||
|
})
|
||||||
|
expect(spy2.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: ast2.children[1].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const ast3 = parse(`<div/>foo<div v-else/>`)
|
||||||
|
const spy3 = jest.fn()
|
||||||
|
transform(ast3, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy3
|
||||||
|
})
|
||||||
|
expect(spy3.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: ast3.children[2].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('error on v-else-if missing adjacent v-if', () => {
|
||||||
|
const ast = parse(`<div v-else-if="foo"/>`)
|
||||||
|
const spy = jest.fn()
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy
|
||||||
|
})
|
||||||
|
expect(spy.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
|
||||||
|
loc: ast.children[0].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const ast2 = parse(`<div/><div v-else-if="foo"/>`)
|
||||||
|
const spy2 = jest.fn()
|
||||||
|
transform(ast2, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy2
|
||||||
|
})
|
||||||
|
expect(spy2.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
|
||||||
|
loc: ast2.children[1].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const ast3 = parse(`<div/>foo<div v-else-if="foo"/>`)
|
||||||
|
const spy3 = jest.fn()
|
||||||
|
transform(ast3, {
|
||||||
|
transforms: [transformIf],
|
||||||
|
onError: spy3
|
||||||
|
})
|
||||||
|
expect(spy3.mock.calls[0]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
|
||||||
|
loc: ast3.children[2].loc.start
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('codegen', () => {
|
||||||
|
// TODO
|
||||||
|
})
|
||||||
|
})
|
@ -25,7 +25,7 @@ describe('compiler: transform', () => {
|
|||||||
{
|
{
|
||||||
parent: ast,
|
parent: ast,
|
||||||
ancestors: [ast],
|
ancestors: [ast],
|
||||||
childIndex: 0
|
currentNode: div
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
expect(calls[1]).toMatchObject([
|
expect(calls[1]).toMatchObject([
|
||||||
@ -33,7 +33,7 @@ describe('compiler: transform', () => {
|
|||||||
{
|
{
|
||||||
parent: div,
|
parent: div,
|
||||||
ancestors: [ast, div],
|
ancestors: [ast, div],
|
||||||
childIndex: 0
|
currentNode: div.children[0]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
expect(calls[2]).toMatchObject([
|
expect(calls[2]).toMatchObject([
|
||||||
@ -41,7 +41,7 @@ describe('compiler: transform', () => {
|
|||||||
{
|
{
|
||||||
parent: div,
|
parent: div,
|
||||||
ancestors: [ast, div],
|
ancestors: [ast, div],
|
||||||
childIndex: 1
|
currentNode: div.children[1]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -81,7 +81,7 @@ describe('compiler: transform', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('context.removeNode', () => {
|
test('context.removeNode', () => {
|
||||||
const ast = parse(`<span/><div/><span/>`)
|
const ast = parse(`<span/><div>hello</div><span/>`)
|
||||||
const c1 = ast.children[0]
|
const c1 = ast.children[0]
|
||||||
const c2 = ast.children[2]
|
const c2 = ast.children[2]
|
||||||
|
|
||||||
@ -99,12 +99,67 @@ describe('compiler: transform', () => {
|
|||||||
expect(ast.children[0]).toBe(c1)
|
expect(ast.children[0]).toBe(c1)
|
||||||
expect(ast.children[1]).toBe(c2)
|
expect(ast.children[1]).toBe(c2)
|
||||||
|
|
||||||
|
// should not traverse children of remove node
|
||||||
expect(spy).toHaveBeenCalledTimes(3)
|
expect(spy).toHaveBeenCalledTimes(3)
|
||||||
// should traverse nodes around removed
|
// should traverse nodes around removed
|
||||||
expect(spy.mock.calls[0][0]).toBe(c1)
|
expect(spy.mock.calls[0][0]).toBe(c1)
|
||||||
expect(spy.mock.calls[2][0]).toBe(c2)
|
expect(spy.mock.calls[2][0]).toBe(c2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('context.removeNode (prev sibling)', () => {
|
||||||
|
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()
|
||||||
|
// remove previous sibling
|
||||||
|
context.removeNode(context.parent.children[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const spy = jest.fn(plugin)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [spy]
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
expect(ast.children[0]).toBe(c2)
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledTimes(3)
|
||||||
|
// should still traverse first span before removal
|
||||||
|
expect(spy.mock.calls[0][0]).toBe(c1)
|
||||||
|
// should still traverse last span
|
||||||
|
expect(spy.mock.calls[2][0]).toBe(c2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('context.removeNode (next sibling)', () => {
|
||||||
|
const ast = parse(`<span/><div/><span/>`)
|
||||||
|
const c1 = ast.children[0]
|
||||||
|
const d1 = ast.children[1]
|
||||||
|
|
||||||
|
const plugin: Transform = (node, context) => {
|
||||||
|
if (node.type === NodeTypes.ELEMENT && node.tag === 'div') {
|
||||||
|
context.removeNode()
|
||||||
|
// remove next sibling
|
||||||
|
context.removeNode(context.parent.children[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const spy = jest.fn(plugin)
|
||||||
|
transform(ast, {
|
||||||
|
transforms: [spy]
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ast.children.length).toBe(1)
|
||||||
|
expect(ast.children[0]).toBe(c1)
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledTimes(2)
|
||||||
|
// should still traverse first span before removal
|
||||||
|
expect(spy.mock.calls[0][0]).toBe(c1)
|
||||||
|
// should not traverse last span
|
||||||
|
expect(spy.mock.calls[1][0]).toBe(d1)
|
||||||
|
})
|
||||||
|
|
||||||
test('onError option', () => {
|
test('onError option', () => {
|
||||||
const ast = parse(`<div/>`)
|
const ast = parse(`<div/>`)
|
||||||
const loc = ast.children[0].loc.start
|
const loc = ast.children[0].loc.start
|
||||||
|
@ -20,16 +20,23 @@ export const transformIf = createDirectiveTransform(
|
|||||||
} else {
|
} else {
|
||||||
// locate the adjacent v-if
|
// locate the adjacent v-if
|
||||||
const siblings = context.parent.children
|
const siblings = context.parent.children
|
||||||
let i = context.childIndex
|
const comments = []
|
||||||
while (i--) {
|
let i = siblings.indexOf(node)
|
||||||
|
while (i-- >= -1) {
|
||||||
const sibling = siblings[i]
|
const sibling = siblings[i]
|
||||||
if (sibling.type === NodeTypes.COMMENT) {
|
if (__DEV__ && sibling && sibling.type === NodeTypes.COMMENT) {
|
||||||
|
context.removeNode(sibling)
|
||||||
|
comments.unshift(sibling)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (sibling.type === NodeTypes.IF) {
|
if (sibling && sibling.type === NodeTypes.IF) {
|
||||||
// move the node to the if node's branches
|
// move the node to the if node's branches
|
||||||
context.removeNode()
|
context.removeNode()
|
||||||
sibling.branches.push(createIfBranch(node, dir))
|
const branch = createIfBranch(node, dir)
|
||||||
|
if (__DEV__ && comments.length) {
|
||||||
|
branch.children = [...comments, ...branch.children]
|
||||||
|
}
|
||||||
|
sibling.branches.push(branch)
|
||||||
} else {
|
} else {
|
||||||
context.onError(
|
context.onError(
|
||||||
createCompilerError(
|
createCompilerError(
|
||||||
|
@ -186,6 +186,10 @@ function pushNode(
|
|||||||
nodes: ChildNode[],
|
nodes: ChildNode[],
|
||||||
node: ChildNode
|
node: ChildNode
|
||||||
): void {
|
): void {
|
||||||
|
// ignore comments in production
|
||||||
|
if (!__DEV__ && node.type === NodeTypes.COMMENT) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (context.ignoreSpaces && node.type === NodeTypes.TEXT && node.isEmpty) {
|
if (context.ignoreSpaces && node.type === NodeTypes.TEXT && node.isEmpty) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,10 @@ export interface TransformContext extends Required<TransformOptions> {
|
|||||||
parent: ParentNode
|
parent: ParentNode
|
||||||
ancestors: ParentNode[]
|
ancestors: ParentNode[]
|
||||||
childIndex: number
|
childIndex: number
|
||||||
|
currentNode: ChildNode | null
|
||||||
replaceNode(node: ChildNode): void
|
replaceNode(node: ChildNode): void
|
||||||
removeNode(): void
|
removeNode(node?: ChildNode): void
|
||||||
nodeRemoved: boolean
|
onNodeRemoved: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transform(root: RootNode, options: TransformOptions) {
|
export function transform(root: RootNode, options: TransformOptions) {
|
||||||
@ -48,17 +49,37 @@ function createTransformContext(
|
|||||||
parent: root,
|
parent: root,
|
||||||
ancestors: [],
|
ancestors: [],
|
||||||
childIndex: 0,
|
childIndex: 0,
|
||||||
|
currentNode: null,
|
||||||
replaceNode(node) {
|
replaceNode(node) {
|
||||||
if (__DEV__ && context.nodeRemoved) {
|
if (__DEV__ && !context.currentNode) {
|
||||||
throw new Error(`node being replaced is already removed`)
|
throw new Error(`node being replaced is already removed.`)
|
||||||
}
|
}
|
||||||
context.parent.children[context.childIndex] = node
|
context.parent.children[context.childIndex] = context.currentNode = node
|
||||||
},
|
},
|
||||||
removeNode() {
|
removeNode(node) {
|
||||||
context.parent.children.splice(context.childIndex, 1)
|
const list = context.parent.children
|
||||||
context.nodeRemoved = true
|
const removalIndex = node
|
||||||
|
? list.indexOf(node)
|
||||||
|
: context.currentNode
|
||||||
|
? context.childIndex
|
||||||
|
: -1
|
||||||
|
if (__DEV__ && removalIndex < 0) {
|
||||||
|
throw new Error(`node being removed is not a child of current parent`)
|
||||||
|
}
|
||||||
|
if (!node || node === context.currentNode) {
|
||||||
|
// current node removed
|
||||||
|
context.currentNode = null
|
||||||
|
context.onNodeRemoved()
|
||||||
|
} else {
|
||||||
|
// sibling node removed
|
||||||
|
if (context.childIndex > removalIndex) {
|
||||||
|
context.childIndex--
|
||||||
|
context.onNodeRemoved()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.parent.children.splice(removalIndex, 1)
|
||||||
},
|
},
|
||||||
nodeRemoved: false
|
onNodeRemoved: () => {}
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
@ -69,14 +90,16 @@ function traverseChildren(
|
|||||||
ancestors: ParentNode[]
|
ancestors: ParentNode[]
|
||||||
) {
|
) {
|
||||||
ancestors = ancestors.concat(parent)
|
ancestors = ancestors.concat(parent)
|
||||||
for (let i = 0; i < parent.children.length; i++) {
|
let i = 0
|
||||||
|
const nodeRemoved = () => {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
for (; i < parent.children.length; i++) {
|
||||||
context.parent = parent
|
context.parent = parent
|
||||||
context.ancestors = ancestors
|
context.ancestors = ancestors
|
||||||
context.childIndex = i
|
context.childIndex = i
|
||||||
traverseNode(parent.children[i], context, ancestors)
|
context.onNodeRemoved = nodeRemoved
|
||||||
if (context.nodeRemoved) {
|
traverseNode((context.currentNode = parent.children[i]), context, ancestors)
|
||||||
i--
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,13 +112,12 @@ function traverseNode(
|
|||||||
const transforms = context.transforms
|
const transforms = context.transforms
|
||||||
for (let i = 0; i < transforms.length; i++) {
|
for (let i = 0; i < transforms.length; i++) {
|
||||||
const plugin = transforms[i]
|
const plugin = transforms[i]
|
||||||
context.nodeRemoved = false
|
|
||||||
plugin(node, context)
|
plugin(node, context)
|
||||||
if (context.nodeRemoved) {
|
if (!context.currentNode) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
// node may have been replaced
|
// node may have been replaced
|
||||||
node = context.parent.children[context.childIndex]
|
node = context.currentNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user