Skip to content

Commit e9942d0

Browse files
authored
Merge branch 'vuejs:main' into fix/ssrRenderSlot
2 parents ddf1a30 + 7d473b7 commit e9942d0

File tree

19 files changed

+777
-393
lines changed

19 files changed

+777
-393
lines changed

package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@
6666
"@rollup/plugin-json": "^6.1.0",
6767
"@rollup/plugin-node-resolve": "^15.2.3",
6868
"@rollup/plugin-replace": "5.0.4",
69-
"@swc/core": "^1.7.3",
69+
"@swc/core": "^1.7.6",
7070
"@types/hash-sum": "^1.0.2",
71-
"@types/node": "^20.14.13",
71+
"@types/node": "^20.14.14",
7272
"@types/semver": "^7.5.8",
7373
"@vitest/coverage-istanbul": "^1.6.0",
7474
"@vue/consolidate": "1.0.0",
@@ -81,19 +81,19 @@
8181
"eslint-plugin-vitest": "^0.5.4",
8282
"estree-walker": "catalog:",
8383
"jsdom": "^24.1.1",
84-
"lint-staged": "^15.2.7",
84+
"lint-staged": "^15.2.8",
8585
"lodash": "^4.17.21",
86-
"magic-string": "^0.30.10",
86+
"magic-string": "^0.30.11",
8787
"markdown-table": "^3.0.3",
88-
"marked": "^12.0.2",
88+
"marked": "^13.0.3",
8989
"npm-run-all2": "^6.2.2",
9090
"picocolors": "^1.0.1",
9191
"prettier": "^3.3.3",
9292
"pretty-bytes": "^6.1.1",
9393
"pug": "^3.0.3",
94-
"puppeteer": "~22.14.0",
95-
"rimraf": "^5.0.9",
96-
"rollup": "^4.19.1",
94+
"puppeteer": "~22.15.0",
95+
"rimraf": "^6.0.1",
96+
"rollup": "^4.20.0",
9797
"rollup-plugin-dts": "^6.1.1",
9898
"rollup-plugin-esbuild": "^6.1.1",
9999
"rollup-plugin-polyfill-node": "^0.13.0",
@@ -102,9 +102,9 @@
102102
"simple-git-hooks": "^2.11.1",
103103
"todomvc-app-css": "^2.4.3",
104104
"tslib": "^2.6.3",
105-
"tsx": "^4.16.2",
105+
"tsx": "^4.16.5",
106106
"typescript": "~5.4.5",
107-
"typescript-eslint": "^7.17.0",
107+
"typescript-eslint": "^8.0.0",
108108
"vite": "catalog:",
109109
"vitest": "^1.6.0"
110110
},

packages/compiler-core/__tests__/transforms/__snapshots__/transformExpressions.spec.ts.snap

