From 616aea97877efeb4cfc53b50e8ed16638f91377e Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 6 Oct 2019 10:31:32 +0100 Subject: [PATCH 1/6] feat: add v-html transformer --- packages/compiler-dom/src/index.ts | 7 +++- packages/compiler-dom/src/transforms/vHtml.ts | 40 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/packages/compiler-dom/src/index.ts b/packages/compiler-dom/src/index.ts index 17a53a3f480..b5e7fef62fa 100644 --- a/packages/compiler-dom/src/index.ts +++ b/packages/compiler-dom/src/index.ts @@ -2,6 +2,7 @@ import { baseCompile, CompilerOptions, CodegenResult } from '@vue/compiler-core' import { parserOptionsMinimal } from './parserOptionsMinimal' import { parserOptionsStandard } from './parserOptionsStandard' import { transformStyle } from './transforms/transformStyle' +import { transformHtml } from './transforms/vHtml' export function compile( template: string, @@ -10,7 +11,11 @@ export function compile( return baseCompile(template, { ...options, ...(__BROWSER__ ? parserOptionsMinimal : parserOptionsStandard), - nodeTransforms: [transformStyle, ...(options.nodeTransforms || [])], + nodeTransforms: [ + transformStyle, + transformHtml, + ...(options.nodeTransforms || []) + ], directiveTransforms: { // TODO include DOM-specific directiveTransforms ...(options.directiveTransforms || {}) diff --git a/packages/compiler-dom/src/transforms/vHtml.ts b/packages/compiler-dom/src/transforms/vHtml.ts index 70b786d12ed..a772455af64 100644 --- a/packages/compiler-dom/src/transforms/vHtml.ts +++ b/packages/compiler-dom/src/transforms/vHtml.ts @@ -1 +1,39 @@ -// TODO +import { + createStructuralDirectiveTransform, + createCompilerError, + ErrorCodes, + createSimpleExpression, + SimpleExpressionNode, + NodeTypes +} from '@vue/compiler-core' + +export const transformHtml = createStructuralDirectiveTransform( + 'html', + (node, dir, context) => { + if (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim()) { + const loc = dir.exp ? dir.exp.loc : node.loc + context.onError( + createCompilerError(ErrorCodes.X_V_HTML_NO_EXPRESSION, dir.loc) + ) + dir.exp = createSimpleExpression('', true, loc) + } + + // v-show can't be used outside of an element + if (node.type !== NodeTypes.ELEMENT) { + createCompilerError(ErrorCodes.X_V_HTML_UNEXPECTED_USAGE, dir.loc) + } + + // add prop innerHTML + node.props.push({ + type: NodeTypes.DIRECTIVE, + name: `bind`, + arg: createSimpleExpression(`innerHTML`, true, dir.loc), + exp: dir.exp, + modifiers: [], + loc: dir.loc + }) + + // remove all the children, since they will be overridden by the `innerHTML` + node.children = [] + } +) From 32762b80ea1d5bf874497cd88bf6681ff6220f72 Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 6 Oct 2019 10:44:27 +0100 Subject: [PATCH 2/6] fix: added the errors and tests --- packages/compiler-core/src/errors.ts | 2 + .../__tests__/transforms/vHtml.spec.ts | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 packages/compiler-dom/__tests__/transforms/vHtml.spec.ts diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index 64716f7ed12..477d2f46999 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -68,6 +68,8 @@ export const enum ErrorCodes { X_FOR_MALFORMED_EXPRESSION, X_V_BIND_NO_EXPRESSION, X_V_ON_NO_EXPRESSION, + X_V_HTML_NO_EXPRESSION, + X_V_HTML_UNEXPECTED_USAGE, X_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET, X_NAMED_SLOT_ON_COMPONENT, X_MIXED_SLOT_USAGE, diff --git a/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts new file mode 100644 index 00000000000..2f2f1bceb17 --- /dev/null +++ b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts @@ -0,0 +1,64 @@ +import { + parse, + transform, + CompilerOptions, + ElementNode, + NodeTypes +} from '@vue/compiler-core' +import { transformHtml } from '../../src/transforms/vHtml' + +function transformWithStyleTransform( + template: string, + options: CompilerOptions = {} +) { + const ast = parse(template) + transform(ast, { + nodeTransforms: [transformHtml], + ...options + }) + return { + root: ast, + node: ast.children[0] as ElementNode + } +} + +describe('compiler: style transform', () => { + it('should add `innerHtml` prop', () => { + const { node } = transformWithStyleTransform(`
`) + expect(node.props[0]).toMatchObject({ + type: NodeTypes.DIRECTIVE, + name: `bind`, + arg: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `innerHTML`, + isStatic: true + }, + exp: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `test`, + isStatic: false + } + }) + }) + + it('should remove all children', () => { + const { node } = transformWithStyleTransform( + `

foo

bar

` + ) + expect(node.children).toHaveLength(0) + expect(node.props[0]).toMatchObject({ + type: NodeTypes.DIRECTIVE, + name: `bind`, + arg: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `innerHTML`, + isStatic: true + }, + exp: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `test`, + isStatic: false + } + }) + }) +}) From d9321c89a9317f195fcb329ab4a9c9cb57f514b1 Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 6 Oct 2019 11:11:35 +0100 Subject: [PATCH 3/6] fix: typos --- packages/compiler-dom/__tests__/transforms/vHtml.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts index 2f2f1bceb17..3b2fdb2f531 100644 --- a/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts @@ -7,7 +7,7 @@ import { } from '@vue/compiler-core' import { transformHtml } from '../../src/transforms/vHtml' -function transformWithStyleTransform( +function transformWithHtmlTransform( template: string, options: CompilerOptions = {} ) { @@ -22,9 +22,9 @@ function transformWithStyleTransform( } } -describe('compiler: style transform', () => { +describe('compiler: html transform', () => { it('should add `innerHtml` prop', () => { - const { node } = transformWithStyleTransform(`
`) + const { node } = transformWithHtmlTransform(`
`) expect(node.props[0]).toMatchObject({ type: NodeTypes.DIRECTIVE, name: `bind`, @@ -42,7 +42,7 @@ describe('compiler: style transform', () => { }) it('should remove all children', () => { - const { node } = transformWithStyleTransform( + const { node } = transformWithHtmlTransform( `

foo

bar

` ) expect(node.children).toHaveLength(0) From 197f3608865b34866a91cc4cbae04cd326a4af0a Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 6 Oct 2019 17:10:55 +0100 Subject: [PATCH 4/6] feat: add warning when replacing children --- .../compiler-dom/__tests__/transforms/vHtml.spec.ts | 3 +++ packages/compiler-dom/src/transforms/vHtml.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts index 3b2fdb2f531..104e1b5a2ba 100644 --- a/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/vHtml.spec.ts @@ -5,6 +5,7 @@ import { ElementNode, NodeTypes } from '@vue/compiler-core' +import { mockWarn } from '@vue/runtime-test' import { transformHtml } from '../../src/transforms/vHtml' function transformWithHtmlTransform( @@ -23,6 +24,7 @@ function transformWithHtmlTransform( } describe('compiler: html transform', () => { + mockWarn() it('should add `innerHtml` prop', () => { const { node } = transformWithHtmlTransform(`
`) expect(node.props[0]).toMatchObject({ @@ -60,5 +62,6 @@ describe('compiler: html transform', () => { isStatic: false } }) + expect(`"v-html" replaced children on "div" element`).toHaveBeenWarned() }) }) diff --git a/packages/compiler-dom/src/transforms/vHtml.ts b/packages/compiler-dom/src/transforms/vHtml.ts index a772455af64..bf462cce3e1 100644 --- a/packages/compiler-dom/src/transforms/vHtml.ts +++ b/packages/compiler-dom/src/transforms/vHtml.ts @@ -33,7 +33,13 @@ export const transformHtml = createStructuralDirectiveTransform( loc: dir.loc }) - // remove all the children, since they will be overridden by the `innerHTML` - node.children = [] + if (node.children.length > 0) { + // remove all the children, since they will be overridden by the `innerHTML` + node.children = [] + + if (__DEV__) { + console.warn(`"v-html" replaced children on "${node.tag}" element`) + } + } } ) From 2b05095f6da90db2ef946dbbc9b68e198976a617 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 7 Oct 2019 08:15:18 +0100 Subject: [PATCH 5/6] feat: v-html change to a simple transform and add compiler error --- packages/compiler-core/src/errors.ts | 2 +- packages/compiler-dom/src/transforms/vHtml.ts | 58 ++++++++----------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index 477d2f46999..fba4770d61e 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -69,7 +69,6 @@ export const enum ErrorCodes { X_V_BIND_NO_EXPRESSION, X_V_ON_NO_EXPRESSION, X_V_HTML_NO_EXPRESSION, - X_V_HTML_UNEXPECTED_USAGE, X_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET, X_NAMED_SLOT_ON_COMPONENT, X_MIXED_SLOT_USAGE, @@ -146,6 +145,7 @@ export const errorMessages: { [code: number]: string } = { [ErrorCodes.X_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`, [ErrorCodes.X_V_BIND_NO_EXPRESSION]: `v-bind is missing expression.`, [ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression.`, + [ErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`, [ErrorCodes.X_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET]: `Unexpected custom directive on outlet.`, [ErrorCodes.X_NAMED_SLOT_ON_COMPONENT]: `Named v-slot on component. ` + diff --git a/packages/compiler-dom/src/transforms/vHtml.ts b/packages/compiler-dom/src/transforms/vHtml.ts index bf462cce3e1..f18e8f6d35d 100644 --- a/packages/compiler-dom/src/transforms/vHtml.ts +++ b/packages/compiler-dom/src/transforms/vHtml.ts @@ -1,45 +1,33 @@ import { - createStructuralDirectiveTransform, createCompilerError, ErrorCodes, createSimpleExpression, - SimpleExpressionNode, - NodeTypes + NodeTypes, + NodeTransform, + DirectiveNode } from '@vue/compiler-core' -export const transformHtml = createStructuralDirectiveTransform( - 'html', - (node, dir, context) => { - if (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim()) { - const loc = dir.exp ? dir.exp.loc : node.loc - context.onError( - createCompilerError(ErrorCodes.X_V_HTML_NO_EXPRESSION, dir.loc) - ) - dir.exp = createSimpleExpression('', true, loc) - } - - // v-show can't be used outside of an element - if (node.type !== NodeTypes.ELEMENT) { - createCompilerError(ErrorCodes.X_V_HTML_UNEXPECTED_USAGE, dir.loc) - } +export const transformHtml: NodeTransform = (node, context) => { + if (node.type === NodeTypes.ELEMENT) { + const htmlProp = node.props.find( + x => x.type === NodeTypes.DIRECTIVE && x.name === 'html' + ) as DirectiveNode | undefined + if (htmlProp) { + htmlProp.name = `bind` + htmlProp.arg = createSimpleExpression(`innerHTML`, true, htmlProp.loc) - // add prop innerHTML - node.props.push({ - type: NodeTypes.DIRECTIVE, - name: `bind`, - arg: createSimpleExpression(`innerHTML`, true, dir.loc), - exp: dir.exp, - modifiers: [], - loc: dir.loc - }) - - if (node.children.length > 0) { - // remove all the children, since they will be overridden by the `innerHTML` - node.children = [] - - if (__DEV__) { - console.warn(`"v-html" replaced children on "${node.tag}" element`) + if (!htmlProp.exp || !htmlProp.exp.loc.source.trim()) { + context.onError( + createCompilerError(ErrorCodes.X_V_HTML_NO_EXPRESSION, htmlProp.loc) + ) + } + if (node.children.length > 0) { + // remove all the children, since they will be overridden by the `innerHTML` + node.children = [] + if (__DEV__) { + console.warn(`"v-html" replaced children on "${node.tag}" element`) + } } } } -) +} From 9a696d6b3aa3072e311d2a9c38efc0b51a66ad14 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 7 Oct 2019 09:04:01 +0100 Subject: [PATCH 6/6] fix: rename variable to prop --- packages/compiler-dom/src/transforms/vHtml.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/compiler-dom/src/transforms/vHtml.ts b/packages/compiler-dom/src/transforms/vHtml.ts index f18e8f6d35d..07f90da7ceb 100644 --- a/packages/compiler-dom/src/transforms/vHtml.ts +++ b/packages/compiler-dom/src/transforms/vHtml.ts @@ -9,16 +9,16 @@ import { export const transformHtml: NodeTransform = (node, context) => { if (node.type === NodeTypes.ELEMENT) { - const htmlProp = node.props.find( + const prop = node.props.find( x => x.type === NodeTypes.DIRECTIVE && x.name === 'html' ) as DirectiveNode | undefined - if (htmlProp) { - htmlProp.name = `bind` - htmlProp.arg = createSimpleExpression(`innerHTML`, true, htmlProp.loc) + if (prop) { + prop.name = `bind` + prop.arg = createSimpleExpression(`innerHTML`, true, prop.loc) - if (!htmlProp.exp || !htmlProp.exp.loc.source.trim()) { + if (!prop.exp || !prop.exp.loc.source.trim()) { context.onError( - createCompilerError(ErrorCodes.X_V_HTML_NO_EXPRESSION, htmlProp.loc) + createCompilerError(ErrorCodes.X_V_HTML_NO_EXPRESSION, prop.loc) ) } if (node.children.length > 0) {