update entities encoding/decoding (fix #3899)

This commit is contained in:
Evan You 2016-10-13 05:05:35 -04:00
parent a675221bb6
commit d362d64633
13 changed files with 31 additions and 47 deletions

View File

@ -38,7 +38,7 @@ const builds = {
env: 'development',
banner,
alias: {
entities: './entity-decoder'
he: './entity-decoder'
}
},
// Runtime+compiler standalone production build.
@ -49,7 +49,7 @@ const builds = {
env: 'production',
banner,
alias: {
entities: './entity-decoder'
he: './entity-decoder'
}
},
// Web compiler (CommonJS).
@ -57,14 +57,14 @@ const builds = {
entry: path.resolve(__dirname, '../src/entries/web-compiler.js'),
dest: path.resolve(__dirname, '../packages/vue-template-compiler/build.js'),
format: 'cjs',
external: ['entities', 'de-indent']
external: ['he', 'de-indent']
},
// Web server renderer (CommonJS).
'web-server-renderer': {
entry: path.resolve(__dirname, '../src/entries/web-server-renderer.js'),
dest: path.resolve(__dirname, '../packages/vue-server-renderer/build.js'),
format: 'cjs',
external: ['stream', 'module', 'vm', 'entities', 'de-indent']
external: ['stream', 'module', 'vm', 'he', 'de-indent']
}
}

View File

@ -1,6 +1,6 @@
declare module 'entities' {
declare function encodeHTML(html: string): string;
declare function decodeHTML(html: string): string;
declare module 'he' {
declare function escape(html: string): string;
declare function decode(html: string): string;
}
declare module 'source-map' {

View File

@ -61,7 +61,6 @@
"codecov.io": "^0.1.6",
"cross-spawn": "^4.0.0",
"de-indent": "^1.0.2",
"entities": "^1.1.1",
"es6-promise": "^3.2.1",
"eslint": "^3.4.0",
"eslint-config-vue": "^1.1.0",
@ -69,6 +68,7 @@
"eslint-plugin-flowtype": "^2.16.0",
"eslint-plugin-html": "^1.5.2",
"flow-bin": "^0.32.0",
"he": "^1.1.0",
"http-server": "^0.9.0",
"jasmine": "2.4.x",
"jasmine-core": "2.4.x",

View File

@ -18,7 +18,7 @@
"url": "https://github.com/vuejs/vue/issues"
},
"dependencies": {
"entities": "^1.1.1",
"he": "^1.1.0",
"de-indent": "^1.0.2"
},
"homepage": "https://github.com/vuejs/vue#readme"

View File

@ -18,7 +18,7 @@
},
"homepage": "https://github.com/vuejs/vue#readme",
"dependencies": {
"de-indent": "^1.0.2",
"entities": "^1.1.1"
"he": "^1.1.0",
"de-indent": "^1.0.2"
}
}

View File

