diff --git a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap index 91d3bf425..2a0a6c1dc 100644 --- a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap @@ -7,9 +7,9 @@ return function render() { const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue return _createVNode(\\"div\\", { id: \\"foo\\", - class: bar + class: bar.baz }, [ - _toString(world), + _toString(world.burn()), ok ? _createVNode(\\"div\\", 0, \\"yes\\") : \\"no\\", @@ -21,25 +21,6 @@ return function render() { }" `; -exports[`compiler: integration tests function mode 2`] = ` -Object { - "mappings": ";;;;WAAA,oBAAA;MAAK,IAAG;MAAO,OAAO;;gBACpB;MACW;UAAX,uBAAe;UACE;MACjB,YAA8B,OAAjB,OAAO;eAApB,wBAAoC,kCAAM", - "names": Array [], - "sources": Array [ - "foo.vue", - ], - "sourcesContent": Array [ - "
- {{ world }} -
yes
- -
{{ value + index }}
-
", - ], - "version": 3, -} -`; - exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = ` "const { createVNode, toString, renderList } = Vue @@ -47,9 +28,9 @@ return function render() { const _ctx = this return createVNode(\\"div\\", { id: \\"foo\\", - class: _ctx.bar + class: _ctx.bar.baz }, [ - toString(_ctx.world), + toString(_ctx.world.burn()), (_ctx.ok) ? createVNode(\\"div\\", 0, \\"yes\\") : \\"no\\", @@ -60,30 +41,6 @@ return function render() { }" `; -exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 2`] = ` -Object { - "mappings": ";;;;SAAA,mBAAA;IAAK,IAAG;IAAO,OAAOA;;aACpBC;KACWC;QAAX,sBAAe;QACE;IACjB,WAA8BC,YAAjB,OAAO;aAApB,uBAAoC,gCAAS,QAAQ", - "names": Array [ - "bar", - "world", - "ok", - "list", - ], - "sources": Array [ - "foo.vue", - ], - "sourcesContent": Array [ - "
- {{ world }} -
yes
- -
{{ value + index }}
-
", - ], - "version": 3, -} -`; - exports[`compiler: integration tests module mode 1`] = ` "import { createVNode, toString, renderList } from \\"vue\\" @@ -91,9 +48,9 @@ export default function render() { const _ctx = this return createVNode(\\"div\\", { id: \\"foo\\", - class: _ctx.bar + class: _ctx.bar.baz }, [ - _toString(_ctx.world), + _toString(_ctx.world.burn()), (_ctx.ok) ? createVNode(\\"div\\", 0, \\"yes\\") : \\"no\\", diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap index 694b37348..947bfb04b 100644 --- a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap @@ -3889,15 +3889,15 @@ Object { "isStatic": false, "loc": Object { "end": Object { - "column": 20, + "column": 18, "line": 1, - "offset": 19, + "offset": 17, }, - "source": "{{a < b}}", + "source": "a < b", "start": Object { - "column": 11, + "column": 13, "line": 1, - "offset": 10, + "offset": 12, }, }, "type": 4, @@ -6965,15 +6965,15 @@ Object { "isStatic": false, "loc": Object { "end": Object { - "column": 23, + "column": 21, "line": 1, - "offset": 22, + "offset": 20, }, - "source": "{{''}}", + "source": "''", "start": Object { - "column": 11, + "column": 13, "line": 1, - "offset": 10, + "offset": 12, }, }, "type": 4, @@ -7322,15 +7322,15 @@ Object { "isStatic": true, "loc": Object { "end": Object { - "column": 5, + "column": 3, "line": 1, - "offset": 4, + "offset": 2, }, - "source": "{{}}", + "source": "", "start": Object { - "column": 1, + "column": 3, "line": 1, - "offset": 0, + "offset": 2, }, }, "type": 4, @@ -7485,7 +7485,7 @@ Object { "line": 1, "offset": 32, }, - "source": "\\"{ some: condition }\\"", + "source": "{ some: condition }", "start": Object { "column": 14, "line": 1, @@ -7565,7 +7565,7 @@ Object { "line": 2, "offset": 70, }, - "source": "\\"{ color: 'red' }\\"", + "source": "{ color: 'red' }", "start": Object { "column": 18, "line": 2, @@ -7672,7 +7672,7 @@ Object { "line": 2, "offset": 70, }, - "source": "\\"{ color: 'red' }\\"", + "source": "{ color: 'red' }", "start": Object { "column": 20, "line": 2, @@ -7771,7 +7771,7 @@ Object { "line": 1, "offset": 32, }, - "source": "\\"{ some: condition }\\"", + "source": "{ some: condition }", "start": Object { "column": 14, "line": 1, diff --git a/packages/compiler-core/__tests__/compile.spec.ts b/packages/compiler-core/__tests__/compile.spec.ts index e5302247d..951702ba2 100644 --- a/packages/compiler-core/__tests__/compile.spec.ts +++ b/packages/compiler-core/__tests__/compile.spec.ts @@ -3,8 +3,8 @@ import { SourceMapConsumer, RawSourceMap } from 'source-map' describe('compiler: integration tests', () => { const source = ` -
- {{ world }} +
+ {{ world.burn() }}
yes
{{ value + index }}
@@ -55,7 +55,6 @@ describe('compiler: integration tests', () => { ) expect(code).toMatchSnapshot() - expect(map).toMatchSnapshot() expect(map!.sources).toEqual([`foo.vue`]) expect(map!.sourcesContent).toEqual([source]) @@ -77,9 +76,21 @@ describe('compiler: integration tests', () => { consumer.originalPositionFor(getPositionInCode(code, `bar`)) ).toMatchObject(getPositionInCode(source, `bar`)) + // without prefixIdentifiers: true, identifiers inside compound expressions + // are mapped to closest parent expression. + expect( + consumer.originalPositionFor(getPositionInCode(code, `baz`)) + ).toMatchObject(getPositionInCode(source, `bar`)) + expect( consumer.originalPositionFor(getPositionInCode(code, `world`)) - ).toMatchObject(getPositionInCode(source, `{{ world }}`)) + ).toMatchObject(getPositionInCode(source, `world`)) + + // without prefixIdentifiers: true, identifiers inside compound expressions + // are mapped to closest parent expression. + expect( + consumer.originalPositionFor(getPositionInCode(code, `burn()`)) + ).toMatchObject(getPositionInCode(source, `world`)) expect( consumer.originalPositionFor(getPositionInCode(code, `ok`)) @@ -99,7 +110,7 @@ describe('compiler: integration tests', () => { expect( consumer.originalPositionFor(getPositionInCode(code, `value + index`)) - ).toMatchObject(getPositionInCode(source, `{{ value + index }}`)) + ).toMatchObject(getPositionInCode(source, `value + index`)) }) test('function mode w/ prefixIdentifiers: true', async () => { @@ -112,7 +123,6 @@ describe('compiler: integration tests', () => { expect(code).toMatch(`const { createVNode, toString, renderList } = Vue`) expect(code).toMatchSnapshot() - expect(map).toMatchSnapshot() expect(map!.sources).toEqual([`foo.vue`]) expect(map!.sourcesContent).toEqual([source]) @@ -136,15 +146,22 @@ describe('compiler: integration tests', () => { expect( consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)) ).toMatchObject(getPositionInCode(source, `bar`, true)) + expect( + consumer.originalPositionFor(getPositionInCode(code, `baz`)) + ).toMatchObject(getPositionInCode(source, `baz`)) expect( consumer.originalPositionFor(getPositionInCode(code, `world`, true)) - ).toMatchObject(getPositionInCode(source, `{{ world }}`, `world`)) + ).toMatchObject(getPositionInCode(source, `world`, `world`)) expect( consumer.originalPositionFor( getPositionInCode(code, `_ctx.world`, `world`) ) - ).toMatchObject(getPositionInCode(source, `{{ world }}`, `world`)) + ).toMatchObject(getPositionInCode(source, `world`, `world`)) + + expect( + consumer.originalPositionFor(getPositionInCode(code, `burn()`)) + ).toMatchObject(getPositionInCode(source, `burn()`)) expect( consumer.originalPositionFor(getPositionInCode(code, `ok`)) @@ -208,15 +225,22 @@ describe('compiler: integration tests', () => { expect( consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)) ).toMatchObject(getPositionInCode(source, `bar`, true)) + expect( + consumer.originalPositionFor(getPositionInCode(code, `baz`)) + ).toMatchObject(getPositionInCode(source, `baz`)) expect( consumer.originalPositionFor(getPositionInCode(code, `world`, true)) - ).toMatchObject(getPositionInCode(source, `{{ world }}`, `world`)) + ).toMatchObject(getPositionInCode(source, `world`, `world`)) expect( consumer.originalPositionFor( getPositionInCode(code, `_ctx.world`, `world`) ) - ).toMatchObject(getPositionInCode(source, `{{ world }}`, `world`)) + ).toMatchObject(getPositionInCode(source, `world`, `world`)) + + expect( + consumer.originalPositionFor(getPositionInCode(code, `burn()`)) + ).toMatchObject(getPositionInCode(source, `burn()`)) expect( consumer.originalPositionFor(getPositionInCode(code, `ok`)) diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts index d948f9ef9..cd99f3b95 100644 --- a/packages/compiler-core/__tests__/parse.spec.ts +++ b/packages/compiler-core/__tests__/parse.spec.ts @@ -298,9 +298,9 @@ describe('compiler: parse', () => { isStatic: false, isInterpolation: true, loc: { - start: { offset: 0, line: 1, column: 1 }, - end: { offset: 11, line: 1, column: 12 }, - source: '{{message}}' + start: { offset: 2, line: 1, column: 3 }, + end: { offset: 9, line: 1, column: 10 }, + source: 'message' } }) }) @@ -315,9 +315,9 @@ describe('compiler: parse', () => { isStatic: false, isInterpolation: true, loc: { - start: { offset: 0, line: 1, column: 1 }, - end: { offset: 9, line: 1, column: 10 }, - source: '{{ a { isStatic: false, isInterpolation: true, loc: { - start: { offset: 0, line: 1, column: 1 }, - end: { offset: 9, line: 1, column: 10 }, - source: '{{ a { isStatic: false, isInterpolation: true, loc: { - start: { offset: 9, line: 1, column: 10 }, - end: { offset: 18, line: 1, column: 19 }, - source: '{{ c>d }}' + start: { offset: 12, line: 1, column: 13 }, + end: { offset: 15, line: 1, column: 16 }, + source: 'c>d' } }) }) @@ -362,9 +362,9 @@ describe('compiler: parse', () => { isStatic: false, isInterpolation: true, loc: { - start: { offset: 5, line: 1, column: 6 }, - end: { offset: 19, line: 1, column: 20 }, - source: '{{ "
" }}' + start: { offset: 8, line: 1, column: 9 }, + end: { offset: 16, line: 1, column: 17 }, + source: '"
"' } }) }) @@ -896,7 +896,7 @@ describe('compiler: parse', () => { loc: { start: { offset: 11, line: 1, column: 12 }, end: { offset: 12, line: 1, column: 13 }, - source: '"a"' + source: 'a' } }, loc: { @@ -1313,17 +1313,20 @@ foo offset += foo.loc.source.length expect(foo.loc.end).toEqual({ line: 2, column: 5, offset }) - expect(bar.loc.start).toEqual({ line: 2, column: 5, offset }) + offset += 3 + expect(bar.loc.start).toEqual({ line: 2, column: 8, offset }) offset += bar.loc.source.length - expect(bar.loc.end).toEqual({ line: 2, column: 14, offset }) + expect(bar.loc.end).toEqual({ line: 2, column: 11, offset }) + offset += 3 expect(but.loc.start).toEqual({ line: 2, column: 14, offset }) offset += but.loc.source.length expect(but.loc.end).toEqual({ line: 2, column: 19, offset }) - expect(baz.loc.start).toEqual({ line: 2, column: 19, offset }) + offset += 3 + expect(baz.loc.start).toEqual({ line: 2, column: 22, offset }) offset += baz.loc.source.length - expect(baz.loc.end).toEqual({ line: 2, column: 28, offset }) + expect(baz.loc.end).toEqual({ line: 2, column: 25, offset }) }) describe('namedCharacterReferences option', () => { diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 566a9f71a..a7e0727b3 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -66,7 +66,7 @@ export interface CodegenContext extends Required { indentLevel: number map?: SourceMapGenerator helper(name: string): string - push(code: string, node?: CodegenNode): void + push(code: string, node?: CodegenNode, openOnly?: boolean): void indent(): void deindent(withoutNewLine?: boolean): void newline(): void @@ -102,7 +102,7 @@ function createCodegenContext( helper(name) { return prefixIdentifiers ? name : `_${name}` }, - push(code, node?: CodegenNode) { + push(code, node, openOnly) { context.code += code if (context.map) { if (node) { @@ -131,6 +131,19 @@ function createCodegenContext( }) } advancePositionWithMutation(context, code) + if (node && !openOnly) { + context.map.addMapping({ + source: context.filename, + original: { + line: node.loc.end.line, + column: node.loc.end.column - 1 + }, + generated: { + line: context.line, + column: context.column - 1 + } + }) + } } }, indent() { @@ -453,7 +466,7 @@ function genIfBranch( function genFor(node: ForNode, context: CodegenContext) { const { push, helper, indent, deindent } = context const { source, keyAlias, valueAlias, objectIndexAlias, children } = node - push(`${helper(RENDER_LIST)}(`, node) + push(`${helper(RENDER_LIST)}(`, node, true) genExpression(source, context) push(`, (`) if (valueAlias) { @@ -491,7 +504,7 @@ function genCallExpression( context: CodegenContext, multilines = node.arguments.length > 2 ) { - context.push(node.callee + `(`, node) + context.push(node.callee + `(`, node, true) multilines && context.indent() genNodeList(node.arguments, context, multilines) multilines && context.deindent() @@ -502,7 +515,7 @@ function genObjectExpression(node: ObjectExpression, context: CodegenContext) { const { push, indent, deindent, newline } = context const { properties } = node const multilines = properties.length > 1 - push(multilines ? `{` : `{ `, node) + push(multilines ? `{` : `{ `) multilines && indent() for (let i = 0; i < properties.length; i++) { const { key, value } = properties[i] diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts index b153bab0f..6dfde5a7f 100644 --- a/packages/compiler-core/src/parse.ts +++ b/packages/compiler-core/src/parse.ts @@ -542,6 +542,7 @@ function parseAttribute( valueLoc.start.offset++ valueLoc.start.column++ valueLoc.end = advancePositionWithClone(valueLoc.start, value.content) + valueLoc.source = valueLoc.source.slice(1, -1) } return { @@ -642,15 +643,26 @@ function parseInterpolation( return undefined } - const start = getCursor(context) advanceBy(context, open.length) - const content = parseTextData(context, closeIndex - open.length, mode).trim() + const start = getCursor(context) + const end = getCursor(context) + const rawContentLength = closeIndex - open.length + const rawContent = context.source.slice(0, rawContentLength) + const preTrimContent = parseTextData(context, rawContentLength, mode) + const content = preTrimContent.trim() + const startOffset = preTrimContent.indexOf(content) + if (startOffset > 0) { + advancePositionWithMutation(start, rawContent, startOffset) + } + const endOffset = + rawContentLength - (preTrimContent.length - content.length - startOffset) + advancePositionWithMutation(end, rawContent, endOffset) advanceBy(context, close.length) return { type: NodeTypes.EXPRESSION, content, - loc: getSelection(context, start), + loc: getSelection(context, start, end), isStatic: content === '', isInterpolation: true } diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts index 533108ace..90aedf060 100644 --- a/packages/compiler-core/src/transforms/transformExpression.ts +++ b/packages/compiler-core/src/transforms/transformExpression.ts @@ -157,8 +157,8 @@ export function processExpression( children.push( createExpression(id.name, false, { source, - start: advancePositionWithClone(node.loc.start, source, id.start + 2), - end: advancePositionWithClone(node.loc.start, source, id.end + 2) + start: advancePositionWithClone(node.loc.start, source, id.start - 1), + end: advancePositionWithClone(node.loc.start, source, id.end - 1) }) ) if (i === ids.length - 1 && id.end - 1 < full.length) { diff --git a/packages/compiler-dom/__tests__/parse.spec.ts b/packages/compiler-dom/__tests__/parse.spec.ts index f9054ab45..6913514fb 100644 --- a/packages/compiler-dom/__tests__/parse.spec.ts +++ b/packages/compiler-dom/__tests__/parse.spec.ts @@ -117,9 +117,9 @@ describe('DOM parser', () => { isStatic: false, isInterpolation: true, loc: { - start: { offset: 5, line: 1, column: 6 }, - end: { offset: 19, line: 1, column: 20 }, - source: '{{ a < b }}' + start: { offset: 8, line: 1, column: 9 }, + end: { offset: 16, line: 1, column: 17 }, + source: 'a < b' } }) })