diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index 9f2183ce8..3855360c4 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -280,6 +280,18 @@ export function render(_ctx) { }" `; +exports[`compile > helper alias > should avoid conflicts with existing variable names 1`] = ` +"import { child as _child2, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
", true) + +export function render(_ctx, $props, $emit, $attrs, $slots) { + const n0 = t0() + const x0 = _child2(n0) + _renderEffect(() => _setText(x0, _toDisplayString(_ctx.foo))) + return n0 +}" +`; + exports[`compile > setInsertionState > next, child and nthChild should be above the setInsertionState 1`] = ` "import { resolveComponent as _resolveComponent, child as _child, next as _next, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, nthChild as _nthChild, createIf as _createIf, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
") diff --git a/packages/compiler-vapor/__tests__/compile.spec.ts b/packages/compiler-vapor/__tests__/compile.spec.ts index 7963a9e98..19bb45b48 100644 --- a/packages/compiler-vapor/__tests__/compile.spec.ts +++ b/packages/compiler-vapor/__tests__/compile.spec.ts @@ -268,4 +268,18 @@ describe('compile', () => { expect(code).matchSnapshot() }) }) + + describe('helper alias', () => { + test('should avoid conflicts with existing variable names', () => { + const code = compile(`
{{ foo }}
`, { + bindingMetadata: { + _child: BindingTypes.LITERAL_CONST, + _child1: BindingTypes.SETUP_REF, + }, + }) + expect(code).matchSnapshot() + expect(code).contains('child as _child2') + expect(code).contains('const x0 = _child2(n0)') + }) + }) }) diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index 193a0f5da..ca26138c8 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -24,11 +24,31 @@ export type CodegenOptions = Omit export class CodegenContext { options: Required - helpers: Set = new Set([]) + bindingNames: Set = new Set() - helper = (name: CoreHelper | VaporHelper) => { - this.helpers.add(name) - return `_${name}` + helpers: Map = new Map() + + helper = (name: CoreHelper | VaporHelper): string => { + if (this.helpers.has(name)) { + return this.helpers.get(name)! + } + + const base = `_${name}` + if (this.bindingNames.size === 0) { + this.helpers.set(name, base) + return base + } + + // check whether an alias is already used bindings + let alias = base + let i = 0 + while (this.bindingNames.has(alias)) { + i++ + alias = `${base}${i}` + } + + this.helpers.set(name, alias) + return alias } delegates: Set = new Set() @@ -90,6 +110,11 @@ export class CodegenContext { } this.options = extend(defaultOptions, options) this.block = ir.block + this.bindingNames = new Set( + this.options.bindingMetadata + ? Object.keys(this.options.bindingMetadata) + : [], + ) } } @@ -105,7 +130,6 @@ export function generate( ): VaporCodegenResult { const [frag, push] = buildCodeFragment() const context = new CodegenContext(ir, options) - const { helpers } = context const { inline, bindingMetadata } = options const functionName = 'render' @@ -156,7 +180,7 @@ export function generate( ast: ir, preamble, map: map && map.toJSON(), - helpers, + helpers: new Set(Array.from(context.helpers.keys())), } } @@ -169,11 +193,11 @@ function genDelegates({ delegates, helper }: CodegenContext) { : '' } -function genHelperImports({ helpers, helper, options }: CodegenContext) { +function genHelperImports({ helpers, options }: CodegenContext) { let imports = '' if (helpers.size) { - imports += `import { ${[...helpers] - .map(h => `${h} as _${h}`) + imports += `import { ${Array.from(helpers) + .map(([h, alias]) => `${h} as ${alias}`) .join(', ')} } from '${options.runtimeModuleName}';\n` } return imports