Skip to content

Commit

Permalink
Merge branch 'vuejs:main' into fix/ssrRenderSlot
Browse files Browse the repository at this point in the history
  • Loading branch information
nieyuyao committed Aug 6, 2024
2 parents ddf1a30 + 7d473b7 commit e9942d0
Show file tree
Hide file tree
Showing 19 changed files with 777 additions and 393 deletions.
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "5.0.4",
"@swc/core": "^1.7.3",
"@swc/core": "^1.7.6",
"@types/hash-sum": "^1.0.2",
"@types/node": "^20.14.13",
"@types/node": "^20.14.14",
"@types/semver": "^7.5.8",
"@vitest/coverage-istanbul": "^1.6.0",
"@vue/consolidate": "1.0.0",
Expand All @@ -81,19 +81,19 @@
"eslint-plugin-vitest": "^0.5.4",
"estree-walker": "catalog:",
"jsdom": "^24.1.1",
"lint-staged": "^15.2.7",
"lint-staged": "^15.2.8",
"lodash": "^4.17.21",
"magic-string": "^0.30.10",
"magic-string": "^0.30.11",
"markdown-table": "^3.0.3",
"marked": "^12.0.2",
"marked": "^13.0.3",
"npm-run-all2": "^6.2.2",
"picocolors": "^1.0.1",
"prettier": "^3.3.3",
"pretty-bytes": "^6.1.1",
"pug": "^3.0.3",
"puppeteer": "~22.14.0",
"rimraf": "^5.0.9",
"rollup": "^4.19.1",
"puppeteer": "~22.15.0",
"rimraf": "^6.0.1",
"rollup": "^4.20.0",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-polyfill-node": "^0.13.0",
Expand All @@ -102,9 +102,9 @@
"simple-git-hooks": "^2.11.1",
"todomvc-app-css": "^2.4.3",
"tslib": "^2.6.3",
"tsx": "^4.16.2",
"tsx": "^4.16.5",
"typescript": "~5.4.5",
"typescript-eslint": "^7.17.0",
"typescript-eslint": "^8.0.0",
"vite": "catalog:",
"vitest": "^1.6.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,92 @@ return function render(_ctx, _cache, $props, $setup, $data, $options) {
}"
`;

exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for loop 1`] = `
exports[`compiler: expression transform > should allow leak of var declarations in for loop 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache, $props, $setup, $data, $options) {
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
for (let i = 0; i < _ctx.list.length; i++) {
_ctx.log(i)
}
for (var i = 0; i < _ctx.list.length; i++) {
_ctx.log(i)
}
_ctx.error(i)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;

exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for...in 1`] = `
exports[`compiler: expression transform > should not prefix catch block param 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache, $props, $setup, $data, $options) {
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
for (const x in _ctx.list) {
_ctx.log(x)
}
try {} catch (err) { console.error(err) }
console.log(_ctx.err)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;

exports[`compiler: expression transform > should not prefix destructured catch block param 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
try {
throw new Error('sup?')
} catch ({ message: { length } }) {
console.error(length)
}
console.log(_ctx.length)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;

exports[`compiler: expression transform > bindingMetadata > should not prefix temp variable of for...of 1`] = `
exports[`compiler: expression transform > should not prefix temp variable of for loop 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache, $props, $setup, $data, $options) {
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
for (let i = 0; i < _ctx.list.length; i++) {
_ctx.log(i)
}
_ctx.error(_ctx.i)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;

exports[`compiler: expression transform > should not prefix temp variable of for...in 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
for (const x in _ctx.list) {
_ctx.log(x)
}
_ctx.error(_ctx.x)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;

exports[`compiler: expression transform > should not prefix temp variable of for...of 1`] = `
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
onClick: () => {
for (const x of _ctx.list) {
_ctx.log(x)
}
for (const x of _ctx.list) {
_ctx.log(x)
}
_ctx.error(_ctx.x)
}
}, null, 8 /* PROPS */, ["onClick"]))
}"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ function parseWithExpressionTransform(
return ast.children[0]
}

function compile(template: string) {
return baseCompile(template, { prefixIdentifiers: true })
}

