mirror of https://github.com/vuejs/core.git
feat: add next helper for sibilings
This commit is contained in:
parent
2075042956
commit
2c15171dcf
|
@ -0,0 +1,19 @@
|
||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`compiler: children transform > children & sibling references 1`] = `
|
||||||
|
"import { next as _next, setText as _setText, createTextNode as _createTextNode, insert as _insert, template as _template } from 'vue/vapor';
|
||||||
|
const t0 = _template("<div><p></p> <!><p></p></div>")
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const n4 = t0()
|
||||||
|
const n0 = n4.firstChild
|
||||||
|
const n3 = _next(n0, 2)
|
||||||
|
const n2 = n3.nextSibling
|
||||||
|
_setText(n0, 'first')
|
||||||
|
const n1 = _createTextNode()
|
||||||
|
_setText(n1, 'second', " ", 'third', " ")
|
||||||
|
_setText(n2, 'forth')
|
||||||
|
_insert(n1, n4, n3)
|
||||||
|
return n4
|
||||||
|
}"
|
||||||
|
`;
|
|
@ -12,12 +12,12 @@ export function render(_ctx) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: v-once > basic 1`] = `
|
exports[`compiler: v-once > basic 1`] = `
|
||||||
"import { children as _children, createTextNode as _createTextNode, setText as _setText, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor';
|
"import { createTextNode as _createTextNode, setText as _setText, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor';
|
||||||
const t0 = _template("<div><span></span></div>")
|
const t0 = _template("<div><span></span></div>")
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const n2 = t0()
|
const n2 = t0()
|
||||||
const n1 = _children(n2, 0)
|
const n1 = n2.firstChild
|
||||||
const n0 = _createTextNode()
|
const n0 = _createTextNode()
|
||||||
_setText(n0, _ctx.msg, " ")
|
_setText(n0, _ctx.msg, " ")
|
||||||
_setClass(n1, _ctx.clz)
|
_setClass(n1, _ctx.clz)
|
||||||
|
@ -37,12 +37,12 @@ export function render(_ctx) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: v-once > on nested plain element 1`] = `
|
exports[`compiler: v-once > on nested plain element 1`] = `
|
||||||
"import { children as _children, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
|
"import { setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
|
||||||
const t0 = _template("<div><div></div></div>")
|
const t0 = _template("<div><div></div></div>")
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const n1 = t0()
|
const n1 = t0()
|
||||||
const n0 = _children(n1, 0)
|
const n0 = n1.firstChild
|
||||||
_setDynamicProp(n0, "id", _ctx.foo)
|
_setDynamicProp(n0, "id", _ctx.foo)
|
||||||
return n1
|
return n1
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,3 +1,39 @@
|
||||||
|
import { makeCompile } from './_utils'
|
||||||
|
import {
|
||||||
|
transformChildren,
|
||||||
|
transformElement,
|
||||||
|
transformText,
|
||||||
|
transformVIf,
|
||||||
|
} from '../../src'
|
||||||
|
|
||||||
|
const compileWithElementTransform = makeCompile({
|
||||||
|
nodeTransforms: [
|
||||||
|
transformText,
|
||||||
|
transformVIf,
|
||||||
|
transformElement,
|
||||||
|
transformChildren,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
describe('compiler: children transform', () => {
|
describe('compiler: children transform', () => {
|
||||||
test.todo('basic')
|
test.todo('basic')
|
||||||
|
|
||||||
|
test('children & sibling references', () => {
|
||||||
|
const { code, vaporHelpers } = compileWithElementTransform(
|
||||||
|
`<div>
|
||||||
|
<p>{{'first'}}</p>
|
||||||
|
{{'second'}}
|
||||||
|
{{'third'}}
|
||||||
|
<p>{{'forth'}}</p>
|
||||||
|
</div>`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(Array.from(vaporHelpers)).containSubset([
|
||||||
|
'next',
|
||||||
|
'setText',
|
||||||
|
'createTextNode',
|
||||||
|
'insert',
|
||||||
|
'template',
|
||||||
|
])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { CodegenContext } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import { DynamicFlag, type IRDynamicInfo } from '../ir'
|
import { DynamicFlag, type IRDynamicInfo } from '../ir'
|
||||||
import { NEWLINE, buildCodeFragment, genCall } from './utils'
|
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||||
|
|
||||||
export function genTemplates(
|
export function genTemplates(
|
||||||
templates: string[],
|
templates: string[],
|
||||||
|
@ -19,7 +19,7 @@ export function genChildren(
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
from: number,
|
from: number,
|
||||||
paths: number[] = [],
|
paths: number[] = [],
|
||||||
) {
|
): CodeFragment[] {
|
||||||
const { vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
const [frag, push] = buildCodeFragment()
|
const [frag, push] = buildCodeFragment()
|
||||||
let offset = 0
|
let offset = 0
|
||||||
|
@ -29,6 +29,7 @@ export function genChildren(
|
||||||
push(NEWLINE, `const n${id} = t${template}()`)
|
push(NEWLINE, `const n${id} = t${template}()`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prev: [id: number, elementIndex: number] | undefined
|
||||||
for (const [index, child] of children.entries()) {
|
for (const [index, child] of children.entries()) {
|
||||||
if (child.flags & DynamicFlag.NON_TEMPLATE) {
|
if (child.flags & DynamicFlag.NON_TEMPLATE) {
|
||||||
offset--
|
offset--
|
||||||
|
@ -44,21 +45,35 @@ export function genChildren(
|
||||||
const elementIndex = Number(index) + offset
|
const elementIndex = Number(index) + offset
|
||||||
const newPaths = [...paths, elementIndex]
|
const newPaths = [...paths, elementIndex]
|
||||||
|
|
||||||
if (id !== undefined) {
|
if (id === undefined) {
|
||||||
|
push(...genChildren(child, context, from, newPaths))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
push(NEWLINE, `const n${id} = `)
|
||||||
|
if (prev) {
|
||||||
|
const offset = elementIndex - prev[1]
|
||||||
|
if (offset === 1) {
|
||||||
|
push(`n${prev[0]}.nextSibling`)
|
||||||
|
} else {
|
||||||
|
push(...genCall(vaporHelper('next'), `n${prev[0]}`, String(offset)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newPaths.length === 1 && newPaths[0] === 0) {
|
||||||
|
push(`n${from}.firstChild`)
|
||||||
|
} else {
|
||||||
push(
|
push(
|
||||||
NEWLINE,
|
|
||||||
`const n${id} = `,
|
|
||||||
...genCall(
|
...genCall(
|
||||||
vaporHelper('children'),
|
vaporHelper('children'),
|
||||||
`n${from}`,
|
`n${from}`,
|
||||||
...newPaths.map(String),
|
...newPaths.map(String),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
push(...genChildren(child, context, id, []))
|
|
||||||
} else {
|
|
||||||
push(...genChildren(child, context, from, newPaths))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
prev = [id, elementIndex]
|
||||||
|
push(...genChildren(child, context, id, []))
|
||||||
|
}
|
||||||
|
|
||||||
return frag
|
return frag
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ export const transformChildren: NodeTransform = (node, context) => {
|
||||||
|
|
||||||
if (!isFragment && node.type !== NodeTypes.ELEMENT) return
|
if (!isFragment && node.type !== NodeTypes.ELEMENT) return
|
||||||
|
|
||||||
let referencedCount = 0
|
|
||||||
for (const [i, child] of node.children.entries()) {
|
for (const [i, child] of node.children.entries()) {
|
||||||
const childContext = createContext(
|
const childContext = createContext(
|
||||||
child,
|
child,
|
||||||
|
@ -42,18 +41,12 @@ export const transformChildren: NodeTransform = (node, context) => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
context.childrenTemplate.push(childContext.template)
|
context.childrenTemplate.push(childContext.template)
|
||||||
if (childContext.dynamic.flags & DynamicFlag.REFERENCED) {
|
|
||||||
referencedCount++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.dynamic.children[i] = childContext.dynamic
|
context.dynamic.children[i] = childContext.dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFragment) {
|
if (!isFragment) {
|
||||||
if (referencedCount > 1) {
|
|
||||||
context.reference()
|
|
||||||
}
|
|
||||||
processDynamicChildren(context as TransformContext<ElementNode>)
|
processDynamicChildren(context as TransformContext<ElementNode>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { isArray } from '@vue/shared'
|
|
||||||
|
|
||||||
/*! #__NO_SIDE_EFFECTS__ */
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
export function template(html: string) {
|
export function template(html: string) {
|
||||||
let node: ChildNode
|
let node: ChildNode
|
||||||
|
@ -13,15 +11,19 @@ export function template(html: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! #__NO_SIDE_EFFECTS__ */
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
export function children(node: Node | Node[], ...paths: number[]): Node {
|
export function children(node: Node, ...paths: number[]): Node {
|
||||||
for (const idx of paths) {
|
for (const idx of paths) {
|
||||||
if (isArray(node)) {
|
|
||||||
node = node[idx]
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i <= idx; i++) {
|
for (let i = 0; i <= idx; i++) {
|
||||||
node = (node as Node)[i === 0 ? 'firstChild' : 'nextSibling']!
|
node = (node as Node)[i === 0 ? 'firstChild' : 'nextSibling']!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return node as Node
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
|
export function next(node: Node, offset: number): Node {
|
||||||
|
for (let i = 0; i < offset; i++) {
|
||||||
|
node = (node as Node).nextSibling!
|
||||||
}
|
}
|
||||||
return node as Node
|
return node as Node
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ export {
|
||||||
type DirectiveModifiers,
|
type DirectiveModifiers,
|
||||||
} from './directives'
|
} from './directives'
|
||||||
|
|
||||||
export { template, children } from './dom/template'
|
export { template, children, next } from './dom/template'
|
||||||
export { insert, prepend, remove, createTextNode } from './dom/element'
|
export { insert, prepend, remove, createTextNode } from './dom/element'
|
||||||
export { setStyle } from './dom/style'
|
export { setStyle } from './dom/style'
|
||||||
export {
|
export {
|
||||||
|
|
Loading…
Reference in New Issue