diff --git a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
index d5e65e6a7..dd8d8311b 100644
--- a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
+++ b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
@@ -20,7 +20,7 @@ exports[`compiler: codegen comment 1`] = `
"
return function render() {
with (this) {
- return createVNode(Comment, 0, \\"foo\\")
+ return _createVNode(_Comment, 0, \\"foo\\")
}
}"
`;
@@ -29,7 +29,7 @@ exports[`compiler: codegen compound expression 1`] = `
"
return function render() {
with (this) {
- return toString(_ctx.foo)
+ return _toString(_ctx.foo)
}
}"
`;
@@ -38,16 +38,30 @@ exports[`compiler: codegen forNode 1`] = `
"
return function render() {
with (this) {
- return renderList(list, (v, k, i) => toString(v))
+ return _renderList(list, (v, k, i) => {
+ return _toString(v)
+ })
}
}"
`;
+exports[`compiler: codegen forNode w/ prefixIdentifiers: true 1`] = `
+"
+return function render() {
+ const _ctx = this
+ return renderList(list, (v, k, i) => {
+ return toString(v)
+ })
+}"
+`;
+
exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
"
return function render() {
with (this) {
- return renderList(list, (v, __key, i) => toString(v))
+ return _renderList(list, (v, __key, i) => {
+ return _toString(v)
+ })
}
}"
`;
@@ -56,7 +70,9 @@ exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
"
return function render() {
with (this) {
- return renderList(list, (__value, k, i) => toString(v))
+ return _renderList(list, (__value, k, i) => {
+ return _toString(v)
+ })
}
}"
`;
@@ -65,7 +81,9 @@ exports[`compiler: codegen forNode w/ skipped value and key aliases 1`] = `
"
return function render() {
with (this) {
- return renderList(list, (__value, __key, i) => toString(v))
+ return _renderList(list, (__value, __key, i) => {
+ return _toString(v)
+ })
}
}"
`;
@@ -74,12 +92,21 @@ exports[`compiler: codegen function mode preamble 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
- const { helperOne, helperTwo } = _Vue
+ const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
return null
}
}"
`;
+exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = `
+"const { helperOne, helperTwo } = Vue
+
+return function render() {
+ const _ctx = this
+ return null
+}"
+`;
+
exports[`compiler: codegen hoists 1`] = `
"const _hoisted_1 = hello
const _hoisted_2 = { id: \\"foo\\" }
@@ -98,8 +125,8 @@ return function render() {
return foo
? \\"foo\\"
: (a + b)
- ? toString(bye)
- : createVNode(Comment, 0, \\"foo\\")
+ ? _toString(bye)
+ : _createVNode(_Comment, 0, \\"foo\\")
}
}"
`;
@@ -111,7 +138,7 @@ return function render() {
return foo
? \\"foo\\"
: (a + b)
- ? toString(bye)
+ ? _toString(bye)
: null
}
}"
@@ -121,7 +148,7 @@ exports[`compiler: codegen interpolation 1`] = `
"
return function render() {
with (this) {
- return toString(hello)
+ return _toString(hello)
}
}"
`;
@@ -171,9 +198,21 @@ return function render() {
with (this) {
return [
\\"foo\\",
- toString(hello),
- createVNode(Comment, 0, \\"foo\\")
+ _toString(hello),
+ _createVNode(_Comment, 0, \\"foo\\")
]
}
}"
`;
+
+exports[`compiler: codegen text + comment + interpolation w/ prefixIdentifiers: true 1`] = `
+"
+return function render() {
+ const _ctx = this
+ return [
+ \\"foo\\",
+ toString(hello),
+ createVNode(Comment, 0, \\"foo\\")
+ ]
+}"
+`;
diff --git a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap
new file mode 100644
index 000000000..f7508225d
--- /dev/null
+++ b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`function mode 1`] = `
+"const _Vue = Vue
+return function render() {
+ with (this) {
+ const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue
+ return _createVNode(\\"div\\", {
+ id: \\"foo\\",
+ class: bar
+ }, [
+ _toString(world),
+ ok
+ ? _createVNode(\\"div\\", 0, \\"yes\\")
+ : \\"no\\",
+ _renderList(list, (i, j) => {
+ return _createVNode(\\"div\\", 0, [_createVNode(\\"span\\", 0, _toString(i + j))])
+ })
+ ])
+ }
+}"
+`;
diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
index 250b91ae0..694b37348 100644
--- a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
+++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
@@ -7481,15 +7481,15 @@ Object {
"isStatic": false,
"loc": Object {
"end": Object {
- "column": 34,
+ "column": 33,
"line": 1,
- "offset": 33,
+ "offset": 32,
},
"source": "\\"{ some: condition }\\"",
"start": Object {
- "column": 13,
+ "column": 14,
"line": 1,
- "offset": 12,
+ "offset": 13,
},
},
"type": 4,
@@ -7561,15 +7561,15 @@ Object {
"isStatic": false,
"loc": Object {
"end": Object {
- "column": 35,
+ "column": 34,
"line": 2,
- "offset": 71,
+ "offset": 70,
},
"source": "\\"{ color: 'red' }\\"",
"start": Object {
- "column": 17,
+ "column": 18,
"line": 2,
- "offset": 53,
+ "offset": 54,
},
},
"type": 4,
@@ -7629,13 +7629,13 @@ Object {
"isSelfClosing": true,
"loc": Object {
"end": Object {
- "column": 38,
+ "column": 39,
"line": 2,
"offset": 73,
},
"source": "
",
"start": Object {
- "column": 2,
+ "column": 3,
"line": 2,
"offset": 37,
},
@@ -7649,13 +7649,13 @@ Object {
"isStatic": true,
"loc": Object {
"end": Object {
- "column": 17,
+ "column": 18,
"line": 2,
"offset": 52,
},
"source": "style",
"start": Object {
- "column": 12,
+ "column": 13,
"line": 2,
"offset": 47,
},
@@ -7670,26 +7670,26 @@ Object {
"end": Object {
"column": 36,
"line": 2,
- "offset": 71,
+ "offset": 70,
},
"source": "\\"{ color: 'red' }\\"",
"start": Object {
- "column": 18,
+ "column": 20,
"line": 2,
- "offset": 53,
+ "offset": 54,
},
},
"type": 4,
},
"loc": Object {
"end": Object {
- "column": 36,
+ "column": 37,
"line": 2,
"offset": 71,
},
"source": "v-bind:style=\\"{ color: 'red' }\\"",
"start": Object {
- "column": 5,
+ "column": 6,
"line": 2,
"offset": 40,
},
@@ -7707,13 +7707,13 @@ Object {
"content": " a comment with inside it ",
"loc": Object {
"end": Object {
- "column": 42,
+ "column": 43,
"line": 3,
"offset": 116,
},
"source": "",
"start": Object {
- "column": 2,
+ "column": 3,
"line": 3,
"offset": 76,
},
@@ -7767,15 +7767,15 @@ Object {
"isStatic": false,
"loc": Object {
"end": Object {
- "column": 34,
+ "column": 33,
"line": 1,
- "offset": 33,
+ "offset": 32,
},
"source": "\\"{ some: condition }\\"",
"start": Object {
- "column": 13,
+ "column": 14,
"line": 1,
- "offset": 12,
+ "offset": 13,
},
},
"type": 4,
diff --git a/packages/compiler-core/__tests__/codegen.spec.ts b/packages/compiler-core/__tests__/codegen.spec.ts
index 5e76e6258..88416f067 100644
--- a/packages/compiler-core/__tests__/codegen.spec.ts
+++ b/packages/compiler-core/__tests__/codegen.spec.ts
@@ -12,7 +12,12 @@ import {
createArrayExpression,
ElementNode
} from '../src'
-import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
+import {
+ CREATE_VNODE,
+ COMMENT,
+ TO_STRING,
+ RENDER_LIST
+} from '../src/runtimeConstants'
const mockLoc: SourceLocation = {
source: ``,
@@ -56,7 +61,22 @@ describe('compiler: codegen', () => {
})
const { code } = generate(root, { mode: 'function' })
expect(code).toMatch(`const _Vue = Vue`)
- expect(code).toMatch(`const { helperOne, helperTwo } = _Vue`)
+ expect(code).toMatch(
+ `const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue`
+ )
+ expect(code).toMatchSnapshot()
+ })
+
+ test('function mode preamble w/ prefixIdentifiers: true', () => {
+ const root = createRoot({
+ imports: [`helperOne`, `helperTwo`]
+ })
+ const { code } = generate(root, {
+ mode: 'function',
+ prefixIdentifiers: true
+ })
+ expect(code).not.toMatch(`const _Vue = Vue`)
+ expect(code).toMatch(`const { helperOne, helperTwo } = Vue`)
expect(code).toMatchSnapshot()
})
@@ -121,7 +141,7 @@ describe('compiler: codegen', () => {
children: [createExpression(`hello`, false, mockLoc, true)]
})
)
- expect(code).toMatch(`return toString(hello)`)
+ expect(code).toMatch(`return _${TO_STRING}(hello)`)
expect(code).toMatchSnapshot()
})
@@ -137,7 +157,7 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`return ${CREATE_VNODE}(${COMMENT}, 0, "foo")`)
+ expect(code).toMatch(`return _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
expect(code).toMatchSnapshot()
})
@@ -163,12 +183,43 @@ describe('compiler: codegen', () => {
expect(code).toMatch(`
return [
"foo",
- toString(hello),
- ${CREATE_VNODE}(${COMMENT}, 0, "foo")
+ _${TO_STRING}(hello),
+ _${CREATE_VNODE}(_${COMMENT}, 0, "foo")
]`)
expect(code).toMatchSnapshot()
})
+ test('text + comment + interpolation w/ prefixIdentifiers: true', () => {
+ const { code } = generate(
+ createRoot({
+ children: [
+ {
+ type: NodeTypes.TEXT,
+ content: 'foo',
+ isEmpty: false,
+ loc: mockLoc
+ },
+ createExpression(`hello`, false, mockLoc, true),
+ {
+ type: NodeTypes.COMMENT,
+ content: 'foo',
+ loc: mockLoc
+ }
+ ]
+ }),
+ {
+ prefixIdentifiers: true
+ }
+ )
+ expect(code).toMatch(`
+ return [
+ "foo",
+ ${TO_STRING}(hello),
+ ${CREATE_VNODE}(${COMMENT}, 0, "foo")
+ ]`)
+ expect(code).toMatchSnapshot()
+ })
+
test('compound expression', () => {
const { code } = generate(
createRoot({
@@ -184,7 +235,7 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`return toString(_ctx.foo)`)
+ expect(code).toMatch(`return _${TO_STRING}(_ctx.foo)`)
expect(code).toMatchSnapshot()
})
@@ -195,13 +246,11 @@ describe('compiler: codegen', () => {
{
type: NodeTypes.IF,
loc: mockLoc,
- isRoot: true,
branches: [
{
type: NodeTypes.IF_BRANCH,
condition: createExpression('foo', false, mockLoc),
loc: mockLoc,
- isRoot: true,
children: [
{
type: NodeTypes.TEXT,
@@ -215,14 +264,12 @@ describe('compiler: codegen', () => {
type: NodeTypes.IF_BRANCH,
condition: createExpression('a + b', false, mockLoc),
loc: mockLoc,
- isRoot: true,
children: [createExpression(`bye`, false, mockLoc, true)]
},
{
type: NodeTypes.IF_BRANCH,
condition: undefined,
loc: mockLoc,
- isRoot: true,
children: [
{
type: NodeTypes.COMMENT,
@@ -240,8 +287,8 @@ describe('compiler: codegen', () => {
return foo
? "foo"
: (a + b)
- ? ${TO_STRING}(bye)
- : ${CREATE_VNODE}(${COMMENT}, 0, "foo")`)
+ ? _${TO_STRING}(bye)
+ : _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
expect(code).toMatchSnapshot()
})
@@ -252,13 +299,11 @@ describe('compiler: codegen', () => {
{
type: NodeTypes.IF,
loc: mockLoc,
- isRoot: true,
branches: [
{
type: NodeTypes.IF_BRANCH,
condition: createExpression('foo', false, mockLoc),
loc: mockLoc,
- isRoot: true,
children: [
{
type: NodeTypes.TEXT,
@@ -272,7 +317,6 @@ describe('compiler: codegen', () => {
type: NodeTypes.IF_BRANCH,
condition: createExpression('a + b', false, mockLoc),
loc: mockLoc,
- isRoot: true,
children: [createExpression(`bye`, false, mockLoc, true)]
}
]
@@ -284,7 +328,7 @@ describe('compiler: codegen', () => {
return foo
? "foo"
: (a + b)
- ? ${TO_STRING}(bye)
+ ? _${TO_STRING}(bye)
: null`)
expect(code).toMatchSnapshot()
})
@@ -305,7 +349,38 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`renderList(list, (v, k, i) => toString(v))`)
+ expect(code).toMatch(
+ `return _${RENDER_LIST}(list, (v, k, i) => {
+ return _${TO_STRING}(v)
+ })`
+ )
+ expect(code).toMatchSnapshot()
+ })
+
+ test('forNode w/ prefixIdentifiers: true', () => {
+ const { code } = generate(
+ createRoot({
+ children: [
+ {
+ type: NodeTypes.FOR,
+ loc: mockLoc,
+ source: createExpression(`list`, false, mockLoc),
+ valueAlias: createExpression(`v`, false, mockLoc),
+ keyAlias: createExpression(`k`, false, mockLoc),
+ objectIndexAlias: createExpression(`i`, false, mockLoc),
+ children: [createExpression(`v`, false, mockLoc, true)]
+ }
+ ]
+ }),
+ {
+ prefixIdentifiers: true
+ }
+ )
+ expect(code).toMatch(
+ `return ${RENDER_LIST}(list, (v, k, i) => {
+ return ${TO_STRING}(v)
+ })`
+ )
expect(code).toMatchSnapshot()
})
@@ -325,7 +400,11 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`renderList(list, (__value, k, i) => toString(v))`)
+ expect(code).toMatch(
+ `return _${RENDER_LIST}(list, (__value, k, i) => {
+ return _${TO_STRING}(v)
+ })`
+ )
expect(code).toMatchSnapshot()
})
@@ -345,7 +424,11 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`renderList(list, (v, __key, i) => toString(v))`)
+ expect(code).toMatch(
+ `return _${RENDER_LIST}(list, (v, __key, i) => {
+ return _${TO_STRING}(v)
+ })`
+ )
expect(code).toMatchSnapshot()
})
@@ -365,7 +448,11 @@ describe('compiler: codegen', () => {
]
})
)
- expect(code).toMatch(`renderList(list, (__value, __key, i) => toString(v))`)
+ expect(code).toMatch(
+ `return _${RENDER_LIST}(list, (__value, __key, i) => {
+ return _${TO_STRING}(v)
+ })`
+ )
expect(code).toMatchSnapshot()
})
diff --git a/packages/compiler-core/__tests__/compile.spec.ts b/packages/compiler-core/__tests__/compile.spec.ts
index d961d0693..ceb69aeae 100644
--- a/packages/compiler-core/__tests__/compile.spec.ts
+++ b/packages/compiler-core/__tests__/compile.spec.ts
@@ -2,35 +2,138 @@ import { compile } from '../src'
import { SourceMapConsumer, RawSourceMap } from 'source-map'
// Integration tests for parser + transform + codegen
-test('basic source map support', async () => {
- const source = `hello {{ world }}`
+test('function mode', async () => {
+ const source = `
+
+ {{ world }}
+
yes
+
no
+
{{ i + j }}
+
+`.trim()
const { code, map } = compile(source, {
sourceMap: true,
filename: `foo.vue`
})
- expect(code).toMatch(
- `const _Vue = Vue
-return function render() {
- with (this) {
- const { toString } = _Vue
- return [
- "hello ",
- toString(world)
- ]
- }
-}`
- )
+ expect(code).toMatchSnapshot()
expect(map!.sources).toEqual([`foo.vue`])
expect(map!.sourcesContent).toEqual([source])
const consumer = await new SourceMapConsumer(map as RawSourceMap)
- const pos = consumer.originalPositionFor({
- line: 7,
- column: 16
- })
- expect(pos).toMatchObject({
+
+ // id=
+ expect(
+ consumer.originalPositionFor({
+ line: 6,
+ column: 6
+ })
+ ).toMatchObject({
line: 1,
- column: 6
+ column: 5
+ })
+
+ // "foo"
+ expect(
+ consumer.originalPositionFor({
+ line: 6,
+ column: 10
+ })
+ ).toMatchObject({
+ line: 1,
+ column: 8
+ })
+
+ // :class=
+ expect(
+ consumer.originalPositionFor({
+ line: 7,
+ column: 6
+ })
+ ).toMatchObject({
+ line: 1,
+ column: 15
+ })
+ // bar
+ expect(
+ consumer.originalPositionFor({
+ line: 7,
+ column: 13
+ })
+ ).toMatchObject({
+ line: 1,
+ column: 22
+ })
+
+ // {{ world }}
+ expect(
+ consumer.originalPositionFor({
+ line: 9,
+ column: 16
+ })
+ ).toMatchObject({
+ line: 2,
+ column: 2
+ })
+
+ // ok
+ expect(
+ consumer.originalPositionFor({
+ line: 10,
+ column: 6
+ })
+ ).toMatchObject({
+ line: 3,
+ column: 13
+ })
+
+ // i
+ expect(
+ consumer.originalPositionFor({
+ line: 13,
+ column: 25
+ })
+ ).toMatchObject({
+ line: 5,
+ column: 15
+ })
+
+ // j
+ expect(
+ consumer.originalPositionFor({
+ line: 13,
+ column: 28
+ })
+ ).toMatchObject({
+ line: 5,
+ column: 18
+ })
+
+ // list
+ expect(
+ consumer.originalPositionFor({
+ line: 13,
+ column: 18
+ })
+ ).toMatchObject({
+ line: 5,
+ column: 24
+ })
+
+ // i + j
+ expect(
+ consumer.originalPositionFor({
+ line: 14,
+ column: 81
+ })
+ ).toMatchObject({
+ line: 5,
+ column: 36
})
})
+
+test.todo('function mode w/ prefixIdentifiers: true')
+
+test.todo('module mode')
+
+test.todo('module mode w/ prefixIdentifiers: true')
diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts
index 692f89bd8..d948f9ef9 100644
--- a/packages/compiler-core/__tests__/parse.spec.ts
+++ b/packages/compiler-core/__tests__/parse.spec.ts
@@ -894,8 +894,8 @@ describe('compiler: parse', () => {
isStatic: false,
isInterpolation: false,
loc: {
- start: { offset: 10, line: 1, column: 11 },
- end: { offset: 13, line: 1, column: 14 },
+ start: { offset: 11, line: 1, column: 12 },
+ end: { offset: 12, line: 1, column: 13 },
source: '"a"'
}
},
@@ -1303,25 +1303,27 @@ describe('compiler: parse', () => {
test('parse with correct location info', () => {
const [foo, bar, but, baz] = parse(
- 'foo \n is {{ bar }} but {{ baz }}'
+ `
+foo
+ is {{ bar }} but {{ baz }}`.trim()
).children
let offset = 0
expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
offset += foo.loc.source.length
- expect(foo.loc.end).toEqual({ line: 2, column: 4, offset })
+ expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
- expect(bar.loc.start).toEqual({ line: 2, column: 4, offset })
+ expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
offset += bar.loc.source.length
- expect(bar.loc.end).toEqual({ line: 2, column: 13, offset })
+ expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
- expect(but.loc.start).toEqual({ line: 2, column: 13, offset })
+ expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
offset += but.loc.source.length
- expect(but.loc.end).toEqual({ line: 2, column: 18, offset })
+ expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
- expect(baz.loc.start).toEqual({ line: 2, column: 18, offset })
+ expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
offset += baz.loc.source.length
- expect(baz.loc.end).toEqual({ line: 2, column: 27, offset })
+ expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
})
describe('namedCharacterReferences option', () => {
diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
index 1723d0f62..eb11cda61 100644
--- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
@@ -3,8 +3,7 @@ import {
CompilerOptions,
parse,
transform,
- ErrorCodes,
- compile
+ ErrorCodes
} from '../../src'
import { transformElement } from '../../src/transforms/transformElement'
import {
@@ -74,7 +73,7 @@ describe('compiler: element transform', () => {
const { root, node } = parseWithElementTransform(
``
)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
// should hoist the static object
expect(root.hoists).toMatchObject([
createStaticObjectMatcher({
@@ -95,7 +94,7 @@ describe('compiler: element transform', () => {
const { root, node } = parseWithElementTransform(
`
`
)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(root.hoists).toMatchObject([
createStaticObjectMatcher({
id: 'foo'
@@ -112,7 +111,7 @@ describe('compiler: element transform', () => {
type: NodeTypes.ELEMENT,
tag: 'span',
codegenNode: {
- callee: CREATE_VNODE,
+ callee: `_${CREATE_VNODE}`,
arguments: [`"span"`]
}
}
@@ -122,7 +121,7 @@ describe('compiler: element transform', () => {
test('0 placeholder for children with no props', () => {
const { node } = parseWithElementTransform(`
`)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments).toMatchObject([
`"div"`,
`0`,
@@ -131,7 +130,7 @@ describe('compiler: element transform', () => {
type: NodeTypes.ELEMENT,
tag: 'span',
codegenNode: {
- callee: CREATE_VNODE,
+ callee: `_${CREATE_VNODE}`,
arguments: [`"span"`]
}
}
@@ -143,7 +142,7 @@ describe('compiler: element transform', () => {
const { root, node } = parseWithElementTransform(``)
// single v-bind doesn't need mergeProps
expect(root.imports).not.toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
// should directly use `obj` in props position
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.EXPRESSION,
@@ -156,10 +155,10 @@ describe('compiler: element transform', () => {
``
)
expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: MERGE_PROPS,
+ callee: `_${MERGE_PROPS}`,
arguments: [
createStaticObjectMatcher({
id: 'foo'
@@ -177,10 +176,10 @@ describe('compiler: element transform', () => {
``
)
expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: MERGE_PROPS,
+ callee: `_${MERGE_PROPS}`,
arguments: [
{
type: NodeTypes.EXPRESSION,
@@ -198,10 +197,10 @@ describe('compiler: element transform', () => {
``
)
expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: MERGE_PROPS,
+ callee: `_${MERGE_PROPS}`,
arguments: [
createStaticObjectMatcher({
id: 'foo'
@@ -222,17 +221,17 @@ describe('compiler: element transform', () => {
``
)
expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: MERGE_PROPS,
+ callee: `_${MERGE_PROPS}`,
arguments: [
createStaticObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: TO_HANDLERS,
+ callee: `_${TO_HANDLERS}`,
arguments: [
{
type: NodeTypes.EXPRESSION,
@@ -252,17 +251,17 @@ describe('compiler: element transform', () => {
``
)
expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: MERGE_PROPS,
+ callee: `_${MERGE_PROPS}`,
arguments: [
createStaticObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: TO_HANDLERS,
+ callee: `_${TO_HANDLERS}`,
arguments: [
{
type: NodeTypes.EXPRESSION,
@@ -301,7 +300,7 @@ describe('compiler: element transform', () => {
}
}
})
- expect(node.callee).toBe(CREATE_VNODE)
+ expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: [
@@ -333,11 +332,11 @@ describe('compiler: element transform', () => {
expect(root.imports).toContain(RESOLVE_DIRECTIVE)
expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
- expect(node.callee).toBe(APPLY_DIRECTIVES)
+ expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: CREATE_VNODE,
+ callee: `_${CREATE_VNODE}`,
arguments: [
`"div"`,
{
@@ -388,7 +387,7 @@ describe('compiler: element transform', () => {
expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`)
expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`)
- expect(node.callee).toBe(APPLY_DIRECTIVES)
+ expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION
@@ -467,13 +466,7 @@ describe('compiler: element transform', () => {
])
})
- test('props dedupe', () => {
- const { code } = compile(
- `
- `
- )
- console.log(code)
- })
+ test.todo(`props dedupe`)
test.todo('slot outlets')
})
diff --git a/packages/compiler-core/__tests__/transforms/vBind.spec.ts b/packages/compiler-core/__tests__/transforms/vBind.spec.ts
index 016efeedd..fb12b20a5 100644
--- a/packages/compiler-core/__tests__/transforms/vBind.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vBind.spec.ts
@@ -49,11 +49,11 @@ describe('compiler: transform v-bind', () => {
loc: {
start: {
line: 1,
- column: 16
+ column: 17
},
end: {
line: 1,
- column: 20
+ column: 19
}
}
},
diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts
index 76100fbeb..30f54dce4 100644
--- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts
@@ -212,150 +212,155 @@ describe('compiler: transform v-for', () => {
const source = ''
const forNode = parseWithForTransform(source)
+ const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
- expect(forNode.valueAlias!.loc.start.offset).toBe(
- source.indexOf('item') - 1
- )
+ expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
- expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+ expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
- source.indexOf('item') + 4
+ itemOffset + 1 + `item`.length
)
+ const itemsOffset = source.indexOf('items')
expect(forNode.source.content).toBe('items')
- expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+ expect(forNode.source.loc.start.offset).toBe(itemsOffset)
expect(forNode.source.loc.start.line).toBe(1)
- expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+ expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
- expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+ expect(forNode.source.loc.end.column).toBe(
+ itemsOffset + 1 + `items`.length
+ )
})
test('bracketed value', () => {
const source = ''
const forNode = parseWithForTransform(source)
+ const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
- expect(forNode.valueAlias!.loc.start.offset).toBe(
- source.indexOf('item') - 1
- )
+ expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
- expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+ expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
- source.indexOf('item') + 4
+ itemOffset + 1 + `item`.length
)
+ const itemsOffset = source.indexOf('items')
expect(forNode.source.content).toBe('items')
- expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+ expect(forNode.source.loc.start.offset).toBe(itemsOffset)
expect(forNode.source.loc.start.line).toBe(1)
- expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+ expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
- expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+ expect(forNode.source.loc.end.column).toBe(
+ itemsOffset + 1 + `items`.length
+ )
})
test('de-structured value', () => {
const source = ''
const forNode = parseWithForTransform(source)
+ const valueIndex = source.indexOf('{ id, key }')
expect(forNode.valueAlias!.content).toBe('{ id, key }')
- expect(forNode.valueAlias!.loc.start.offset).toBe(
- source.indexOf('{ id, key }') - 1
- )
+ expect(forNode.valueAlias!.loc.start.offset).toBe(valueIndex)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
- expect(forNode.valueAlias!.loc.start.column).toBe(
- source.indexOf('{ id, key }')
- )
+ expect(forNode.valueAlias!.loc.start.column).toBe(valueIndex + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
- source.indexOf('{ id, key }') + '{ id, key }'.length
+ valueIndex + 1 + '{ id, key }'.length
)
+ const itemsOffset = source.indexOf('items')
expect(forNode.source.content).toBe('items')
- expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+ expect(forNode.source.loc.start.offset).toBe(itemsOffset)
expect(forNode.source.loc.start.line).toBe(1)
- expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+ expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
- expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+ expect(forNode.source.loc.end.column).toBe(
+ itemsOffset + 1 + `items`.length
+ )
})
test('bracketed value, key, index', () => {
const source = ''
const forNode = parseWithForTransform(source)
+ const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
- expect(forNode.valueAlias!.loc.start.offset).toBe(
- source.indexOf('item') - 1
- )
+ expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
- expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+ expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
- source.indexOf('item') + 4
+ itemOffset + 1 + `item`.length
)
+ const keyOffset = source.indexOf('key')
expect(forNode.keyAlias!.content).toBe('key')
- expect(forNode.keyAlias!.loc.start.offset).toBe(source.indexOf('key') - 1)
+ expect(forNode.keyAlias!.loc.start.offset).toBe(keyOffset)
expect(forNode.keyAlias!.loc.start.line).toBe(1)
- expect(forNode.keyAlias!.loc.start.column).toBe(source.indexOf('key'))
+ expect(forNode.keyAlias!.loc.start.column).toBe(keyOffset + 1)
expect(forNode.keyAlias!.loc.end.line).toBe(1)
- expect(forNode.keyAlias!.loc.end.column).toBe(source.indexOf('key') + 3)
+ expect(forNode.keyAlias!.loc.end.column).toBe(
+ keyOffset + 1 + `key`.length
+ )
+ const indexOffset = source.indexOf('index')
expect(forNode.objectIndexAlias!.content).toBe('index')
- expect(forNode.objectIndexAlias!.loc.start.offset).toBe(
- source.indexOf('index') - 1
- )
+ expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
- expect(forNode.objectIndexAlias!.loc.start.column).toBe(
- source.indexOf('index')
- )
+ expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.end.column).toBe(
- source.indexOf('index') + 5
+ indexOffset + 1 + `index`.length
)
+ const itemsOffset = source.indexOf('items')
expect(forNode.source.content).toBe('items')
- expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+ expect(forNode.source.loc.start.offset).toBe(itemsOffset)
expect(forNode.source.loc.start.line).toBe(1)
- expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+ expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
- expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+ expect(forNode.source.loc.end.column).toBe(
+ itemsOffset + 1 + `items`.length
+ )
})
test('skipped key', () => {
const source = ''
const forNode = parseWithForTransform(source)
+ const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
- expect(forNode.valueAlias!.loc.start.offset).toBe(
- source.indexOf('item') - 1
- )
+ expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
- expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+ expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
- source.indexOf('item') + 4
+ itemOffset + 1 + `item`.length
)
+ const indexOffset = source.indexOf('index')
expect(forNode.objectIndexAlias!.content).toBe('index')
- expect(forNode.objectIndexAlias!.loc.start.offset).toBe(
- source.indexOf('index') - 1
- )
+ expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
- expect(forNode.objectIndexAlias!.loc.start.column).toBe(
- source.indexOf('index')
- )
+ expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.end.column).toBe(
- source.indexOf('index') + 5
+ indexOffset + 1 + `index`.length
)
+ const itemsOffset = source.indexOf('items')
expect(forNode.source.content).toBe('items')
- expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+ expect(forNode.source.loc.start.offset).toBe(itemsOffset)
expect(forNode.source.loc.start.line).toBe(1)
- expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+ expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
- expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+ expect(forNode.source.loc.end.column).toBe(
+ itemsOffset + 1 + `items`.length
+ )
})
})
})
diff --git a/packages/compiler-core/__tests__/transforms/vIf.spec.ts b/packages/compiler-core/__tests__/transforms/vIf.spec.ts
index 2c6ddc463..a9da46889 100644
--- a/packages/compiler-core/__tests__/transforms/vIf.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vIf.spec.ts
@@ -29,9 +29,7 @@ describe('compiler: transform v-if', () => {
test('basic v-if', () => {
const node = parseWithIfTransform(``)
expect(node.type).toBe(NodeTypes.IF)
- expect(node.isRoot).toBe(true)
expect(node.branches.length).toBe(1)
- expect(node.branches[0].isRoot).toBe(true)
expect(node.branches[0].condition!.content).toBe(`ok`)
expect(node.branches[0].children.length).toBe(1)
expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
diff --git a/packages/compiler-core/__tests__/transforms/vOn.spec.ts b/packages/compiler-core/__tests__/transforms/vOn.spec.ts
index 713b34be5..2f2f131e6 100644
--- a/packages/compiler-core/__tests__/transforms/vOn.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vOn.spec.ts
@@ -50,11 +50,11 @@ describe('compiler: transform v-bind', () => {
loc: {
start: {
line: 1,
- column: 17
+ column: 18
},
end: {
line: 1,
- column: 26
+ column: 25
}
}
},
diff --git a/packages/compiler-core/__tests__/utils.spec.ts b/packages/compiler-core/__tests__/utils.spec.ts
index c83ce2261..b5d1bea04 100644
--- a/packages/compiler-core/__tests__/utils.spec.ts
+++ b/packages/compiler-core/__tests__/utils.spec.ts
@@ -28,7 +28,7 @@ describe('advancePositionWithClone', () => {
const pos = p(1, 1, 0)
const newPos = advancePositionWithClone(pos, 'foo\nbar\nbaz', 10)
- expect(newPos.column).toBe(2)
+ expect(newPos.column).toBe(3)
expect(newPos.line).toBe(3)
expect(newPos.offset).toBe(10)
})
@@ -62,7 +62,7 @@ describe('getInnerRange', () => {
expect(loc2.start.column).toBe(1)
expect(loc2.start.line).toBe(2)
expect(loc2.start.offset).toBe(4)
- expect(loc2.end.column).toBe(3)
+ expect(loc2.end.column).toBe(4)
expect(loc2.end.line).toBe(2)
expect(loc2.end.offset).toBe(7)
})
diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts
index 786cdfd4d..d9b3cbc4c 100644
--- a/packages/compiler-core/src/ast.ts
+++ b/packages/compiler-core/src/ast.ts
@@ -118,14 +118,12 @@ export interface ExpressionNode extends Node {
export interface IfNode extends Node {
type: NodeTypes.IF
branches: IfBranchNode[]
- isRoot: boolean
}
export interface IfBranchNode extends Node {
type: NodeTypes.IF_BRANCH
condition: ExpressionNode | undefined // else
children: ChildNode[]
- isRoot: boolean
}
export interface ForNode extends Node {
diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts
index 84e5a5d74..c851d9567 100644
--- a/packages/compiler-core/src/codegen.ts
+++ b/packages/compiler-core/src/codegen.ts
@@ -65,6 +65,7 @@ export interface CodegenContext extends Required {
offset: number
indentLevel: number
map?: SourceMapGenerator
+ helper(name: string): string
push(code: string, node?: CodegenNode): void
indent(): void
deindent(withoutNewLine?: boolean): void
@@ -98,11 +99,14 @@ function createCodegenContext(
? undefined
: new (require('source-map')).SourceMapGenerator(),
+ helper(name) {
+ return prefixIdentifiers ? name : `_${name}`
+ },
push(code, node?: CodegenNode) {
context.code += code
if (context.map) {
if (node) {
- context.map.addMapping({
+ const mapping = {
source: context.filename,
original: {
line: node.loc.start.line,
@@ -112,9 +116,10 @@ function createCodegenContext(
line: context.line,
column: context.column - 1
}
- })
+ }
+ context.map.addMapping(mapping)
}
- advancePositionWithMutation(context, code, code.length)
+ advancePositionWithMutation(context, code)
}
},
indent() {
@@ -144,7 +149,7 @@ export function generate(
): CodegenResult {
const context = createCodegenContext(ast, options)
const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
- const imports = ast.imports.join(', ')
+ const hasImports = ast.imports.length
// preambles
if (mode === 'function') {
@@ -152,9 +157,9 @@ export function generate(
// In prefix mode, we place the const declaration at top so it's done
// only once; But if we not prefixing, we place the decalration inside the
// with block so it doesn't incur the `in` check cost for every helper access.
- if (imports) {
+ if (hasImports) {
if (prefixIdentifiers) {
- push(`const { ${imports} } = Vue\n`)
+ push(`const { ${ast.imports.join(', ')} } = Vue\n`)
} else {
// save Vue in a separate variable to avoid collision
push(`const _Vue = Vue`)
@@ -164,8 +169,8 @@ export function generate(
push(`return `)
} else {
// generate import statements for helpers
- if (imports) {
- push(`import { ${imports} } from 'vue'\n`)
+ if (hasImports) {
+ push(`import { ${ast.imports.join(', ')} } from 'vue'\n`)
}
genHoists(ast.hoists, context)
push(`export default `)
@@ -179,8 +184,9 @@ export function generate(
push(`with (this) {`)
indent()
// function mode const declarations should be inside with block
- if (mode === 'function' && imports) {
- push(`const { ${imports} } = _Vue`)
+ // also they should be renamed to avoid collision with user properties
+ if (mode === 'function' && hasImports) {
+ push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
newline()
}
} else {
@@ -199,7 +205,7 @@ export function generate(
// generate the VNode tree expression
push(`return `)
- genChildren(ast.children, context, true /* asRoot */)
+ genChildren(ast.children, context, true)
if (!prefixIdentifiers) {
deindent()
push(`}`)
@@ -223,13 +229,12 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
}
// This will generate a single vnode call if:
-// - The list has length === 1, AND:
-// - This is a root node, OR:
-// - The only child is a text or expression.
+// - The target position explicitly allows a single node (root, if, for)
+// - The list has length === 1, AND The only child is a text or expression.
function genChildren(
children: ChildNode[],
context: CodegenContext,
- asRoot: boolean = false
+ allowSingle: boolean = false
) {
if (!children.length) {
return context.push(`null`)
@@ -237,7 +242,7 @@ function genChildren(
const child = children[0]
if (
children.length === 1 &&
- (asRoot ||
+ (allowSingle ||
child.type === NodeTypes.TEXT ||
child.type == NodeTypes.EXPRESSION)
) {
@@ -336,10 +341,10 @@ function genText(node: TextNode | ExpressionNode, context: CodegenContext) {
}
function genExpression(node: ExpressionNode, context: CodegenContext) {
- const { push } = context
+ const { push, helper } = context
const { content, children, isStatic, isInterpolation } = node
if (isInterpolation) {
- push(`${TO_STRING}(`)
+ push(`${helper(TO_STRING)}(`)
}
if (children) {
genCompoundExpression(node, context)
@@ -383,8 +388,11 @@ function genCompoundExpression(node: ExpressionNode, context: CodegenContext) {
function genComment(node: CommentNode, context: CodegenContext) {
if (__DEV__) {
- context.push(
- `${CREATE_VNODE}(${COMMENT}, 0, ${JSON.stringify(node.content)})`,
+ const { push, helper } = context
+ push(
+ `${helper(CREATE_VNODE)}(${helper(COMMENT)}, 0, ${JSON.stringify(
+ node.content
+ )})`,
node
)
}
@@ -396,7 +404,7 @@ function genIf(node: IfNode, context: CodegenContext) {
}
function genIfBranch(
- { condition, children, isRoot }: IfBranchNode,
+ { condition, children }: IfBranchNode,
branches: IfBranchNode[],
nextIndex: number,
context: CodegenContext
@@ -411,7 +419,7 @@ function genIfBranch(
indent()
context.indentLevel++
push(`? `)
- genChildren(children, context, isRoot)
+ genChildren(children, context, true)
context.indentLevel--
newline()
push(`: `)
@@ -424,14 +432,14 @@ function genIfBranch(
} else {
// v-else
__DEV__ && assert(nextIndex === branches.length)
- genChildren(children, context, isRoot)
+ genChildren(children, context, true)
}
}
function genFor(node: ForNode, context: CodegenContext) {
- const { push } = context
+ const { push, helper, indent, deindent } = context
const { source, keyAlias, valueAlias, objectIndexAlias, children } = node
- push(`${RENDER_LIST}(`, node)
+ push(`${helper(RENDER_LIST)}(`, node)
genExpression(source, context)
push(`, (`)
if (valueAlias) {
@@ -455,9 +463,12 @@ function genFor(node: ForNode, context: CodegenContext) {
push(`, `)
genExpression(objectIndexAlias, context)
}
- push(`) => `)
- genChildren(children, context)
- push(`)`)
+ push(`) => {`)
+ indent()
+ push(`return `)
+ genChildren(children, context, true)
+ deindent()
+ push(`})`)
}
// JavaScript
diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts
index e80480fba..b153bab0f 100644
--- a/packages/compiler-core/src/parse.ts
+++ b/packages/compiler-core/src/parse.ts
@@ -479,7 +479,14 @@ function parseAttribute(
advanceBy(context, name.length)
// Value
- let value: { content: string; loc: SourceLocation } | undefined = undefined
+ let value:
+ | {
+ content: string
+ isQuoted: boolean
+ loc: SourceLocation
+ }
+ | undefined = undefined
+
if (/^[\t\r\n\f ]*=/.test(context.source)) {
advanceSpaces(context)
advanceBy(context, 1)
@@ -530,6 +537,13 @@ function parseAttribute(
}
}
+ if (value && value.isQuoted) {
+ const valueLoc = value.loc
+ valueLoc.start.offset++
+ valueLoc.start.column++
+ valueLoc.end = advancePositionWithClone(valueLoc.start, value.content)
+ }
+
return {
type: NodeTypes.DIRECTIVE,
name:
@@ -567,13 +581,20 @@ function parseAttribute(
function parseAttributeValue(
context: ParserContext
-): { content: string; loc: SourceLocation } | undefined {
+):
+ | {
+ content: string
+ isQuoted: boolean
+ loc: SourceLocation
+ }
+ | undefined {
const start = getCursor(context)
let content: string
- if (/^["']/.test(context.source)) {
+ const quote = context.source[0]
+ const isQuoted = quote === `"` || quote === `'`
+ if (isQuoted) {
// Quoted value.
- const quote = context.source[0]
advanceBy(context, 1)
const endIndex = context.source.indexOf(quote)
@@ -605,7 +626,7 @@ function parseAttributeValue(
content = parseTextData(context, match[0].length, TextModes.ATTRIBUTE_VALUE)
}
- return { content, loc: getSelection(context, start) }
+ return { content, isQuoted, loc: getSelection(context, start) }
}
function parseInterpolation(
diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts
index ad62b402b..a7714b5c3 100644
--- a/packages/compiler-core/src/transform.ts
+++ b/packages/compiler-core/src/transform.ts
@@ -59,6 +59,7 @@ export interface TransformContext extends Required {
parent: ParentNode
childIndex: number
currentNode: ChildNode | null
+ helper(name: string): string
replaceNode(node: ChildNode): void
removeNode(node?: ChildNode): void
onNodeRemoved: () => void
@@ -89,6 +90,10 @@ function createTransformContext(
parent: root,
childIndex: 0,
currentNode: null,
+ helper(name) {
+ context.imports.add(name)
+ return prefixIdentifiers ? name : `_${name}`
+ },
replaceNode(node) {
/* istanbul ignore if */
if (__DEV__ && !context.currentNode) {
@@ -195,15 +200,15 @@ export function traverseNode(node: ChildNode, context: TransformContext) {
switch (node.type) {
case NodeTypes.COMMENT:
- context.imports.add(CREATE_VNODE)
+ context.helper(CREATE_VNODE)
// inject import for the Comment symbol, which is needed for creating
// comment nodes with `createVNode`
- context.imports.add(COMMENT)
+ context.helper(COMMENT)
break
case NodeTypes.EXPRESSION:
// no need to traverse, but we need to inject toString helper
if (node.isInterpolation) {
- context.imports.add(TO_STRING)
+ context.helper(TO_STRING)
}
break
diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts
index a28a9e1ea..e346afbd1 100644
--- a/packages/compiler-core/src/transforms/transformElement.ts
+++ b/packages/compiler-core/src/transforms/transformElement.ts
@@ -42,12 +42,11 @@ export const transformElement: NodeTransform = (node, context) => {
let componentIdentifier: string | undefined
if (isComponent) {
- context.imports.add(RESOLVE_COMPONENT)
componentIdentifier = `_component_${toValidId(node.tag)}`
context.statements.push(
- `const ${componentIdentifier} = ${RESOLVE_COMPONENT}(${JSON.stringify(
- node.tag
- )})`
+ `const ${componentIdentifier} = ${context.helper(
+ RESOLVE_COMPONENT
+ )}(${JSON.stringify(node.tag)})`
)
}
@@ -70,13 +69,15 @@ export const transformElement: NodeTransform = (node, context) => {
}
const { loc } = node
- context.imports.add(CREATE_VNODE)
- const vnode = createCallExpression(CREATE_VNODE, args, loc)
+ const vnode = createCallExpression(
+ context.helper(CREATE_VNODE),
+ args,
+ loc
+ )
if (runtimeDirectives && runtimeDirectives.length) {
- context.imports.add(APPLY_DIRECTIVES)
node.codegenNode = createCallExpression(
- APPLY_DIRECTIVES,
+ context.helper(APPLY_DIRECTIVES),
[
vnode,
createArrayExpression(
@@ -147,11 +148,10 @@ function buildProps(
mergeArgs.push(exp)
} else {
// v-on="obj" -> toHandlers(obj)
- context.imports.add(TO_HANDLERS)
mergeArgs.push({
type: NodeTypes.JS_CALL_EXPRESSION,
loc,
- callee: TO_HANDLERS,
+ callee: context.helper(TO_HANDLERS),
arguments: [exp]
})
}
@@ -197,8 +197,11 @@ function buildProps(
)
}
if (mergeArgs.length > 1) {
- context.imports.add(MERGE_PROPS)
- propsExpression = createCallExpression(MERGE_PROPS, mergeArgs, elementLoc)
+ propsExpression = createCallExpression(
+ context.helper(MERGE_PROPS),
+ mergeArgs,
+ elementLoc
+ )
} else {
// single v-bind with nothing else - no need for a mergeProps call
propsExpression = mergeArgs[0]
@@ -285,12 +288,12 @@ function createDirectiveArgs(
dir: DirectiveNode,
context: TransformContext
): ArrayExpression {
- // inject import for `resolveDirective`
- context.imports.add(RESOLVE_DIRECTIVE)
// inject statement for resolving directive
const dirIdentifier = `_directive_${toValidId(dir.name)}`
context.statements.push(
- `const ${dirIdentifier} = ${RESOLVE_DIRECTIVE}(${JSON.stringify(dir.name)})`
+ `const ${dirIdentifier} = ${context.helper(
+ RESOLVE_DIRECTIVE
+ )}(${JSON.stringify(dir.name)})`
)
const dirArgs: ArrayExpression['elements'] = [dirIdentifier]
const { loc } = dir
diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts
index b1cf727aa..04c6bf34d 100644
--- a/packages/compiler-core/src/transforms/vFor.ts
+++ b/packages/compiler-core/src/transforms/vFor.ts
@@ -24,7 +24,7 @@ export const transformFor = createStructuralDirectiveTransform(
const parseResult = parseForExpression(dir.exp, context)
if (parseResult) {
- context.imports.add(RENDER_LIST)
+ context.helper(RENDER_LIST)
const { source, value, key, index } = parseResult
context.replaceNode({
diff --git a/packages/compiler-core/src/transforms/vIf.ts b/packages/compiler-core/src/transforms/vIf.ts
index 70120d5f1..1d8fe08aa 100644
--- a/packages/compiler-core/src/transforms/vIf.ts
+++ b/packages/compiler-core/src/transforms/vIf.ts
@@ -19,14 +19,10 @@ export const transformIf = createStructuralDirectiveTransform(
processExpression(dir.exp, context)
}
if (dir.name === 'if') {
- // check if this v-if is root - so that in codegen we can avoid generating
- // arrays for each branch
- const isRoot = context.parent === context.root
context.replaceNode({
type: NodeTypes.IF,
loc: node.loc,
- branches: [createIfBranch(node, dir, isRoot)],
- isRoot
+ branches: [createIfBranch(node, dir)]
})
} else {
// locate the adjacent v-if
@@ -43,7 +39,7 @@ export const transformIf = createStructuralDirectiveTransform(
if (sibling && sibling.type === NodeTypes.IF) {
// move the node to the if node's branches
context.removeNode()
- const branch = createIfBranch(node, dir, sibling.isRoot)
+ const branch = createIfBranch(node, dir)
if (__DEV__ && comments.length) {
branch.children = [...comments, ...branch.children]
}
@@ -67,16 +63,11 @@ export const transformIf = createStructuralDirectiveTransform(
}
)
-function createIfBranch(
- node: ElementNode,
- dir: DirectiveNode,
- isRoot: boolean
-): IfBranchNode {
+function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
return {
type: NodeTypes.IF_BRANCH,
loc: node.loc,
condition: dir.name === 'else' ? undefined : dir.exp,
- children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node],
- isRoot
+ children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node]
}
}
diff --git a/packages/compiler-core/src/utils.ts b/packages/compiler-core/src/utils.ts
index f857f629e..2745b041c 100644
--- a/packages/compiler-core/src/utils.ts
+++ b/packages/compiler-core/src/utils.ts
@@ -31,7 +31,7 @@ export function getInnerRange(
export function advancePositionWithClone(
pos: Position,
source: string,
- numberOfCharacters: number
+ numberOfCharacters: number = source.length
): Position {
return advancePositionWithMutation({ ...pos }, source, numberOfCharacters)
}
@@ -41,7 +41,7 @@ export function advancePositionWithClone(
export function advancePositionWithMutation(
pos: Position,
source: string,
- numberOfCharacters: number
+ numberOfCharacters: number = source.length
): Position {
let linesCount = 0
let lastNewLinePos = -1
@@ -57,7 +57,7 @@ export function advancePositionWithMutation(
pos.column =
lastNewLinePos === -1
? pos.column + numberOfCharacters
- : Math.max(1, numberOfCharacters - lastNewLinePos - 1)
+ : Math.max(1, numberOfCharacters - lastNewLinePos)
return pos
}