+63-15
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,92 @@ return function render(_ctx, _cache, $props, $setup, $data, $options) {
1414
}"
1515
`;
1616

17-
exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for loop 1`] = `
17+
exports[`compiler: expression transform > should allow leak of var declarations in for loop 1`] = `
1818
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
1919
20-
return function render(_ctx, _cache, $props, $setup, $data, $options) {
20+
return function render(_ctx, _cache) {
2121
return (_openBlock(), _createElementBlock("div", {
2222
onClick: () => {
23-
for (let i = 0; i < _ctx.list.length; i++) {
24-
_ctx.log(i)
25-
}
23+
for (var i = 0; i < _ctx.list.length; i++) {
24+
_ctx.log(i)
2625
}
26+
_ctx.error(i)
27+
}
2728
}, null, 8 /* PROPS */, ["onClick"]))
2829
}"
2930
`;
3031

31-
exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for...in 1`] = `
32+
exports[`compiler: expression transform > should not prefix catch block param 1`] = `
3233
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
3334
34-
return function render(_ctx, _cache, $props, $setup, $data, $options) {
35+
return function render(_ctx, _cache) {
3536
return (_openBlock(), _createElementBlock("div", {
3637
onClick: () => {
37-
for (const x in _ctx.list) {
38-
_ctx.log(x)
39-
}
38+
try {} catch (err) { console.error(err) }
39+
console.log(_ctx.err)
40+
}
41+
}, null, 8 /* PROPS */, ["onClick"]))
42+
}"
43+
`;
44+
45+
exports[`compiler: expression transform > should not prefix destructured catch block param 1`] = `
46+
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
47+
48+
return function render(_ctx, _cache) {
49+
return (_openBlock(), _createElementBlock("div", {
50+
onClick: () => {
51+
try {
52+
throw new Error('sup?')
53+
} catch ({ message: { length } }) {
54+
console.error(length)
4055
}
56+
console.log(_ctx.length)
57+
}
4158
}, null, 8 /* PROPS */, ["onClick"]))
4259
}"
4360
`;
4461

45-
exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for...of 1`] = `
62+
exports[`compiler: expression transform > should not prefix temp variable of for loop 1`] = `
4663
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
4764
48-
return function render(_ctx, _cache, $props, $setup, $data, $options) {
65+
return function render(_ctx, _cache) {
66+
return (_openBlock(), _createElementBlock("div", {
67+
onClick: () => {
68+
for (let i = 0; i < _ctx.list.length; i++) {
69+
_ctx.log(i)
70+
}
71+
_ctx.error(_ctx.i)
72+
}
73+
}, null, 8 /* PROPS */, ["onClick"]))
74+
}"
75+
`;
76+
77+
exports[`compiler: expression transform > should not prefix temp variable of for...in 1`] = `
78+
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
79+
80+
return function render(_ctx, _cache) {
81+
return (_openBlock(), _createElementBlock("div", {
82+
onClick: () => {
83+
for (const x in _ctx.list) {
84+
_ctx.log(x)
85+
}
86+
_ctx.error(_ctx.x)
87+
}
88+
}, null, 8 /* PROPS */, ["onClick"]))
89+
}"
90+
`;
91+
92+
exports[`compiler: expression transform > should not prefix temp variable of for...of 1`] = `
93+
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
94+
95+
return function render(_ctx, _cache) {
4996
return (_openBlock(), _createElementBlock("div", {
5097
onClick: () => {
51-
for (const x of _ctx.list) {
52-
_ctx.log(x)
53-
}
98+
for (const x of _ctx.list) {
99+
_ctx.log(x)
54100
}
101+
_ctx.error(_ctx.x)
102+
}
55103
}, null, 8 /* PROPS */, ["onClick"]))
56104
}"
57105
`;

packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts

+89-36
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ function parseWithExpressionTransform(
2727
return ast.children[0]
2828
}
2929

30+
function compile(template: string) {
31+
return baseCompile(template, { prefixIdentifiers: true })
32+
}
33+
3034
describe('compiler: expression transform', () => {
3135
test('interpolation (root)', () => {
3236
const node = parseWithExpressionTransform(`{{ foo }}`) as InterpolationNode
@@ -291,6 +295,7 @@ describe('compiler: expression transform', () => {
291295
],
292296
})
293297
})
298+
294299
test('should not prefix an object property key', () => {
295300
const node = parseWithExpressionTransform(
296301
`{{ { foo() { baz() }, value: bar } }}`,
@@ -457,6 +462,90 @@ describe('compiler: expression transform', () => {
457462
})
458463
})
459464

465+
test('should not prefix temp variable of for...in', () => {
466+
const { code } = compile(
467+
`<div @click="() => {
468+
for (const x in list) {
469+
log(x)
470+
}
471+
error(x)
472+
}"/>`,
473+
)
474+
expect(code).not.toMatch(`log(_ctx.x)`)
475+
expect(code).toMatch(`error(_ctx.x)`)
476+
expect(code).toMatchSnapshot()
477+
})
478+
479+
test('should not prefix temp variable of for...of', () => {
480+
const { code } = compile(
481+
`<div @click="() => {
482+
for (const x of list) {
483+
log(x)
484+
}
485+
error(x)
486+
}"/>`,
487+
)
488+
expect(code).not.toMatch(`log(_ctx.x)`)
489+
expect(code).toMatch(`error(_ctx.x)`)
490+
expect(code).toMatchSnapshot()
491+
})
492+
493+
test('should not prefix temp variable of for loop', () => {
494+
const { code } = compile(
495+
`<div @click="() => {
496+
for (let i = 0; i < list.length; i++) {
497+
log(i)
498+
}
499+
error(i)
500+
}"/>`,
501+
)
502+
expect(code).not.toMatch(`log(_ctx.i)`)
503+
expect(code).toMatch(`error(_ctx.i)`)
504+
expect(code).toMatchSnapshot()
505+
})
506+
507+
test('should allow leak of var declarations in for loop', () => {
508+
const { code } = compile(
509+
`<div @click="() => {
510+
for (var i = 0; i < list.length; i++) {
511+
log(i)
512+
}
513+
error(i)
514+
}"/>`,
515+
)
516+
expect(code).not.toMatch(`log(_ctx.i)`)
517+
expect(code).not.toMatch(`error(_ctx.i)`)
518+
expect(code).toMatchSnapshot()
519+
})
520+
521+
test('should not prefix catch block param', () => {
522+
const { code } = compile(
523+
`<div @click="() => {
524+
try {} catch (err) { console.error(err) }
525+
console.log(err)
526+
}"/>`,
527+
)
528+
expect(code).not.toMatch(`console.error(_ctx.err)`)
529+
expect(code).toMatch(`console.log(_ctx.err)`)
530+
expect(code).toMatchSnapshot()
531+
})
532+
533+
test('should not prefix destructured catch block param', () => {
534+
const { code } = compile(
535+
`<div @click="() => {
536+
try {
537+
throw new Error('sup?')
538+
} catch ({ message: { length } }) {
539+
console.error(length)
540+
}
541+
console.log(length)
542+
}"/>`,
543+
)
544+
expect(code).not.toMatch(`console.error(_ctx.length)`)
545+
expect(code).toMatch(`console.log(_ctx.length)`)
546+
expect(code).toMatchSnapshot()
547+
})
548+
460549
describe('ES Proposals support', () => {
461550
test('bigInt', () => {
462551
const node = parseWithExpressionTransform(
@@ -555,42 +644,6 @@ describe('compiler: expression transform', () => {
555644
expect(code).toMatchSnapshot()
556645
})
557646

558-
test('should not prefix temp variable of for...in', () => {
559-
const { code } = compileWithBindingMetadata(
560-
`<div @click="() => {
561-
for (const x in list) {
562-
log(x)
563-
}
564-
}"/>`,
565-
)
566-
expect(code).not.toMatch(`_ctx.x`)
567-
expect(code).toMatchSnapshot()
568-
})
569-
570-
test('should not prefix temp variable of for...of', () => {
571-
const { code } = compileWithBindingMetadata(
572-
`<div @click="() => {
573-
for (const x of list) {
574-
log(x)
575-
}
576-
}"/>`,
577-
)
578-
expect(code).not.toMatch(`_ctx.x`)
579-
expect(code).toMatchSnapshot()
580-
})
581-
582-
test('should not prefix temp variable of for loop', () => {
583-
const { code } = compileWithBindingMetadata(
584-
`<div @click="() => {
585-
for (let i = 0; i < list.length; i++) {
586-
log(i)
587-
}
588-
}"/>`,
589-
)
590-
expect(code).not.toMatch(`_ctx.i`)
591-
expect(code).toMatchSnapshot()
592-
})
593-
594647
test('inline mode', () => {
595648
const { code } = compileWithBindingMetadata(
596649
`<div>{{ props }} {{ setup }} {{ setupConst }} {{ data }} {{ options }} {{ isNaN }}</div>`,

packages/compiler-core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"dependencies": {
4949
"@babel/parser": "catalog:",
5050
"@vue/shared": "workspace:*",
51-
"entities": "^4.5.0",
51+
"entities": "^5.0.0",
5252
"estree-walker": "catalog:",
5353
"source-map-js": "catalog:"
5454
},

packages/compiler-core/src/babelUtils.ts

+41-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// do not import runtime methods
33
import type {
44
BlockStatement,
5+
ForInStatement,
6+
ForOfStatement,
7+
ForStatement,
58
Function,
69
Identifier,
710
Node,
@@ -77,6 +80,14 @@ export function walkIdentifiers(
7780
markScopeIdentifier(node, id, knownIds),
7881
)
7982
}
83+
} else if (node.type === 'CatchClause' && node.param) {
84+
for (const id of extractIdentifiers(node.param)) {
85+
markScopeIdentifier(node, id, knownIds)
86+
}
87+
} else if (isForStatement(node)) {
88+
walkForStatement(node, false, id =>
89+
markScopeIdentifier(node, id, knownIds),
90+
)
8091
}
8192
},
8293
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
@@ -192,18 +203,36 @@ export function walkBlockDeclarations(
192203
) {
193204
if (stmt.declare || !stmt.id) continue
194205
onIdent(stmt.id)
195-
} else if (
196-
stmt.type === 'ForOfStatement' ||
197-
stmt.type === 'ForInStatement' ||
198-
stmt.type === 'ForStatement'
199-
) {
200-
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
201-
if (variable && variable.type === 'VariableDeclaration') {
202-
for (const decl of variable.declarations) {
203-
for (const id of extractIdentifiers(decl.id)) {
204-
onIdent(id)
205-
}
206-
}
206+
} else if (isForStatement(stmt)) {
207+
walkForStatement(stmt, true, onIdent)
208+
}
209+
}
210+
}
211+
212+
function isForStatement(
213+
stmt: Node,
214+
): stmt is ForStatement | ForOfStatement | ForInStatement {
215+
return (
216+
stmt.type === 'ForOfStatement' ||
217+
stmt.type === 'ForInStatement' ||
218+
stmt.type === 'ForStatement'
219+
)
220+
}
221+
222+
function walkForStatement(
223+
stmt: ForStatement | ForOfStatement | ForInStatement,
224+
isVar: boolean,
225+
onIdent: (id: Identifier) => void,
226+
) {
227+
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
228+
if (
229+
variable &&
230+
variable.type === 'VariableDeclaration' &&
231+
(variable.kind === 'var' ? isVar : !isVar)
232+
) {
233+
for (const decl of variable.declarations) {
234+
for (const id of extractIdentifiers(decl.id)) {
235+
onIdent(id)
207236
}
208237
}
209238
}

0 commit comments

Comments
 (0)