diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
index e3631f15890..141d3e410dc 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
@@ -47,6 +47,21 @@ export function render(_ctx) {
}"
`;
+exports[`compiler: v-for > key only binding pattern 1`] = `
+"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, createFor as _createFor, template as _template } from 'vue';
+const t0 = _template("
", true)
+
+export function render(_ctx) {
+ const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
+ const n2 = t0()
+ const x2 = _child(n2)
+ _setText(x2, _toDisplayString(_for_item0.value.id + _for_item0.value.id))
+ return n2
+ }, (row) => (row.id))
+ return n0
+}"
+`;
+
exports[`compiler: v-for > multi effect 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("", true)
@@ -130,6 +145,75 @@ export function render(_ctx) {
}"
`;
+exports[`compiler: v-for > selector pattern 1`] = `
+"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, createFor as _createFor, template as _template } from 'vue';
+const t0 = _template("
", true)
+
+export function render(_ctx) {
+ const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
+ const n2 = t0()
+ const x2 = _child(n2)
+ _selector0_0(() => {
+ _setText(x2, _toDisplayString(_ctx.selected === _for_item0.value.id ? 'danger' : ''))
+ })
+ return n2
+ }, (row) => (row.id))
+ const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ return n0
+}"
+`;
+
+exports[`compiler: v-for > selector pattern 2`] = `
+"import { setClass as _setClass, createFor as _createFor, template as _template } from 'vue';
+const t0 = _template("
", true)
+
+export function render(_ctx) {
+ const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
+ const n2 = t0()
+ _selector0_0(() => {
+ _setClass(n2, _ctx.selected === _for_item0.value.id ? 'danger' : '')
+ })
+ return n2
+ }, (row) => (row.id))
+ const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ return n0
+}"
+`;
+
+exports[`compiler: v-for > selector pattern 3`] = `
+"import { setClass as _setClass, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
+const t0 = _template("
", true)
+
+export function render(_ctx) {
+ const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
+ const n2 = t0()
+ _renderEffect(() => {
+ const _row = _for_item0.value
+ _setClass(n2, _row.label === _row.id ? 'danger' : '')
+ })
+ return n2
+ }, (row) => (row.id))
+ return n0
+}"
+`;
+
+exports[`compiler: v-for > selector pattern 4`] = `
+"import { setClass as _setClass, createFor as _createFor, template as _template } from 'vue';
+const t0 = _template("
", true)
+
+export function render(_ctx) {
+ const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
+ const n2 = t0()
+ _selector0_0(() => {
+ _setClass(n2, { danger: _for_item0.value.id === _ctx.selected })
+ })
+ return n2
+ }, (row) => (row.id))
+ const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ return n0
+}"
+`;
+
exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = `
"import { getDefaultValue as _getDefaultValue, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("
", true)
diff --git a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
index d22981c1e30..7357ad84fef 100644
--- a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
@@ -67,6 +67,73 @@ describe('compiler: v-for', () => {
).lengthOf(1)
})
+ test('key only binding pattern', () => {
+ expect(
+ compileWithVFor(
+ `
+
+ {{ row.id + row.id }}
+
+ `,
+ ).code,
+ ).matchSnapshot()
+ })
+
+ test('selector pattern', () => {
+ expect(
+ compileWithVFor(
+ `
+
+ {{ selected === row.id ? 'danger' : '' }}
+
+ `,
+ ).code,
+ ).matchSnapshot()
+
+ expect(
+ compileWithVFor(
+ `
+
+ `,
+ ).code,
+ ).matchSnapshot()
+
+ // Should not be optimized because row.label is not from parent scope
+ expect(
+ compileWithVFor(
+ `
+
+ `,
+ ).code,
+ ).matchSnapshot()
+
+ expect(
+ compileWithVFor(
+ `
+
+ `,
+ ).code,
+ ).matchSnapshot()
+ })
+
test('multi effect', () => {
const { code } = compileWithVFor(
``,
diff --git a/packages/compiler-vapor/src/generators/block.ts b/packages/compiler-vapor/src/generators/block.ts
index ff240dd6eac..30347394756 100644
--- a/packages/compiler-vapor/src/generators/block.ts
+++ b/packages/compiler-vapor/src/generators/block.ts
@@ -19,14 +19,13 @@ export function genBlock(
context: CodegenContext,
args: CodeFragment[] = [],
root?: boolean,
- customReturns?: (returns: CodeFragment[]) => CodeFragment[],
): CodeFragment[] {
return [
'(',
...args,
') => {',
INDENT_START,
- ...genBlockContent(oper, context, root, customReturns),
+ ...genBlockContent(oper, context, root),
INDENT_END,
NEWLINE,
'}',
@@ -37,7 +36,7 @@ export function genBlockContent(
block: BlockIRNode,
context: CodegenContext,
root?: boolean,
- customReturns?: (returns: CodeFragment[]) => CodeFragment[],
+ genEffectsExtraFrag?: () => CodeFragment[],
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
const { dynamic, effect, operation, returns } = block
@@ -70,7 +69,7 @@ export function genBlockContent(
}
push(...genOperations(operation, context))
- push(...genEffects(effect, context))
+ push(...genEffects(effect, context, genEffectsExtraFrag))
push(NEWLINE, `return `)
@@ -79,7 +78,7 @@ export function genBlockContent(
returnNodes.length > 1
? genMulti(DELIMITERS_ARRAY, ...returnNodes)
: [returnNodes[0] || 'null']
- push(...(customReturns ? customReturns(returnsCode) : returnsCode))
+ push(...returnsCode)
resetBlock()
return frag
diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts
index a8fbc8f8300..aa7edf658f5 100644
--- a/packages/compiler-vapor/src/generators/expression.ts
+++ b/packages/compiler-vapor/src/generators/expression.ts
@@ -233,6 +233,7 @@ function canPrefix(name: string) {
type DeclarationResult = {
ids: Record
frag: CodeFragment[]
+ varNames: string[]
}
type DeclarationValue = {
name: string
@@ -246,6 +247,7 @@ type DeclarationValue = {
export function processExpressions(
context: CodegenContext,
expressions: SimpleExpressionNode[],
+ shouldDeclare: boolean,
): DeclarationResult {
// analyze variables
const {
@@ -277,7 +279,11 @@ export function processExpressions(
expToVariableMap,
)
- return genDeclarations([...varDeclarations, ...expDeclarations], context)
+ return genDeclarations(
+ [...varDeclarations, ...expDeclarations],
+ context,
+ shouldDeclare,
+ )
}
function analyzeExpressions(expressions: SimpleExpressionNode[]) {
@@ -592,15 +598,21 @@ function processRepeatedExpressions(
function genDeclarations(
declarations: DeclarationValue[],
context: CodegenContext,
+ shouldDeclare: boolean,
): DeclarationResult {
const [frag, push] = buildCodeFragment()
const ids: Record = Object.create(null)
+ const varNames = new Set()
// process identifiers first as expressions may rely on them
declarations.forEach(({ name, isIdentifier, value }) => {
if (isIdentifier) {
const varName = (ids[name] = `_${name}`)
- push(`const ${varName} = `, ...genExpression(value, context), NEWLINE)
+ varNames.add(varName)
+ if (shouldDeclare) {
+ push(`const `)
+ }
+ push(`${varName} = `, ...genExpression(value, context), NEWLINE)
}
})
@@ -608,15 +620,19 @@ function genDeclarations(
declarations.forEach(({ name, isIdentifier, value }) => {
if (!isIdentifier) {
const varName = (ids[name] = `_${name}`)
+ varNames.add(varName)
+ if (shouldDeclare) {
+ push(`const `)
+ }
push(
- `const ${varName} = `,
+ `${varName} = `,
...context.withId(() => genExpression(value, context), ids),
NEWLINE,
)
}
})
- return { ids, frag }
+ return { ids, frag, varNames: [...varNames] }
}
function escapeRegExp(string: string) {
diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts
index fbb72c61d47..40f002a8536 100644
--- a/packages/compiler-vapor/src/generators/for.ts
+++ b/packages/compiler-vapor/src/generators/for.ts
@@ -1,16 +1,32 @@
import {
type SimpleExpressionNode,
createSimpleExpression,
+ isStaticNode,
walkIdentifiers,
} from '@vue/compiler-dom'
-import { genBlock } from './block'
+import { genBlockContent } from './block'
import { genExpression } from './expression'
import type { CodegenContext } from '../generate'
-import type { ForIRNode } from '../ir'
-import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
-import type { Identifier } from '@babel/types'
+import type { BlockIRNode, ForIRNode, IREffect } from '../ir'
+import {
+ type CodeFragment,
+ INDENT_END,
+ INDENT_START,
+ NEWLINE,
+ genCall,
+ genMulti,
+} from './utils'
+import {
+ type Expression,
+ type Identifier,
+ type Node,
+ isNodesEquivalent,
+} from '@babel/types'
import { parseExpression } from '@babel/parser'
import { VaporVForFlags } from '../../../shared/src/vaporFlags'
+import { walk } from 'estree-walker'
+import { genOperation } from './operation'
+import { extend, isGloballyAllowed } from '@vue/shared'
export function genFor(
oper: ForIRNode,
@@ -78,7 +94,62 @@ export function genFor(
idMap[indexVar] = null
}
- const blockFn = context.withId(() => genBlock(render, context, args), idMap)
+ const { selectorPatterns, keyOnlyBindingPatterns } = matchPatterns(
+ render,
+ keyProp,
+ idMap,
+ )
+ const patternFrag: CodeFragment[] = []
+
+ for (let i = 0; i < selectorPatterns.length; i++) {
+ const { selector } = selectorPatterns[i]
+ const selectorName = `_selector${id}_${i}`
+ patternFrag.push(
+ NEWLINE,
+ `const ${selectorName} = `,
+ ...genCall(`n${id}.useSelector`, [
+ `() => `,
+ ...genExpression(selector, context),
+ ]),
+ )
+ }
+
+ const blockFn = context.withId(() => {
+ const frag: CodeFragment[] = []
+ frag.push('(', ...args, ') => {', INDENT_START)
+ if (selectorPatterns.length || keyOnlyBindingPatterns.length) {
+ frag.push(
+ ...genBlockContent(render, context, false, () => {
+ const patternFrag: CodeFragment[] = []
+
+ for (let i = 0; i < selectorPatterns.length; i++) {
+ const { effect } = selectorPatterns[i]
+ patternFrag.push(
+ NEWLINE,
+ `_selector${id}_${i}(() => {`,
+ INDENT_START,
+ )
+ for (const oper of effect.operations) {
+ patternFrag.push(...genOperation(oper, context))
+ }
+ patternFrag.push(INDENT_END, NEWLINE, `})`)
+ }
+
+ for (const { effect } of keyOnlyBindingPatterns) {
+ for (const oper of effect.operations) {
+ patternFrag.push(...genOperation(oper, context))
+ }
+ }
+
+ return patternFrag
+ }),
+ )
+ } else {
+ frag.push(...genBlockContent(render, context))
+ }
+ frag.push(INDENT_END, NEWLINE, '}')
+ return frag
+ }, idMap)
exitScope()
let flags = 0
@@ -103,6 +174,7 @@ export function genFor(
flags ? String(flags) : undefined,
// todo: hydrationNode
),
+ ...patternFrag,
]
// construct a id -> accessor path map.
@@ -234,3 +306,223 @@ export function genFor(
return idMap
}
}
+
+function matchPatterns(
+ render: BlockIRNode,
+ keyProp: SimpleExpressionNode | undefined,
+ idMap: Record,
+) {
+ const selectorPatterns: NonNullable<
+ ReturnType
+ >[] = []
+ const keyOnlyBindingPatterns: NonNullable<
+ ReturnType
+ >[] = []
+
+ render.effect = render.effect.filter(effect => {
+ if (keyProp !== undefined) {
+ const selector = matchSelectorPattern(effect, keyProp.ast, idMap)
+ if (selector) {
+ selectorPatterns.push(selector)
+ return false
+ }
+ const keyOnly = matchKeyOnlyBindingPattern(effect, keyProp.ast)
+ if (keyOnly) {
+ keyOnlyBindingPatterns.push(keyOnly)
+ return false
+ }
+ }
+
+ return true
+ })
+
+ return {
+ keyOnlyBindingPatterns,
+ selectorPatterns,
+ }
+}
+
+function matchKeyOnlyBindingPattern(
+ effect: IREffect,
+ keyAst: any,
+):
+ | {
+ effect: IREffect
+ }
+ | undefined {
+ // TODO: expressions can be multiple?
+ if (effect.expressions.length === 1) {
+ const ast = effect.expressions[0].ast
+ if (typeof ast === 'object' && ast !== null) {
+ if (isKeyOnlyBinding(ast, keyAst)) {
+ return { effect }
+ }
+ }
+ }
+}
+
+function matchSelectorPattern(
+ effect: IREffect,
+ keyAst: any,
+ idMap: Record,
+):
+ | {
+ effect: IREffect
+ selector: SimpleExpressionNode
+ }
+ | undefined {
+ // TODO: expressions can be multiple?
+ if (effect.expressions.length === 1) {
+ const ast = effect.expressions[0].ast
+ if (typeof ast === 'object' && ast) {
+ const matcheds: [key: Expression, selector: Expression][] = []
+
+ walk(ast, {
+ enter(node) {
+ if (
+ typeof node === 'object' &&
+ node &&
+ node.type === 'BinaryExpression' &&
+ node.operator === '===' &&
+ node.left.type !== 'PrivateName'
+ ) {
+ const { left, right } = node
+ for (const [a, b] of [
+ [left, right],
+ [right, left],
+ ]) {
+ const aIsKey = isKeyOnlyBinding(a, keyAst)
+ const bIsKey = isKeyOnlyBinding(b, keyAst)
+ const bVars = analyzeVariableScopes(b, idMap)
+ if (aIsKey && !bIsKey && !bVars.locals.length) {
+ matcheds.push([a, b])
+ }
+ }
+ }
+ },
+ })
+
+ if (matcheds.length === 1) {
+ const [key, selector] = matcheds[0]
+ const content = effect.expressions[0].content
+
+ let hasExtraId = false
+ const parentStackMap = new Map()
+ const parentStack: Node[] = []
+ walkIdentifiers(
+ ast,
+ id => {
+ if (id.start !== key.start && id.start !== selector.start) {
+ hasExtraId = true
+ }
+ parentStackMap.set(id, parentStack.slice())
+ },
+ false,
+ parentStack,
+ )
+
+ if (!hasExtraId) {
+ const name = content.slice(selector.start! - 1, selector.end! - 1)
+ return {
+ effect,
+ // @ts-expect-error
+ selector: {
+ content: name,
+ ast: extend({}, selector, {
+ start: 1,
+ end: name.length + 1,
+ }),
+ loc: selector.loc as any,
+ isStatic: false,
+ },
+ }
+ }
+ }
+ }
+
+ const content = effect.expressions[0].content
+ if (
+ typeof ast === 'object' &&
+ ast &&
+ ast.type === 'ConditionalExpression' &&
+ ast.test.type === 'BinaryExpression' &&
+ ast.test.operator === '===' &&
+ ast.test.left.type !== 'PrivateName' &&
+ isStaticNode(ast.consequent) &&
+ isStaticNode(ast.alternate)
+ ) {
+ const left = ast.test.left
+ const right = ast.test.right
+ for (const [a, b] of [
+ [left, right],
+ [right, left],
+ ]) {
+ const aIsKey = isKeyOnlyBinding(a, keyAst)
+ const bIsKey = isKeyOnlyBinding(b, keyAst)
+ const bVars = analyzeVariableScopes(b, idMap)
+ if (aIsKey && !bIsKey && !bVars.locals.length) {
+ return {
+ effect,
+ // @ts-expect-error
+ selector: {
+ content: content.slice(b.start! - 1, b.end! - 1),
+ ast: b,
+ loc: b.loc as any,
+ isStatic: false,
+ },
+ }
+ }
+ }
+ }
+ }
+}
+
+function analyzeVariableScopes(
+ ast: Node,
+ idMap: Record,
+) {
+ let globals: string[] = []
+ let locals: string[] = []
+
+ const ids: Identifier[] = []
+ const parentStackMap = new Map()
+ const parentStack: Node[] = []
+ walkIdentifiers(
+ ast,
+ id => {
+ ids.push(id)
+ parentStackMap.set(id, parentStack.slice())
+ },
+ false,
+ parentStack,
+ )
+
+ for (const id of ids) {
+ if (isGloballyAllowed(id.name)) {
+ continue
+ }
+ if (idMap[id.name]) {
+ locals.push(id.name)
+ } else {
+ globals.push(id.name)
+ }
+ }
+
+ return { globals, locals }
+}
+
+function isKeyOnlyBinding(expr: Node, keyAst: any) {
+ let only = true
+ walk(expr, {
+ enter(node) {
+ if (isNodesEquivalent(node, keyAst)) {
+ this.skip()
+ return
+ }
+ if (node.type === 'Identifier') {
+ only = false
+ }
+ },
+ })
+ return only
+}
diff --git a/packages/compiler-vapor/src/generators/operation.ts b/packages/compiler-vapor/src/generators/operation.ts
index 563d72f1ee1..13ce5477cc1 100644
--- a/packages/compiler-vapor/src/generators/operation.ts
+++ b/packages/compiler-vapor/src/generators/operation.ts
@@ -98,15 +98,18 @@ export function genOperation(
export function genEffects(
effects: IREffect[],
context: CodegenContext,
+ genExtraFrag?: () => CodeFragment[],
): CodeFragment[] {
const { helper } = context
const expressions = effects.flatMap(effect => effect.expressions)
const [frag, push, unshift] = buildCodeFragment()
+ const shouldDeclare = genExtraFrag === undefined
let operationsCount = 0
- const { ids, frag: declarationFrags } = processExpressions(
- context,
- expressions,
- )
+ const {
+ ids,
+ frag: declarationFrags,
+ varNames,
+ } = processExpressions(context, expressions, shouldDeclare)
push(...declarationFrags)
for (let i = 0; i < effects.length; i++) {
const effect = effects[i]
@@ -123,6 +126,9 @@ export function genEffects(
if (newLineCount > 1 || operationsCount > 1 || declarationFrags.length > 0) {
unshift(`{`, INDENT_START, NEWLINE)
push(INDENT_END, NEWLINE, '}')
+ if (!effects.length) {
+ unshift(NEWLINE)
+ }
}
if (effects.length) {
@@ -130,6 +136,14 @@ export function genEffects(
push(`)`)
}
+ if (!shouldDeclare && varNames.length) {
+ unshift(NEWLINE, `let `, varNames.join(', '))
+ }
+
+ if (genExtraFrag) {
+ push(...context.withId(genExtraFrag, ids))
+ }
+
return frag
}
diff --git a/packages/runtime-vapor/__tests__/for.spec.ts b/packages/runtime-vapor/__tests__/for.spec.ts
index db91b6a62da..dc247b6d4ca 100644
--- a/packages/runtime-vapor/__tests__/for.spec.ts
+++ b/packages/runtime-vapor/__tests__/for.spec.ts
@@ -101,7 +101,7 @@ describe('createFor', () => {
})
return span
},
- item => item.name,
+ item => item,
)
return n1
}).render()
diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts
index 62529149ad4..b1aef20e094 100644
--- a/packages/runtime-vapor/src/apiCreateFor.ts
+++ b/packages/runtime-vapor/src/apiCreateFor.ts
@@ -10,6 +10,7 @@ import {
shallowRef,
toReactive,
toReadonly,
+ watch,
} from '@vue/reactivity'
import { getSequence, isArray, isObject, isString } from '@vue/shared'
import { createComment, createTextNode } from './dom/node'
@@ -87,12 +88,18 @@ export const createFor = (
let oldBlocks: ForBlock[] = []
let newBlocks: ForBlock[]
let parent: ParentNode | undefined | null
+ // useSelector only
+ let currentKey: any
// TODO handle this in hydration
const parentAnchor = __DEV__ ? createComment('for') : createTextNode()
const frag = new VaporFragment(oldBlocks)
const instance = currentInstance!
- const canUseFastRemove = flags & VaporVForFlags.FAST_REMOVE
- const isComponent = flags & VaporVForFlags.IS_COMPONENT
+ const canUseFastRemove = !!(flags & VaporVForFlags.FAST_REMOVE)
+ const isComponent = !!(flags & VaporVForFlags.IS_COMPONENT)
+ const selectors: {
+ deregister: (key: any) => void
+ cleanup: () => void
+ }[] = []
if (__DEV__ && !instance) {
warn('createFor() can only be used inside setup()')
@@ -120,9 +127,12 @@ export const createFor = (
}
} else if (!newLength) {
// fast path for clearing all
+ for (const selector of selectors) {
+ selector.cleanup()
+ }
const doRemove = !canUseFastRemove
for (let i = 0; i < oldLength; i++) {
- unmount(oldBlocks[i], doRemove)
+ unmount(oldBlocks[i], doRemove, false)
}
if (canUseFastRemove) {
parent!.textContent = ''
@@ -362,9 +372,18 @@ export const createFor = (
}
}
- const unmount = ({ nodes, scope }: ForBlock, doRemove = true) => {
- scope && scope.stop()
- doRemove && removeBlock(nodes, parent!)
+ const unmount = (block: ForBlock, doRemove = true, doDeregister = true) => {
+ if (!isComponent) {
+ block.scope!.stop()
+ }
+ if (doRemove) {
+ removeBlock(block.nodes, parent!)
+ }
+ if (doDeregister) {
+ for (const selector of selectors) {
+ selector.deregister(block.key)
+ }
+ }
}
if (flags & VaporVForFlags.ONCE) {
@@ -377,7 +396,59 @@ export const createFor = (
insert(frag, _insertionParent, _insertionAnchor)
}
+ // @ts-expect-error
+ frag.useSelector = useSelector
+
return frag
+
+ function useSelector(source: () => any): (key: any, cb: () => void) => void {
+ let operMap = new Map void)[]>()
+ let activeKey = source()
+ let activeOpers: (() => void)[] | undefined
+
+ watch(source, newValue => {
+ if (activeOpers !== undefined) {
+ for (const oper of activeOpers) {
+ oper()
+ }
+ }
+ activeOpers = operMap.get(newValue)
+ if (activeOpers !== undefined) {
+ for (const oper of activeOpers) {
+ oper()
+ }
+ }
+ })
+
+ selectors.push({ deregister, cleanup })
+ return register
+
+ function cleanup() {
+ operMap = new Map()
+ activeOpers = undefined
+ }
+
+ function register(oper: () => void) {
+ oper()
+ let opers = operMap.get(currentKey)
+ if (opers !== undefined) {
+ opers.push(oper)
+ } else {
+ opers = [oper]
+ operMap.set(currentKey, opers)
+ if (currentKey === activeKey) {
+ activeOpers = opers
+ }
+ }
+ }
+
+ function deregister(key: any) {
+ operMap.delete(key)
+ if (key === activeKey) {
+ activeOpers = undefined
+ }
+ }
+ }
}
export function createForSlots(
diff --git a/rollup.config.js b/rollup.config.js
index 7f2ecb8c864..1fa345f87fc 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -314,6 +314,7 @@ function createConfig(format, output, plugins = []) {
const treeShakenDeps = [
'source-map-js',
'@babel/parser',
+ '@babel/types',
'estree-walker',
'entities/lib/decode.js',
]