Skip to content

Commit ad525c4

Browse files
committed
refactor(compiler-vapor): generate unique helper aliases to prevent collisions with user variables
1 parent ea397b7 commit ad525c4

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,18 @@ export function render(_ctx) {
280280
}"
281281
`;
282282
283+
exports[`compile > helper alias > should avoid conflicts with existing variable names 1`] = `
284+
"import { child as _child2, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
285+
const t0 = _template("<div> </div>", true)
286+
287+
export function render(_ctx, $props, $emit, $attrs, $slots) {
288+
const n0 = t0()
289+
const x0 = _child2(n0)
290+
_renderEffect(() => _setText(x0, _toDisplayString(_ctx.foo)))
291+
return n0
292+
}"
293+
`;
294+
283295
exports[`compile > setInsertionState > next, child and nthChild should be above the setInsertionState 1`] = `
284296
"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';
285297
const t0 = _template("<div></div>")

packages/compiler-vapor/__tests__/compile.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,18 @@ describe('compile', () => {
268268
expect(code).matchSnapshot()
269269
})
270270
})
271+
272+
describe('helper alias', () => {
273+
test('should avoid conflicts with existing variable names', () => {
274+
const code = compile(`<div>{{ foo }}</div>`, {
275+
bindingMetadata: {
276+
_child: BindingTypes.LITERAL_CONST,
277+
_child1: BindingTypes.SETUP_REF,
278+
},
279+
})
280+
expect(code).matchSnapshot()
281+
expect(code).contains('child as _child2')
282+
expect(code).contains('const x0 = _child2(n0)')
283+
})
284+
})
271285
})

packages/compiler-vapor/src/generate.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,31 @@ export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
2424
export class CodegenContext {
2525
options: Required<CodegenOptions>
2626

27-
helpers: Set<string> = new Set<string>([])
27+
bindingNames: Set<string> = new Set<string>()
2828

29-
helper = (name: CoreHelper | VaporHelper) => {
30-
this.helpers.add(name)
31-
return `_${name}`
29+
helpers: Map<string, string> = new Map()
30+
31+
helper = (name: CoreHelper | VaporHelper): string => {
32+
if (this.helpers.has(name)) {
33+
return this.helpers.get(name)!
34+
}
35+
36+
const base = `_${name}`
37+
if (this.bindingNames.size === 0) {
38+
this.helpers.set(name, base)
39+
return base
40+
}
41+
42+
// check whether an alias is already used bindings
43+
let alias = base
44+
let i = 0
45+
while (this.bindingNames.has(alias)) {
46+
i++
47+
alias = `${base}${i}`
48+
}
49+
50+
this.helpers.set(name, alias)
51+
return alias
3252
}
3353

3454
delegates: Set<string> = new Set<string>()
@@ -90,6 +110,11 @@ export class CodegenContext {
90110
}
91111
this.options = extend(defaultOptions, options)
92112
this.block = ir.block
113+
this.bindingNames = new Set<string>(
114+
this.options.bindingMetadata
115+
? Object.keys(this.options.bindingMetadata)
116+
: [],
117+
)
93118
}
94119
}
95120

@@ -105,7 +130,6 @@ export function generate(
105130
): VaporCodegenResult {
106131
const [frag, push] = buildCodeFragment()
107132
const context = new CodegenContext(ir, options)
108-
const { helpers } = context
109133
const { inline, bindingMetadata } = options
110134
const functionName = 'render'
111135

@@ -156,7 +180,7 @@ export function generate(
156180
ast: ir,
157181
preamble,
158182
map: map && map.toJSON(),
159-
helpers,
183+
helpers: new Set<string>(Array.from(context.helpers.keys())),
160184
}
161185
}
162186

@@ -169,11 +193,11 @@ function genDelegates({ delegates, helper }: CodegenContext) {
169193
: ''
170194
}
171195

172-
function genHelperImports({ helpers, helper, options }: CodegenContext) {
196+
function genHelperImports({ helpers, options }: CodegenContext) {
173197
let imports = ''
174198
if (helpers.size) {
175-
imports += `import { ${[...helpers]
176-
.map(h => `${h} as _${h}`)
199+
imports += `import { ${Array.from(helpers)
200+
.map(([h, alias]) => `${h} as ${alias}`)
177201
.join(', ')} } from '${options.runtimeModuleName}';\n`
178202
}
179203
return imports

0 commit comments

Comments
 (0)