Merge ac390a6d95
into 5f8314cb7f
This commit is contained in:
commit
f8b4f289fc
|
@ -45,6 +45,20 @@ return function render(_ctx, _cache) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > codegen > no whitespace around (in|of) with basic v-for 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
with (_ctx) {
|
||||
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList([items], (item) => {
|
||||
return (_openBlock(), _createElementBlock("span"))
|
||||
}), 256 /* UNKEYED_FRAGMENT */))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > codegen > skipped key 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
|
|
|
@ -45,6 +45,20 @@ return function render(_ctx, _cache) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > codegen > no whitespace around (in|of) with basic v-for 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
with (_ctx) {
|
||||
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList([items], (item) => {
|
||||
return (_openBlock(), _createElementBlock("span"))
|
||||
}), 256 /* UNKEYED_FRAGMENT */))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > codegen > skipped key 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
|
|
|
@ -218,6 +218,43 @@ describe('compiler: v-for', () => {
|
|||
"state ['my items']",
|
||||
)
|
||||
})
|
||||
|
||||
test('no whitespace around (in|of) with simple expression', () => {
|
||||
const { node: forNode } = parseWithForTransform(
|
||||
'<span v-for="(item)in[items]" />',
|
||||
)
|
||||
|
||||
expect(forNode.keyAlias).toBeUndefined()
|
||||
expect(forNode.objectIndexAlias).toBeUndefined()
|
||||
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
|
||||
expect((forNode.source as SimpleExpressionNode).content).toBe('[items]')
|
||||
})
|
||||
|
||||
test('no whitespace around (in|of) with object de-structured value', () => {
|
||||
const { node: forNode } = parseWithForTransform(
|
||||
'<span v-for="{ id, value }in[item]" />',
|
||||
)
|
||||
|
||||
expect(forNode.keyAlias).toBeUndefined()
|
||||
expect(forNode.objectIndexAlias).toBeUndefined()
|
||||
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
|
||||
'{ id, value }',
|
||||
)
|
||||
expect((forNode.source as SimpleExpressionNode).content).toBe('[item]')
|
||||
})
|
||||
|
||||
test('no whitespace around (in|of) with array de-structured value', () => {
|
||||
const { node: forNode } = parseWithForTransform(
|
||||
'<span v-for="[ id ]in[item]" />',
|
||||
)
|
||||
|
||||
expect(forNode.keyAlias).toBeUndefined()
|
||||
expect(forNode.objectIndexAlias).toBeUndefined()
|
||||
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
|
||||
'[ id ]',
|
||||
)
|
||||
expect((forNode.source as SimpleExpressionNode).content).toBe('[item]')
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
|
@ -257,6 +294,18 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
})
|
||||
|
||||
test('invalid expression containing (in|of)', () => {
|
||||
const onError = vi.fn()
|
||||
parseWithForTransform('<span v-for="fooinbar" />', { onError })
|
||||
|
||||
expect(onError).toHaveBeenCalledTimes(1)
|
||||
expect(onError).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
test('missing source', () => {
|
||||
const onError = vi.fn()
|
||||
parseWithForTransform('<span v-for="item in" />', { onError })
|
||||
|
@ -293,6 +342,18 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
})
|
||||
|
||||
test('missing source and value', () => {
|
||||
const onError = vi.fn()
|
||||
parseWithForTransform('<span v-for=" in " />', { onError })
|
||||
|
||||
expect(onError).toHaveBeenCalledTimes(1)
|
||||
expect(onError).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
test('<template v-for> key placement', () => {
|
||||
const onError = vi.fn()
|
||||
parseWithForTransform(
|
||||
|
@ -437,6 +498,48 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
})
|
||||
|
||||
test('no whitespace around (in|of) with bracketed value, key, index', () => {
|
||||
const source = '<span v-for="( item, key, index )in[items]" />'
|
||||
const { node: forNode } = parseWithForTransform(source)
|
||||
|
||||
const itemOffset = source.indexOf('item')
|
||||
const value = forNode.valueAlias as SimpleExpressionNode
|
||||
expect(value.content).toBe('item')
|
||||
expect(value.loc.start.offset).toBe(itemOffset)
|
||||
expect(value.loc.start.line).toBe(1)
|
||||
expect(value.loc.start.column).toBe(itemOffset + 1)
|
||||
expect(value.loc.end.line).toBe(1)
|
||||
expect(value.loc.end.column).toBe(itemOffset + 1 + `item`.length)
|
||||
|
||||
const keyOffset = source.indexOf('key')
|
||||
const key = forNode.keyAlias as SimpleExpressionNode
|
||||
expect(key.content).toBe('key')
|
||||
expect(key.loc.start.offset).toBe(keyOffset)
|
||||
expect(key.loc.start.line).toBe(1)
|
||||
expect(key.loc.start.column).toBe(keyOffset + 1)
|
||||
expect(key.loc.end.line).toBe(1)
|
||||
expect(key.loc.end.column).toBe(keyOffset + 1 + `key`.length)
|
||||
|
||||
const indexOffset = source.indexOf('index')
|
||||
const index = forNode.objectIndexAlias as SimpleExpressionNode
|
||||
expect(index.content).toBe('index')
|
||||
expect(index.loc.start.offset).toBe(indexOffset)
|
||||
expect(index.loc.start.line).toBe(1)
|
||||
expect(index.loc.start.column).toBe(indexOffset + 1)
|
||||
expect(index.loc.end.line).toBe(1)
|
||||
expect(index.loc.end.column).toBe(indexOffset + 1 + `index`.length)
|
||||
|
||||
const itemsOffset = source.indexOf('[items]')
|
||||
expect((forNode.source as SimpleExpressionNode).content).toBe('[items]')
|
||||
expect(forNode.source.loc.start.offset).toBe(itemsOffset)
|
||||
expect(forNode.source.loc.start.line).toBe(1)
|
||||
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
|
||||
expect(forNode.source.loc.end.line).toBe(1)
|
||||
expect(forNode.source.loc.end.column).toBe(
|
||||
itemsOffset + 1 + `[items]`.length,
|
||||
)
|
||||
})
|
||||
|
||||
test('skipped key', () => {
|
||||
const source = '<span v-for="( item,, index ) in items" />'
|
||||
const { node: forNode } = parseWithForTransform(source)
|
||||
|
@ -747,6 +850,21 @@ describe('compiler: v-for', () => {
|
|||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('no whitespace around (in|of) with basic v-for', () => {
|
||||
const {
|
||||
root,
|
||||
node: { codegenNode },
|
||||
} = parseWithForTransform('<span v-for="(item)in[items]" />')
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `[items]` },
|
||||
params: [{ content: `item` }],
|
||||
innerVNodeCall: {
|
||||
tag: `"span"`,
|
||||
},
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('value + key + index', () => {
|
||||
const {
|
||||
root,
|
||||
|
|
|
@ -491,15 +491,25 @@ const tokenizer = new Tokenizer(stack, {
|
|||
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
|
||||
const stripParensRE = /^\(|\)$/g
|
||||
|
||||
function matchForAlias(exp: string) {
|
||||
const inMatch = exp.match(forAliasRE)
|
||||
if (!inMatch) return
|
||||
|
||||
const LHS = inMatch[1].trim()
|
||||
const RHS = inMatch[2].trim()
|
||||
|
||||
if (LHS && RHS) return { LHS, RHS }
|
||||
}
|
||||
|
||||
function parseForExpression(
|
||||
input: SimpleExpressionNode,
|
||||
): ForParseResult | undefined {
|
||||
const loc = input.loc
|
||||
const exp = input.content
|
||||
const inMatch = exp.match(forAliasRE)
|
||||
const inMatch = matchForAlias(exp)
|
||||
if (!inMatch) return
|
||||
|
||||
const [, LHS, RHS] = inMatch
|
||||
const { LHS, RHS } = inMatch
|
||||
|
||||
const createAliasExpression = (
|
||||
content: string,
|
||||
|
@ -518,14 +528,14 @@ function parseForExpression(
|
|||
}
|
||||
|
||||
const result: ForParseResult = {
|
||||
source: createAliasExpression(RHS.trim(), exp.indexOf(RHS, LHS.length)),
|
||||
source: createAliasExpression(RHS, exp.indexOf(RHS, LHS.length)),
|
||||
value: undefined,
|
||||
key: undefined,
|
||||
index: undefined,
|
||||
finalized: false,
|
||||
}
|
||||
|
||||
let valueContent = LHS.trim().replace(stripParensRE, '').trim()
|
||||
let valueContent = LHS.replace(stripParensRE, '').trim()
|
||||
const trimmedOffset = LHS.indexOf(valueContent)
|
||||
|
||||
const iteratorMatch = valueContent.match(forIteratorRE)
|
||||
|
|
|
@ -563,4 +563,5 @@ export function getMemoedVNodeCall(
|
|||
}
|
||||
}
|
||||
|
||||
export const forAliasRE: RegExp = /([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/
|
||||
export const forAliasRE: RegExp =
|
||||
/([\s\S]*?[\s\)\}\]]+)(?:in|of)([\s\[]+[\s\S]*)/
|
||||
|
|
Loading…
Reference in New Issue