@ -2,7 +2,7 @@
const decoder = document.createElement('div')
export function decodeHTML (html: string): string {
export function decode (html: string): string {
decoder.innerHTML = html
return decoder.textContent
}

View File

@ -54,21 +54,21 @@ const nlRE = /
/g
const ampRE = /&/g
const quoteRE = /"/g
function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) {
if (shouldDecodeTags) {
value = value.replace(ltRE, '<').replace(gtRE, '>')
}
function decodeAttr (value, shouldDecodeNewlines) {
if (shouldDecodeNewlines) {
value = value.replace(nlRE, '\n')
}
return value.replace(ampRE, '&').replace(quoteRE, '"')
return value
.replace(ltRE, '<')
.replace(gtRE, '>')
.replace(ampRE, '&')
.replace(quoteRE, '"')
}
export function parseHTML (html, options) {
const stack = []
const expectHTML = options.expectHTML
const isUnaryTag = options.isUnaryTag || no
const isFromDOM = options.isFromDOM
let index = 0
let last, lastTag
while (html) {
@ -218,11 +218,10 @@ export function parseHTML (html, options) {
const value = args[3] || args[4] || args[5] || ''
attrs[i] = {
name: args[1],
value: isFromDOM ? decodeAttr(
value: decodeAttr(
value,
options.shouldDecodeTags,
options.shouldDecodeNewlines
) : value
)
}
}

View File

@ -1,6 +1,6 @@
/* @flow */
import { decodeHTML } from 'entities'
import { decode } from 'he'
import { parseHTML } from './html-parser'
import { parseText } from './text-parser'
import { cached, no, camelize } from 'shared/util'
@ -24,7 +24,7 @@ const argRE = /:(.*)$/
const modifierRE = /\.[^\.]+/g
const specialNewlineRE = /\u2028|\u2029/g
const decodeHTMLCached = cached(decodeHTML)
const decodeHTMLCached = cached(decode)
// configurable state
let warn
@ -61,8 +61,6 @@ export function parse (
parseHTML(template, {
expectHTML: options.expectHTML,
isUnaryTag: options.isUnaryTag,
isFromDOM: options.isFromDOM,
shouldDecodeTags: options.shouldDecodeTags,
shouldDecodeNewlines: options.shouldDecodeNewlines,
start (tag, attrs, unary) {
// check namespace.

View File

@ -3,7 +3,7 @@
import Vue from './web-runtime'
import { warn, cached } from 'core/util/index'
import { query } from 'web/util/index'
import { shouldDecodeTags, shouldDecodeNewlines } from 'web/util/compat'
import { shouldDecodeNewlines } from 'web/util/compat'
import { compileToFunctions } from 'web/compiler/index'
const idToTemplate = cached(id => {
@ -30,15 +30,12 @@ Vue.prototype.$mount = function (
// resolve template/el and convert to render function
if (!options.render) {
let template = options.template
let isFromDOM = false
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
isFromDOM = true
template = idToTemplate(template)
}
} else if (template.nodeType) {
isFromDOM = true
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
@ -47,14 +44,11 @@ Vue.prototype.$mount = function (
return this
}
} else if (el) {
isFromDOM = true
template = getOuterHTML(el)
}
if (template) {
const { render, staticRenderFns } = compileToFunctions(template, {
warn,
isFromDOM,
shouldDecodeTags,
shouldDecodeNewlines,
delimiters: options.delimiters
}, this)

View File

@ -9,13 +9,6 @@ function shouldDecode (content: string, encoded: string): boolean {
return div.innerHTML.indexOf(encoded) > 0
}
// According to
// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value
// when serializing innerHTML, <, >, ", & should be encoded as entities.
// However, only some browsers, e.g. PhantomJS, encodes < and >.
// this causes problems with the in-browser parser.
export const shouldDecodeTags = inBrowser ? shouldDecode('>', '&gt;') : false
// #3663
// IE encodes newlines inside attribute values while other browsers don't
export const shouldDecodeNewlines = inBrowser ? shouldDecode('\n', '&#10;') : false

View File

@ -1,6 +1,6 @@
/* @flow */
import { encodeHTML } from 'entities'
import { escape } from 'he'
import { compileToFunctions } from 'web/compiler/index'
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
@ -112,7 +112,7 @@ export function createRenderFunction (
} else if (node.isComment) {
write(`<!--${node.text}-->`, next)
} else {
write(node.raw ? node.text : encodeHTML(String(node.text)), next)
write(node.raw ? node.text : escape(String(node.text)), next)
}
}
}

View File

@ -37,7 +37,7 @@ describe('SSR: bundle renderer', () => {
const context = { url: '/test' }
renderer.renderToString(context, (err, res) => {
expect(err).toBeNull()
expect(res).toBe('<div server-rendered="true">&sol;test</div>')
expect(res).toBe('<div server-rendered="true">/test</div>')
expect(context.msg).toBe('hello')
done()
})
@ -53,7 +53,7 @@ describe('SSR: bundle renderer', () => {
res += chunk.toString()
})
stream.on('end', () => {
expect(res).toBe('<div server-rendered="true">&sol;test</div>')
expect(res).toBe('<div server-rendered="true">/test</div>')
expect(context.msg).toBe('hello')
done()
})
@ -99,7 +99,7 @@ describe('SSR: bundle renderer', () => {
}
}
createRenderer('cache.js', renderer => {
const expected = '<div server-rendered="true">&sol;test</div>'
const expected = '<div server-rendered="true">/test</div>'
const key = 'app::1'
renderer.renderToString((err, res) => {
expect(err).toBeNull()
@ -142,7 +142,7 @@ describe('SSR: bundle renderer', () => {
}
}
createRenderer('cache.js', renderer => {
const expected = '<div server-rendered="true">&sol;test</div>'
const expected = '<div server-rendered="true">/test</div>'
const key = 'app::1'
renderer.renderToString((err, res) => {
expect(err).toBeNull()

View File

@ -94,7 +94,7 @@ describe('SSR: renderToString', () => {
bar: '<span>rendering</span>'
}
}, result => {
expect(result).toContain('<div server-rendered="true">server side &lt;span&gt;rendering&lt;&sol;span&gt;</div>')
expect(result).toContain('<div server-rendered="true">server side &lt;span&gt;rendering&lt;/span&gt;</div>')
done()
})
})
@ -118,7 +118,7 @@ describe('SSR: renderToString', () => {
text: '<span>foo</span>'
}
}, result => {
expect(result).toContain('<div server-rendered="true">&lt;span&gt;foo&lt;&sol;span&gt;</div>')
expect(result).toContain('<div server-rendered="true">&lt;span&gt;foo&lt;/span&gt;</div>')
done()
})
})