Skip to content

Commit

Permalink
feat(compiler): Allow BigInt usage in templates (issue vuejs#11126)
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowings-zy committed Feb 27, 2020
1 parent 6390f70 commit a22d5a3
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 4 deletions.
3 changes: 2 additions & 1 deletion flow/component.js
Expand Up @@ -74,7 +74,8 @@ declare interface Component {
// _virtualComponents?: { [key: string]: Component };

// private methods

_bigInt: Function; // BigInt support

// lifecycle
_init: Function;
_mount: (el?: Element | void, hydrating?: boolean) => Component;
Expand Down
20 changes: 20 additions & 0 deletions src/compiler/parser/bigint-parser.js
@@ -0,0 +1,20 @@
/* @flow */

/**
* turn "1000n" into "BigInt(1000)"
* and then turn "BigInt(1000)" into "_bigInt(1000)"
*
* by the way, if we meet variable like "l18n"
* we will change "l18n" to "l18@"
* after we finish parse bigint
* we will change "l18@" back to "l18n"
* @param {*} exp
*/
export function parseBigint(exp: string): string {
let expression = exp
.replace(/([a-zA-Z_$]+[0-9]+)n/g, '$1@')
.replace(/([0-9]+)n/g, 'BigInt($1)')
.replace(/([a-zA-Z_$]+[0-9]+)@/g, '$1n')
.replace(/BigInt\(/g, '_bigInt(')
return expression
}
7 changes: 5 additions & 2 deletions src/compiler/parser/text-parser.js
Expand Up @@ -2,6 +2,7 @@

import { cached } from 'shared/util'
import { parseFilters } from './filter-parser'
import { parseBigint } from './bigint-parser'

const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g
const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g
Expand Down Expand Up @@ -36,8 +37,10 @@ export function parseText (
rawTokens.push(tokenValue = text.slice(lastIndex, index))
tokens.push(JSON.stringify(tokenValue))
}
// tag token
const exp = parseFilters(match[1].trim())
// tag token and parse BigInt
let exp = parseFilters(match[1].trim())
exp = parseBigint(exp)

tokens.push(`_s(${exp})`)
rawTokens.push({ '@binding': exp })
lastIndex = index + match[0].length
Expand Down
22 changes: 22 additions & 0 deletions src/core/instance/render-helpers/bigint-helper.js
@@ -0,0 +1,22 @@
/* @flow */
import { warn } from 'core/util/index'
/**
* get BigInt function
* if the browser support window.BigInt, we will use it
* if not, we can customize BigInt() for vue
*/
export function getBigintFunc (): Function {
if (typeof window !== 'undefined' && typeof window.BigInt === 'function') {
return window.BigInt
} else if (typeof global !== 'undefined' && typeof global.BigInt === 'function') {
return global.BigInt
} else {
warn(
'BigInt is not support!'
)
// customize our own BigInt() function
return function (arg) {
return arg
}
}
}
4 changes: 3 additions & 1 deletion src/core/instance/render.js
Expand Up @@ -11,6 +11,7 @@ import {
import { createElement } from '../vdom/create-element'
import { installRenderHelpers } from './render-helpers/index'
import { resolveSlots } from './render-helpers/resolve-slots'
import { getBigintFunc } from './render-helpers/bigint-helper'
import { normalizeScopedSlots } from '../vdom/helpers/normalize-scoped-slots'
import VNode, { createEmptyVNode } from '../vdom/vnode'

Expand All @@ -32,7 +33,8 @@ export function initRender (vm: Component) {
// normalization is always applied for the public version, used in
// user-written render functions.
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

// load BigInt function on vm instance
vm._bigInt = getBigintFunc()
// $attrs & $listeners are exposed for easier HOC creation.
// they need to be reactive so that HOCs using them are always updated
const parentData = parentVnode && parentVnode.data
Expand Down
7 changes: 7 additions & 0 deletions test/unit/features/filter/filter.spec.js
Expand Up @@ -194,4 +194,11 @@ describe('Filters', () => {
it('support template string', () => {
expect(parseFilters('`a | ${b}c` | d')).toBe('_f("d")(`a | ${b}c`)')
})

it('bigint support', () => {
const vm = new Vue({
template: `<div>{{ BigInt(BigInt(10000000)) + BigInt(2000000000n) * 3000000n }}</div>`
}).$mount()
expect(vm.$el.textContent).toBe('6000000010000000')
})
})

0 comments on commit a22d5a3

Please sign in to comment.