describe('compiler: expression transform', () => {
test('interpolation (root)', () => {
const node = parseWithExpressionTransform(`{{ foo }}`) as InterpolationNode
Expand Down Expand Up @@ -291,6 +295,7 @@ describe('compiler: expression transform', () => {
],
})
})

test('should not prefix an object property key', () => {
const node = parseWithExpressionTransform(
`{{ { foo() { baz() }, value: bar } }}`,
Expand Down Expand Up @@ -457,6 +462,90 @@ describe('compiler: expression transform', () => {
})
})

test('should not prefix temp variable of for...in', () => {
const { code } = compile(
`<div @click="() => {
for (const x in list) {
log(x)
}
error(x)
}"/>`,
)
expect(code).not.toMatch(`log(_ctx.x)`)
expect(code).toMatch(`error(_ctx.x)`)
expect(code).toMatchSnapshot()
})

test('should not prefix temp variable of for...of', () => {
const { code } = compile(
`<div @click="() => {
for (const x of list) {
log(x)
}
error(x)
}"/>`,
)
expect(code).not.toMatch(`log(_ctx.x)`)
expect(code).toMatch(`error(_ctx.x)`)
expect(code).toMatchSnapshot()
})

test('should not prefix temp variable of for loop', () => {
const { code } = compile(
`<div @click="() => {
for (let i = 0; i < list.length; i++) {
log(i)
}
error(i)
}"/>`,
)
expect(code).not.toMatch(`log(_ctx.i)`)
expect(code).toMatch(`error(_ctx.i)`)
expect(code).toMatchSnapshot()
})

test('should allow leak of var declarations in for loop', () => {
const { code } = compile(
`<div @click="() => {
for (var i = 0; i < list.length; i++) {
log(i)
}
error(i)
}"/>`,
)
expect(code).not.toMatch(`log(_ctx.i)`)
expect(code).not.toMatch(`error(_ctx.i)`)
expect(code).toMatchSnapshot()
})

test('should not prefix catch block param', () => {
const { code } = compile(
`<div @click="() => {
try {} catch (err) { console.error(err) }
console.log(err)
}"/>`,
)
expect(code).not.toMatch(`console.error(_ctx.err)`)
expect(code).toMatch(`console.log(_ctx.err)`)
expect(code).toMatchSnapshot()
})

test('should not prefix destructured catch block param', () => {
const { code } = compile(
`<div @click="() => {
try {
throw new Error('sup?')
} catch ({ message: { length } }) {
console.error(length)
}
console.log(length)
}"/>`,
)
expect(code).not.toMatch(`console.error(_ctx.length)`)
expect(code).toMatch(`console.log(_ctx.length)`)
expect(code).toMatchSnapshot()
})

describe('ES Proposals support', () => {
test('bigInt', () => {
const node = parseWithExpressionTransform(
Expand Down Expand Up @@ -555,42 +644,6 @@ describe('compiler: expression transform', () => {
expect(code).toMatchSnapshot()
})

test('should not prefix temp variable of for...in', () => {
const { code } = compileWithBindingMetadata(
`<div @click="() => {
for (const x in list) {
log(x)
}
}"/>`,
)
expect(code).not.toMatch(`_ctx.x`)
expect(code).toMatchSnapshot()
})

test('should not prefix temp variable of for...of', () => {
const { code } = compileWithBindingMetadata(
`<div @click="() => {
for (const x of list) {
log(x)
}
}"/>`,
)
expect(code).not.toMatch(`_ctx.x`)
expect(code).toMatchSnapshot()
})

test('should not prefix temp variable of for loop', () => {
const { code } = compileWithBindingMetadata(
`<div @click="() => {
for (let i = 0; i < list.length; i++) {
log(i)
}
}"/>`,
)
expect(code).not.toMatch(`_ctx.i`)
expect(code).toMatchSnapshot()
})

test('inline mode', () => {
const { code } = compileWithBindingMetadata(
`<div>{{ props }} {{ setup }} {{ setupConst }} {{ data }} {{ options }} {{ isNaN }}</div>`,
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"dependencies": {
"@babel/parser": "catalog:",
"@vue/shared": "workspace:*",
"entities": "^4.5.0",
"entities": "^5.0.0",
"estree-walker": "catalog:",
"source-map-js": "catalog:"
},
Expand Down
53 changes: 41 additions & 12 deletions packages/compiler-core/src/babelUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// do not import runtime methods
import type {
BlockStatement,
ForInStatement,
ForOfStatement,
ForStatement,
Function,
Identifier,
Node,
Expand Down Expand Up @@ -77,6 +80,14 @@ export function walkIdentifiers(
markScopeIdentifier(node, id, knownIds),
)
}
} else if (node.type === 'CatchClause' && node.param) {
for (const id of extractIdentifiers(node.param)) {
markScopeIdentifier(node, id, knownIds)
}
} else if (isForStatement(node)) {
walkForStatement(node, false, id =>
markScopeIdentifier(node, id, knownIds),
)
}
},
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
Expand Down Expand Up @@ -192,18 +203,36 @@ export function walkBlockDeclarations(
) {
if (stmt.declare || !stmt.id) continue
onIdent(stmt.id)
} else if (
stmt.type === 'ForOfStatement' ||
stmt.type === 'ForInStatement' ||
stmt.type === 'ForStatement'
) {
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
if (variable && variable.type === 'VariableDeclaration') {
for (const decl of variable.declarations) {
for (const id of extractIdentifiers(decl.id)) {
onIdent(id)
}
}
} else if (isForStatement(stmt)) {
walkForStatement(stmt, true, onIdent)
}
}
}

function isForStatement(
stmt: Node,
): stmt is ForStatement | ForOfStatement | ForInStatement {
return (
stmt.type === 'ForOfStatement' ||
stmt.type === 'ForInStatement' ||
stmt.type === 'ForStatement'
)
}

function walkForStatement(
stmt: ForStatement | ForOfStatement | ForInStatement,
isVar: boolean,
onIdent: (id: Identifier) => void,
) {
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
if (
variable &&
variable.type === 'VariableDeclaration' &&
(variable.kind === 'var' ? isVar : !isVar)
) {
for (const decl of variable.declarations) {
for (const id of extractIdentifiers(decl.id)) {
onIdent(id)
}
}
}
Expand Down
Loading

0 comments on commit e9942d0

Please sign in to comment.