user model added; message model changed; tag model added

This commit is contained in:
mandutzse68104 committed 2019-06-04 14:50:37 +02:00
1 parent d27216c8a8
commit f6a8c83586
5156 files changed
+62 -437424

No files matched your search

Generated Vendored
-21
View File
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
export default function bind (el: ASTElement, dir: ASTDirective) {
el.wrapData = (code: string) => {
return `_b(${code},'${el.tag}',${dir.value},${
dir.modifiers && dir.modifiers.prop ? 'true' : 'false'
}${
dir.modifiers && dir.modifiers.sync ? ',true' : ''
})`
}
}
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
import on from './on'
import bind from './bind'
import { noop } from 'shared/util'
export default {
on,
bind,
cloak: noop
}
-10
View File
@@ -1,10 +0,0 @@
/* @flow */
import { warn } from 'core/util/index'
export default function on (el: ASTElement, dir: ASTDirective) {
if (process.env.NODE_ENV !== 'production' && dir.modifiers) {
warn(`v-on without argument does not support modifiers.`)
}
el.wrapListeners = (code: string) => `_g(${code},${dir.value})`
}
-25
View File
@@ -1,25 +0,0 @@
/* @flow */
import { parse } from './parser/index'
import { optimize } from './optimizer'
import { generate } from './codegen/index'
import { createCompilerCreator } from './create-compiler'
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
export const createCompiler = createCompilerCreator(function baseCompile (
template: string,
options: CompilerOptions
): CompiledResult {
const ast = parse(template.trim(), options)
if (options.optimize !== false) {
optimize(ast, options)
}
const code = generate(ast, options)
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
let decoder
export default {
decode (html: string): string {
decoder = decoder || document.createElement('div')
decoder.innerHTML = html
return decoder.textContent
}
}
-97
View File
@@ -1,97 +0,0 @@
/* @flow */
const validDivisionCharRE = /[\w).+\-_$\]]/
export function parseFilters (exp: string): string {
let inSingle = false
let inDouble = false
let inTemplateString = false
let inRegex = false
let curly = 0
let square = 0
let paren = 0
let lastFilterIndex = 0
let c, prev, i, expression, filters
for (i = 0; i < exp.length; i++) {
prev = c
c = exp.charCodeAt(i)
if (inSingle) {
if (c === 0x27 && prev !== 0x5C) inSingle = false
} else if (inDouble) {
if (c === 0x22 && prev !== 0x5C) inDouble = false
} else if (inTemplateString) {
if (c === 0x60 && prev !== 0x5C) inTemplateString = false
} else if (inRegex) {
if (c === 0x2f && prev !== 0x5C) inRegex = false
} else if (
c === 0x7C && // pipe
exp.charCodeAt(i + 1) !== 0x7C &&
exp.charCodeAt(i - 1) !== 0x7C &&
!curly && !square && !paren
) {
if (expression === undefined) {
// first filter, end of expression
lastFilterIndex = i + 1
expression = exp.slice(0, i).trim()
} else {
pushFilter()
}
} else {
switch (c) {
case 0x22: inDouble = true; break // "
case 0x27: inSingle = true; break // '
case 0x60: inTemplateString = true; break // `
case 0x28: paren++; break // (
case 0x29: paren--; break // )
case 0x5B: square++; break // [
case 0x5D: square--; break // ]
case 0x7B: curly++; break // {
case 0x7D: curly--; break // }
}
if (c === 0x2f) { // /
let j = i - 1
let p
// find first non-whitespace prev char
for (; j >= 0; j--) {
p = exp.charAt(j)
if (p !== ' ') break
}
if (!p || !validDivisionCharRE.test(p)) {
inRegex = true
}
}
}
}
if (expression === undefined) {
expression = exp.slice(0, i).trim()
} else if (lastFilterIndex !== 0) {
pushFilter()
}
function pushFilter () {
(filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim())
lastFilterIndex = i + 1
}
if (filters) {
for (i = 0; i < filters.length; i++) {
expression = wrapFilter(expression, filters[i])
}
}
return expression
}
function wrapFilter (exp: string, filter: string): string {
const i = filter.indexOf('(')
if (i < 0) {
// _f: resolveFilter
return `_f("${filter}")(${exp})`
} else {
const name = filter.slice(0, i)
const args = filter.slice(i + 1)
return `_f("${name}")(${exp}${args !== ')' ? ',' + args : args}`
}
}
-5
View File
@@ -1,5 +0,0 @@
import KeepAlive from './keep-alive'
export default {
KeepAlive
}
-124
View File
@@ -1,124 +0,0 @@
/* @flow */
import { isRegExp, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'
type VNodeCache = { [key: string]: ?VNode };
function getComponentName (opts: ?VNodeComponentOptions): ?string {
return opts && (opts.Ctor.options.name || opts.tag)
}
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
} else if (isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
}
function pruneCache (keepAliveInstance: any, filter: Function) {
const { cache, keys, _vnode } = keepAliveInstance
for (const key in cache) {
const cachedNode: ?VNode = cache[key]
if (cachedNode) {
const name: ?string = getComponentName(cachedNode.componentOptions)
if (name && !filter(name)) {
pruneCacheEntry(cache, key, keys, _vnode)
}
}
}
}
function pruneCacheEntry (
cache: VNodeCache,
key: string,
keys: Array<string>,
current?: VNode
) {
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
cached.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
}
const patternTypes: Array<Function> = [String, RegExp, Array]
export default {
name: 'keep-alive',
abstract: true,
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},
created () {
this.cache = Object.create(null)
this.keys = []
},
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted () {
this.$watch('include', val => {
pruneCache(this, name => matches(val, name))
})
this.$watch('exclude', val => {
pruneCache(this, name => !matches(val, name))
})
},
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
-34
View File
@@ -1,34 +0,0 @@
/* @flow */
import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'
export function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
*/
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
-95
View File
@@ -1,95 +0,0 @@
/* @flow */
import { ASSET_TYPES } from 'shared/constants'
import { defineComputed, proxy } from '../instance/state'
import { extend, mergeOptions, validateComponentName } from '../util/index'
export function initExtend (Vue: GlobalAPI) {
/**
* Each instance constructor, including Vue, has a unique
* cid. This enables us to create wrapped "child
* constructors" for prototypal inheritance and cache them.
*/
Vue.cid = 0
let cid = 1
/**
* Class inheritance
*/
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
cachedCtors[SuperId] = Sub
return Sub
}
}
function initProps (Comp) {
const props = Comp.options.props
for (const key in props) {
proxy(Comp.prototype, `_props`, key)
}
}
function initComputed (Comp) {
const computed = Comp.options.computed
for (const key in computed) {
defineComputed(Comp.prototype, key, computed[key])
}
}
-10
View File
@@ -1,10 +0,0 @@
/* @flow */
import { mergeOptions } from '../util/index'
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin)
return this
}
}
-23
View File
@@ -1,23 +0,0 @@
/* @flow */
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
-26
View File
@@ -1,26 +0,0 @@
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
Vue.version = '__VERSION__'
export default Vue
-23
View File
@@ -1,23 +0,0 @@
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
@@ -1,22 +0,0 @@
/* @flow */
import { warn, extend, isPlainObject } from 'core/util/index'
export function bindObjectListeners (data: any, value: any): VNodeData {
if (value) {
if (!isPlainObject(value)) {
process.env.NODE_ENV !== 'production' && warn(
'v-on without argument expects an Object value',
this
)
} else {
const on = data.on = data.on ? extend({}, data.on) : {}
for (const key in value) {
const existing = on[key]
const ours = value[key]
on[key] = existing ? [].concat(existing, ours) : ours
}
}
}
return data
}
-34
View File
@@ -1,34 +0,0 @@
/* @flow */
import config from 'core/config'
import { hyphenate } from 'shared/util'
function isKeyNotMatch<T> (expect: T | Array<T>, actual: T): boolean {
if (Array.isArray(expect)) {
return expect.indexOf(actual) === -1
} else {
return expect !== actual
}
}
/**
* Runtime helper for checking keyCodes from config.
* exposed as Vue.prototype._k
* passing in eventKeyName as last argument separately for backwards compat
*/
export function checkKeyCodes (
eventKeyCode: number,
key: string,
builtInKeyCode?: number | Array<number>,
eventKeyName?: string,
builtInKeyName?: string | Array<string>
): ?boolean {
const mappedKeyCode = config.keyCodes[key] || builtInKeyCode
if (builtInKeyName && eventKeyName && !config.keyCodes[key]) {
return isKeyNotMatch(builtInKeyName, eventKeyName)
} else if (mappedKeyCode) {
return isKeyNotMatch(mappedKeyCode, eventKeyCode)
} else if (eventKeyName) {
return hyphenate(eventKeyName) !== key
}
}
-60
View File
@@ -1,60 +0,0 @@
/* @flow */
/**
* Runtime helper for rendering static trees.
*/
export function renderStatic (
index: number,
isInFor: boolean
): VNode | Array<VNode> {
const cached = this._staticTrees || (this._staticTrees = [])
let tree = cached[index]
// if has already-rendered static tree and not inside v-for,
// we can reuse the same tree.
if (tree && !isInFor) {
return tree
}
// otherwise, render a fresh tree.
tree = cached[index] = this.$options.staticRenderFns[index].call(
this._renderProxy,
null,
this // for render fns generated for functional component templates
)
markStatic(tree, `__static__${index}`, false)
return tree
}
/**
* Runtime helper for v-once.
* Effectively it means marking the node as static with a unique key.
*/
export function markOnce (
tree: VNode | Array<VNode>,
index: number,
key: string
) {
markStatic(tree, `__once__${index}${key ? `_${key}` : ``}`, true)
return tree
}
function markStatic (
tree: VNode | Array<VNode>,
key: string,
isOnce: boolean
) {
if (Array.isArray(tree)) {
for (let i = 0; i < tree.length; i++) {
if (tree[i] && typeof tree[i] !== 'string') {
markStaticNode(tree[i], `${key}_${i}`, isOnce)
}
}
} else {
markStaticNode(tree, key, isOnce)
}
}
function markStaticNode (node, key, isOnce) {
node.isStatic = true
node.key = key
node.isOnce = isOnce
}
-10
View File
@@ -1,10 +0,0 @@
/* @flow */
import { identity, resolveAsset } from 'core/util/index'
/**
* Runtime helper for resolving filters
*/
export function resolveFilter (id: string): Function {
return resolveAsset(this.$options, 'filters', id, true) || identity
}
-45
View File
@@ -1,45 +0,0 @@
/*
* not type checking this file because flow doesn't play well with
* dynamically accessing methods on Array prototype
*/
import { def } from '../util/index'
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})
-40
View File
@@ -1,40 +0,0 @@
/* @flow */
import { _Set as Set, isObject } from '../util/index'
import type { SimpleSet } from '../util/index'
import VNode from '../vdom/vnode'
const seenObjects = new Set()
/**
* Recursively traverse an object to evoke all converted
* getters, so that every nested property inside the object
* is collected as a "deep" dependency.
*/
export function traverse (val: any) {
_traverse(val, seenObjects)
seenObjects.clear()
}
function _traverse (val: any, seen: SimpleSet) {
let i, keys
const isA = Array.isArray(val)
if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {
return
}
if (val.__ob__) {
const depId = val.__ob__.dep.id
if (seen.has(depId)) {
return
}
seen.add(depId)
}
if (isA) {
i = val.length
while (i--) _traverse(val[i], seen)
} else {
keys = Object.keys(val)
i = keys.length
while (i--) _traverse(val[keys[i]], seen)
}
}
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
export * from 'shared/util'
export * from './lang'
export * from './env'
export * from './options'
export * from './debug'
export * from './props'
export * from './error'
export * from './next-tick'
export { defineReactive } from '../observer/index'
-75
View File
@@ -1,75 +0,0 @@
/* @flow */
import {
tip,
hasOwn,
isDef,
isUndef,
hyphenate,
formatComponentName
} from 'core/util/index'
export function extractPropsFromVNodeData (
data: VNodeData,
Ctor: Class<Component>,
tag?: string
): ?Object {
// we are only extracting raw values here.
// validation and default values are handled in the child
// component itself.
const propOptions = Ctor.options.props
if (isUndef(propOptions)) {
return
}
const res = {}
const { attrs, props } = data
if (isDef(attrs) || isDef(props)) {
for (const key in propOptions) {
const altKey = hyphenate(key)
if (process.env.NODE_ENV !== 'production') {
const keyInLowerCase = key.toLowerCase()
if (
key !== keyInLowerCase &&
attrs && hasOwn(attrs, keyInLowerCase)
) {
tip(
`Prop "${keyInLowerCase}" is passed to component ` +
`${formatComponentName(tag || Ctor)}, but the declared prop name is` +
` "${key}". ` +
`Note that HTML attributes are case-insensitive and camelCased ` +
`props need to use their kebab-case equivalents when using in-DOM ` +
`templates. You should probably use "${altKey}" instead of "${key}".`
)
}
}
checkProp(res, props, key, altKey, true) ||
checkProp(res, attrs, key, altKey, false)
}
}
return res
}
function checkProp (
res: Object,
hash: ?Object,
key: string,
altKey: string,
preserve: boolean
): boolean {
if (isDef(hash)) {
if (hasOwn(hash, key)) {
res[key] = hash[key]
if (!preserve) {
delete hash[key]
}
return true
} else if (hasOwn(hash, altKey)) {
res[key] = hash[altKey]
if (!preserve) {
delete hash[altKey]
}
return true
}
}
return false
}
-15
View File
@@ -1,15 +0,0 @@
/* @flow */
import { isDef } from 'shared/util'
import { isAsyncPlaceholder } from './is-async-placeholder'
export function getFirstComponentChild (children: ?Array<VNode>): ?VNode {
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
const c = children[i]
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
return c
}
}
}
}
-9
View File
@@ -1,9 +0,0 @@
/* @flow */
export * from './merge-hook'
export * from './extract-props'
export * from './update-listeners'
export * from './normalize-children'
export * from './resolve-async-component'
export * from './get-first-component-child'
export * from './is-async-placeholder'
-5
View File
@@ -1,5 +0,0 @@
/* @flow */
export function isAsyncPlaceholder (node: VNode): boolean {
return node.isComment && node.asyncFactory
}
-38
View File
@@ -1,38 +0,0 @@
/* @flow */
import VNode from '../vnode'
import { createFnInvoker } from './update-listeners'
import { remove, isDef, isUndef, isTrue } from 'shared/util'
export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) {
if (def instanceof VNode) {
def = def.data.hook || (def.data.hook = {})
}
let invoker
const oldHook = def[hookKey]
function wrappedHook () {
hook.apply(this, arguments)
// important: remove merged hook to ensure it's called only once
// and prevent memory leak
remove(invoker.fns, wrappedHook)
}
if (isUndef(oldHook)) {
// no existing hook
invoker = createFnInvoker([wrappedHook])
} else {
/* istanbul ignore if */
if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
// already a merged invoker
invoker = oldHook
invoker.fns.push(wrappedHook)
} else {
// existing plain hook
invoker = createFnInvoker([oldHook, wrappedHook])
}
}
invoker.merged = true
def[hookKey] = invoker
}
-89
View File
@@ -1,89 +0,0 @@
/* @flow */
import VNode, { createTextVNode } from 'core/vdom/vnode'
import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'
// The template compiler attempts to minimize the need for normalization by
// statically analyzing the template at compile time.
//
// For plain HTML markup, normalization can be completely skipped because the
// generated render function is guaranteed to return Array<VNode>. There are
// two cases where extra normalization is needed:
// 1. When the children contains components - because a functional component
// may return an Array instead of a single root. In this case, just a simple
// normalization is needed - if any child is an Array, we flatten the whole
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
// because functional components already normalize their own children.
export function simpleNormalizeChildren (children: any) {
for (let i = 0; i < children.length; i++) {
if (Array.isArray(children[i])) {
return Array.prototype.concat.apply([], children)
}
}
return children
}
// 2. When the children contains constructs that always generated nested Arrays,
// e.g. <template>, <slot>, v-for, or when the children is provided by user
// with hand-written render functions / JSX. In such cases a full normalization
// is needed to cater to all possible types of children values.
export function normalizeChildren (children: any): ?Array<VNode> {
return isPrimitive(children)
? [createTextVNode(children)]
: Array.isArray(children)
? normalizeArrayChildren(children)
: undefined
}
function isTextNode (node): boolean {
return isDef(node) && isDef(node.text) && isFalse(node.isComment)
}
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
const res = []
let i, c, lastIndex, last
for (i = 0; i < children.length; i++) {
c = children[i]
if (isUndef(c) || typeof c === 'boolean') continue
lastIndex = res.length - 1
last = res[lastIndex]
// nested
if (Array.isArray(c)) {
if (c.length > 0) {
c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
// merge adjacent text nodes
if (isTextNode(c[0]) && isTextNode(last)) {
res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
c.shift()
}
res.push.apply(res, c)
}
} else if (isPrimitive(c)) {
if (isTextNode(last)) {
// merge adjacent text nodes
// this is necessary for SSR hydration because text nodes are
// essentially merged when rendered to HTML strings
res[lastIndex] = createTextVNode(last.text + c)
} else if (c !== '') {
// convert primitive to vnode
res.push(createTextVNode(c))
}
} else {
if (isTextNode(c) && isTextNode(last)) {
// merge adjacent text nodes
res[lastIndex] = createTextVNode(last.text + c.text)
} else {
// default key for nested array children (likely generated by v-for)
if (isTrue(children._isVList) &&
isDef(c.tag) &&
isUndef(c.key) &&
isDef(nestedIndex)) {
c.key = `__vlist${nestedIndex}_${i}__`
}
res.push(c)
}
}
}
return res
}
-7
View File
@@ -1,7 +0,0 @@
import directives from './directives'
import ref from './ref'
export default [
ref,
directives
]
-45
View File
@@ -1,45 +0,0 @@
/* @flow */
import { remove, isDef } from 'shared/util'
export default {
create (_: any, vnode: VNodeWithData) {
registerRef(vnode)
},
update (oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (oldVnode.data.ref !== vnode.data.ref) {
registerRef(oldVnode, true)
registerRef(vnode)
}
},
destroy (vnode: VNodeWithData) {
registerRef(vnode, true)
}
}
export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) {
const key = vnode.data.ref
if (!isDef(key)) return
const vm = vnode.context
const ref = vnode.componentInstance || vnode.elm
const refs = vm.$refs
if (isRemoval) {
if (Array.isArray(refs[key])) {
remove(refs[key], ref)
} else if (refs[key] === ref) {
refs[key] = undefined
}
} else {
if (vnode.data.refInFor) {
if (!Array.isArray(refs[key])) {
refs[key] = [ref]
} else if (refs[key].indexOf(ref) < 0) {
// $flow-disable-line
refs[key].push(ref)
}
} else {
refs[key] = ref
}
}
}
BIN
View File
Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
import model from './model'
import text from './text'
import html from './html'
export default {
model,
text,
html
}
-8
View File
@@ -1,8 +0,0 @@
/* @flow */
import { baseOptions } from './options'
import { createCompiler } from 'compiler/index'
const { compile, compileToFunctions } = createCompiler(baseOptions)
export { compile, compileToFunctions }
-9
View File
@@ -1,9 +0,0 @@
import klass from './class'
import style from './style'
import model from './model'
export default [
klass,
style,
model
]
-94
View File
@@ -1,94 +0,0 @@
/* @flow */
/**
* Expand input[v-model] with dyanmic type bindings into v-if-else chains
* Turn this:
* <input v-model="data[type]" :type="type">
* into this:
* <input v-if="type === 'checkbox'" type="checkbox" v-model="data[type]">
* <input v-else-if="type === 'radio'" type="radio" v-model="data[type]">
* <input v-else :type="type" v-model="data[type]">
*/
import {
addRawAttr,
getBindingAttr,
getAndRemoveAttr
} from 'compiler/helpers'
import {
processFor,
processElement,
addIfCondition,
createASTElement
} from 'compiler/parser/index'
function preTransformNode (el: ASTElement, options: CompilerOptions) {
if (el.tag === 'input') {
const map = el.attrsMap
if (!map['v-model']) {
return
}
let typeBinding
if (map[':type'] || map['v-bind:type']) {
typeBinding = getBindingAttr(el, 'type')
}
if (!map.type && !typeBinding && map['v-bind']) {
typeBinding = `(${map['v-bind']}).type`
}
if (typeBinding) {
const ifCondition = getAndRemoveAttr(el, 'v-if', true)
const ifConditionExtra = ifCondition ? `&&(${ifCondition})` : ``
const hasElse = getAndRemoveAttr(el, 'v-else', true) != null
const elseIfCondition = getAndRemoveAttr(el, 'v-else-if', true)
// 1. checkbox
const branch0 = cloneASTElement(el)
// process for on the main node
processFor(branch0)
addRawAttr(branch0, 'type', 'checkbox')
processElement(branch0, options)
branch0.processed = true // prevent it from double-processed
branch0.if = `(${typeBinding})==='checkbox'` + ifConditionExtra
addIfCondition(branch0, {
exp: branch0.if,
block: branch0
})
// 2. add radio else-if condition
const branch1 = cloneASTElement(el)
getAndRemoveAttr(branch1, 'v-for', true)
addRawAttr(branch1, 'type', 'radio')
processElement(branch1, options)
addIfCondition(branch0, {
exp: `(${typeBinding})==='radio'` + ifConditionExtra,
block: branch1
})
// 3. other
const branch2 = cloneASTElement(el)
getAndRemoveAttr(branch2, 'v-for', true)
addRawAttr(branch2, ':type', typeBinding)
processElement(branch2, options)
addIfCondition(branch0, {
exp: ifCondition,
block: branch2
})
if (hasElse) {
branch0.else = true
} else if (elseIfCondition) {
branch0.elseif = elseIfCondition
}
return branch0
}
}
}
function cloneASTElement (el) {
return createASTElement(el.tag, el.attrsList.slice(), el.parent)
}
export default {
preTransformNode
}
-26
View File
@@ -1,26 +0,0 @@
/* @flow */
import {
isPreTag,
mustUseProp,
isReservedTag,
getTagNamespace
} from '../util/index'
import modules from './modules/index'
import directives from './directives/index'
import { genStaticKeys } from 'shared/util'
import { isUnaryTag, canBeLeftOpenTag } from './util'
export const baseOptions: CompilerOptions = {
expectHTML: true,
modules,
directives,
isPreTag,
isUnaryTag,
mustUseProp,
canBeLeftOpenTag,
isReservedTag,
getTagNamespace,
staticKeys: genStaticKeys(modules)
}
-24
View File
@@ -1,24 +0,0 @@
/* @flow */
import { makeMap } from 'shared/util'
export const isUnaryTag = makeMap(
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr'
)
// Elements that you can, intentionally, leave open
// (and which close themselves)
export const canBeLeftOpenTag = makeMap(
'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
)
// HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
export const isNonPhrasingTag = makeMap(
'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
'title,tr,track'
)
-5
View File
@@ -1,5 +0,0 @@
/* @flow */
import Vue from './runtime/index'
export default Vue
-13
View File
@@ -1,13 +0,0 @@
/* @flow */
import modules from './server/modules/index'
import directives from './server/directives/index'
import { isUnaryTag, canBeLeftOpenTag } from './compiler/util'
import { createBasicRenderer } from 'server/create-basic-renderer'
export default createBasicRenderer({
modules,
directives,
isUnaryTag,
canBeLeftOpenTag
})
-27
View File
@@ -1,27 +0,0 @@
/* @flow */
process.env.VUE_ENV = 'server'
import { extend } from 'shared/util'
import modules from './server/modules/index'
import baseDirectives from './server/directives/index'
import { isUnaryTag, canBeLeftOpenTag } from './compiler/util'
import { createRenderer as _createRenderer } from 'server/create-renderer'
import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer'
export function createRenderer (options?: Object = {}): {
renderToString: Function,
renderToStream: Function
} {
return _createRenderer(extend(extend({}, options), {
isUnaryTag,
canBeLeftOpenTag,
modules,
// user can provide server-side implementations for custom directives
// when creating the renderer.
directives: extend(baseDirectives, options.directives)
}))
}
export const createBundleRenderer = createBundleRendererCreator(createRenderer)
-7
View File
@@ -1,7 +0,0 @@
import Transition from './transition'
import TransitionGroup from './transition-group'
export default {
Transition,
TransitionGroup
}
-7
View File
@@ -1,7 +0,0 @@
import model from './model'
import show from './show'
export default {
model,
show
}
-147
View File
@@ -1,147 +0,0 @@
/**
* Not type checking this file because flow doesn't like attaching
* properties to Elements.
*/
import { isTextInputType } from 'web/util/element'
import { looseEqual, looseIndexOf } from 'shared/util'
import { mergeVNodeHook } from 'core/vdom/helpers/index'
import { warn, isIE9, isIE, isEdge } from 'core/util/index'
/* istanbul ignore if */
if (isIE9) {
// http://www.matts411.com/post/internet-explorer-9-oninput/
document.addEventListener('selectionchange', () => {
const el = document.activeElement
if (el && el.vmodel) {
trigger(el, 'input')
}
})
}
const directive = {
inserted (el, binding, vnode, oldVnode) {
if (vnode.tag === 'select') {
// #6903
if (oldVnode.elm && !oldVnode.elm._vOptions) {
mergeVNodeHook(vnode, 'postpatch', () => {
directive.componentUpdated(el, binding, vnode)
})
} else {
setSelected(el, binding, vnode.context)
}
el._vOptions = [].map.call(el.options, getValue)
} else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
el._vModifiers = binding.modifiers
if (!binding.modifiers.lazy) {
el.addEventListener('compositionstart', onCompositionStart)
el.addEventListener('compositionend', onCompositionEnd)
// Safari < 10.2 & UIWebView doesn't fire compositionend when
// switching focus before confirming composition choice
// this also fixes the issue where some browsers e.g. iOS Chrome
// fires "change" instead of "input" on autocomplete.
el.addEventListener('change', onCompositionEnd)
/* istanbul ignore if */
if (isIE9) {
el.vmodel = true
}
}
}
},
componentUpdated (el, binding, vnode) {
if (vnode.tag === 'select') {
setSelected(el, binding, vnode.context)
// in case the options rendered by v-for have changed,
// it's possible that the value is out-of-sync with the rendered options.
// detect such cases and filter out values that no longer has a matching
// option in the DOM.
const prevOptions = el._vOptions
const curOptions = el._vOptions = [].map.call(el.options, getValue)
if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) {
// trigger change event if
// no matching option found for at least one value
const needReset = el.multiple
? binding.value.some(v => hasNoMatchingOption(v, curOptions))
: binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions)
if (needReset) {
trigger(el, 'change')
}
}
}
}
}
function setSelected (el, binding, vm) {
actuallySetSelected(el, binding, vm)
/* istanbul ignore if */
if (isIE || isEdge) {
setTimeout(() => {
actuallySetSelected(el, binding, vm)
}, 0)
}
}
function actuallySetSelected (el, binding, vm) {
const value = binding.value
const isMultiple = el.multiple
if (isMultiple && !Array.isArray(value)) {
process.env.NODE_ENV !== 'production' && warn(
`<select multiple v-model="${binding.expression}"> ` +
`expects an Array value for its binding, but got ${
Object.prototype.toString.call(value).slice(8, -1)
}`,
vm
)
return
}
let selected, option
for (let i = 0, l = el.options.length; i < l; i++) {
option = el.options[i]
if (isMultiple) {
selected = looseIndexOf(value, getValue(option)) > -1
if (option.selected !== selected) {
option.selected = selected
}
} else {
if (looseEqual(getValue(option), value)) {
if (el.selectedIndex !== i) {
el.selectedIndex = i
}
return
}
}
}
if (!isMultiple) {
el.selectedIndex = -1
}
}
function hasNoMatchingOption (value, options) {
return options.every(o => !looseEqual(o, value))
}
function getValue (option) {
return '_value' in option
? option._value
: option.value
}
function onCompositionStart (e) {
e.target.composing = true
}
function onCompositionEnd (e) {
// prevent triggering an input event for no reason
if (!e.target.composing) return
e.target.composing = false
trigger(e.target, 'input')
}
function trigger (el, type) {
const e = document.createEvent('HTMLEvents')
e.initEvent(type, true, true)
el.dispatchEvent(e)
}
export default directive
-60
View File
@@ -1,60 +0,0 @@
/* @flow */
import { enter, leave } from '../modules/transition'
// recursively search for possible transition defined inside the component root
function locateNode (vnode: VNode): VNodeWithData {
return vnode.componentInstance && (!vnode.data || !vnode.data.transition)
? locateNode(vnode.componentInstance._vnode)
: vnode
}
export default {
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
vnode = locateNode(vnode)
const transition = vnode.data && vnode.data.transition
const originalDisplay = el.__vOriginalDisplay =
el.style.display === 'none' ? '' : el.style.display
if (value && transition) {
vnode.data.show = true
enter(vnode, () => {
el.style.display = originalDisplay
})
} else {
el.style.display = value ? originalDisplay : 'none'
}
},
update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) {
/* istanbul ignore if */
if (!value === !oldValue) return
vnode = locateNode(vnode)
const transition = vnode.data && vnode.data.transition
if (transition) {
vnode.data.show = true
if (value) {
enter(vnode, () => {
el.style.display = el.__vOriginalDisplay
})
} else {
leave(vnode, () => {
el.style.display = 'none'
})
}
} else {
el.style.display = value ? el.__vOriginalDisplay : 'none'
}
},
unbind (
el: any,
binding: VNodeDirective,
vnode: VNodeWithData,
oldVnode: VNodeWithData,
isDestroy: boolean
) {
if (!isDestroy) {
el.style.display = el.__vOriginalDisplay
}
}
}
-48
View File
@@ -1,48 +0,0 @@
/* @flow */
import {
isDef,
isUndef
} from 'shared/util'
import {
concat,
stringifyClass,
genClassForVnode
} from 'web/util/index'
function updateClass (oldVnode: any, vnode: any) {
const el = vnode.elm
const data: VNodeData = vnode.data
const oldData: VNodeData = oldVnode.data
if (
isUndef(data.staticClass) &&
isUndef(data.class) && (
isUndef(oldData) || (
isUndef(oldData.staticClass) &&
isUndef(oldData.class)
)
)
) {
return
}
let cls = genClassForVnode(vnode)
// handle transition classes
const transitionClass = el._transitionClasses
if (isDef(transitionClass)) {
cls = concat(cls, stringifyClass(transitionClass))
}
// set the class
if (cls !== el._prevClass) {
el.setAttribute('class', cls)
el._prevClass = cls
}
}
export default {
create: updateClass,
update: updateClass
}
-15
View File
@@ -1,15 +0,0 @@
import attrs from './attrs'
import klass from './class'
import events from './events'
import domProps from './dom-props'
import style from './style'
import transition from './transition'
export default [
attrs,
klass,
events,
domProps,
style,
transition
]
-59
View File
@@ -1,59 +0,0 @@
/* @flow */
import { namespaceMap } from 'web/util/index'
export function createElement (tagName: string, vnode: VNode): Element {
const elm = document.createElement(tagName)
if (tagName !== 'select') {
return elm
}
// false or null will remove the attribute but undefined will not
if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {
elm.setAttribute('multiple', 'multiple')
}
return elm
}
export function createElementNS (namespace: string, tagName: string): Element {
return document.createElementNS(namespaceMap[namespace], tagName)
}
export function createTextNode (text: string): Text {
return document.createTextNode(text)
}
export function createComment (text: string): Comment {
return document.createComment(text)
}
export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) {
parentNode.insertBefore(newNode, referenceNode)
}
export function removeChild (node: Node, child: Node) {
node.removeChild(child)
}
export function appendChild (node: Node, child: Node) {
node.appendChild(child)
}
export function parentNode (node: Node): ?Node {
return node.parentNode
}
export function nextSibling (node: Node): ?Node {
return node.nextSibling
}
export function tagName (node: Element): string {
return node.tagName
}
export function setTextContent (node: Node, text: string) {
node.textContent = text
}
export function setStyleScope (node: Element, scopeId: string) {
node.setAttribute(scopeId, '')
}
-12
View File
@@ -1,12 +0,0 @@
/* @flow */
import * as nodeOps from 'web/runtime/node-ops'
import { createPatchFunction } from 'core/vdom/patch'
import baseModules from 'core/vdom/modules/index'
import platformModules from 'web/runtime/modules/index'
// the directive module should be applied last, after all
// built-in modules have been applied.
const modules = platformModules.concat(baseModules)
export const patch: Function = createPatchFunction({ nodeOps, modules })
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
import { baseOptions } from '../compiler/options'
import { createCompiler } from 'server/optimizing-compiler/index'
const { compile, compileToFunctions } = createCompiler(baseOptions)
export {
compile as ssrCompile,
compileToFunctions as ssrCompileToFunctions
}
-7
View File
@@ -1,7 +0,0 @@
import show from './show'
import model from './model'
export default {
show,
model
}
-44
View File
@@ -1,44 +0,0 @@
/* @flow */
import { looseEqual, looseIndexOf } from 'shared/util'
// this is only applied for <select v-model> because it is the only edge case
// that must be done at runtime instead of compile time.
export default function model (node: VNodeWithData, dir: VNodeDirective) {
if (!node.children) return
const value = dir.value
const isMultiple = node.data.attrs && node.data.attrs.multiple
for (let i = 0, l = node.children.length; i < l; i++) {
const option = node.children[i]
if (option.tag === 'option') {
if (isMultiple) {
const selected =
Array.isArray(value) &&
(looseIndexOf(value, getValue(option)) > -1)
if (selected) {
setSelected(option)
}
} else {
if (looseEqual(value, getValue(option))) {
setSelected(option)
return
}
}
}
}
}
function getValue (option) {
const data = option.data || {}
return (
(data.attrs && data.attrs.value) ||
(data.domProps && data.domProps.value) ||
(option.children && option.children[0] && option.children[0].text)
)
}
function setSelected (option) {
const data = option.data || (option.data = {})
const attrs = data.attrs || (data.attrs = {})
attrs.selected = ''
}
-12
View File
@@ -1,12 +0,0 @@
/* @flow */
export default function show (node: VNodeWithData, dir: VNodeDirective) {
if (!dir.value) {
const style: any = node.data.style || (node.data.style = {})
if (Array.isArray(style)) {
style.push({ display: 'none' })
} else {
style.display = 'none'
}
}
}
-11
View File
@@ -1,11 +0,0 @@
/* @flow */
import { escape } from '../util'
import { genClassForVnode } from 'web/util/index'
export default function renderClass (node: VNodeWithData): ?string {
const classList = genClassForVnode(node)
if (classList !== '') {
return ` class="${escape(classList)}"`
}
}
-50
View File
@@ -1,50 +0,0 @@
/* @flow */
import VNode from 'core/vdom/vnode'
import { renderAttr } from './attrs'
import { isDef, isUndef, extend } from 'shared/util'
import { propsToAttrMap, isRenderableAttr } from '../util'
export default function renderDOMProps (node: VNodeWithData): string {
let props = node.data.domProps
let res = ''
let parent = node.parent
while (isDef(parent)) {
if (parent.data && parent.data.domProps) {
props = extend(extend({}, props), parent.data.domProps)
}
parent = parent.parent
}
if (isUndef(props)) {
return res
}
const attrs = node.data.attrs
for (const key in props) {
if (key === 'innerHTML') {
setText(node, props[key], true)
} else if (key === 'textContent') {
setText(node, props[key], false)
} else if (key === 'value' && node.tag === 'textarea') {
setText(node, props[key], false)
} else {
// $flow-disable-line (WTF?)
const attr = propsToAttrMap[key] || key.toLowerCase()
if (isRenderableAttr(attr) &&
// avoid rendering double-bound props/attrs twice
!(isDef(attrs) && isDef(attrs[attr]))
) {
res += renderAttr(attr, props[key])
}
}
}
return res
}
function setText (node, text, raw) {
const child = new VNode(undefined, undefined, undefined, text)
child.raw = raw
node.children = [child]
}
-11
View File
@@ -1,11 +0,0 @@
import attrs from './attrs'
import domProps from './dom-props'
import klass from './class'
import style from './style'
export default [
attrs,
domProps,
klass,
style
]
-85
View File
@@ -1,85 +0,0 @@
/* @flow */
import { isDef, isObject } from 'shared/util'
export function genClassForVnode (vnode: VNodeWithData): string {
let data = vnode.data
let parentNode = vnode
let childNode = vnode
while (isDef(childNode.componentInstance)) {
childNode = childNode.componentInstance._vnode
if (childNode && childNode.data) {
data = mergeClassData(childNode.data, data)
}
}
while (isDef(parentNode = parentNode.parent)) {
if (parentNode && parentNode.data) {
data = mergeClassData(data, parentNode.data)
}
}
return renderClass(data.staticClass, data.class)
}
function mergeClassData (child: VNodeData, parent: VNodeData): {
staticClass: string,
class: any
} {
return {
staticClass: concat(child.staticClass, parent.staticClass),
class: isDef(child.class)
? [child.class, parent.class]
: parent.class
}
}
export function renderClass (
staticClass: ?string,
dynamicClass: any
): string {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass))
}
/* istanbul ignore next */
return ''
}
export function concat (a: ?string, b: ?string): string {
return a ? b ? (a + ' ' + b) : a : (b || '')
}
export function stringifyClass (value: any): string {
if (Array.isArray(value)) {
return stringifyArray(value)
}
if (isObject(value)) {
return stringifyObject(value)
}
if (typeof value === 'string') {
return value
}
/* istanbul ignore next */
return ''
}
function stringifyArray (value: Array<any>): string {
let res = ''
let stringified
for (let i = 0, l = value.length; i < l; i++) {
if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {
if (res) res += ' '
res += stringified
}
}
return res
}
function stringifyObject (value: Object): string {
let res = ''
for (const key in value) {
if (value[key]) {
if (res) res += ' '
res += key
}
}
return res
}
-16
View File
@@ -1,16 +0,0 @@
/* @flow */
import { inBrowser } from 'core/util/index'
// check whether current browser encodes a char inside attribute values
let div
function getShouldDecode (href: boolean): boolean {
div = div || document.createElement('div')
div.innerHTML = href ? `<a href="\n"/>` : `<div a="\n"/>`
return div.innerHTML.indexOf('&#10;') > 0
}
// #3663: IE encodes newlines inside attribute values while other browsers don't
export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false
// #6828: chrome encodes content in a[href]
export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false
-77
View File
@@ -1,77 +0,0 @@
/* @flow */
import { inBrowser } from 'core/util/env'
import { makeMap } from 'shared/util'
export const namespaceMap = {
svg: 'http://www.w3.org/2000/svg',
math: 'http://www.w3.org/1998/Math/MathML'
}
export const isHTMLTag = makeMap(
'html,body,base,head,link,meta,style,title,' +
'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
'embed,object,param,source,canvas,script,noscript,del,ins,' +
'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
'output,progress,select,textarea,' +
'details,dialog,menu,menuitem,summary,' +
'content,element,shadow,template,blockquote,iframe,tfoot'
)
// this map is intentionally selective, only covering SVG elements that may
// contain child elements.
export const isSVG = makeMap(
'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
true
)
export const isPreTag = (tag: ?string): boolean => tag === 'pre'
export const isReservedTag = (tag: string): ?boolean => {
return isHTMLTag(tag) || isSVG(tag)
}
export function getTagNamespace (tag: string): ?string {
if (isSVG(tag)) {
return 'svg'
}
// basic support for MathML
// note it doesn't support other MathML elements being component roots
if (tag === 'math') {
return 'math'
}
}
const unknownElementCache = Object.create(null)
export function isUnknownElement (tag: string): boolean {
/* istanbul ignore if */
if (!inBrowser) {
return true
}
if (isReservedTag(tag)) {
return false
}
tag = tag.toLowerCase()
/* istanbul ignore if */
if (unknownElementCache[tag] != null) {
return unknownElementCache[tag]
}
const el = document.createElement(tag)
if (tag.indexOf('-') > -1) {
// http://stackoverflow.com/a/28210364/1070244
return (unknownElementCache[tag] = (
el.constructor === window.HTMLUnknownElement ||
el.constructor === window.HTMLElement
))
} else {
return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
}
}
export const isTextInputType = makeMap('text,number,password,search,email,tel,url')
-25
View File
@@ -1,25 +0,0 @@
/* @flow */
import { warn } from 'core/util/index'
export * from './attrs'
export * from './class'
export * from './element'
/**
* Query an element selector if it's not an element already.
*/
export function query (el: string | Element): Element {
if (typeof el === 'string') {
const selected = document.querySelector(el)
if (!selected) {
process.env.NODE_ENV !== 'production' && warn(
'Cannot find element: ' + el
)
return document.createElement('div')
}
return selected
} else {
return el
}
}
BIN
View File
Binary file not shown.
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
import model from './model'
export default {
model
}
-52
View File
@@ -1,52 +0,0 @@
/* @flow */
import { genStaticKeys } from 'shared/util'
import { createCompiler } from 'compiler/index'
import modules from './modules/index'
import directives from './directives/index'
import {
isUnaryTag,
mustUseProp,
isReservedTag,
canBeLeftOpenTag,
getTagNamespace
} from '../util/element'
export const baseOptions: WeexCompilerOptions = {
modules,
directives,
isUnaryTag,
mustUseProp,
canBeLeftOpenTag,
isReservedTag,
getTagNamespace,
preserveWhitespace: false,
recyclable: false,
staticKeys: genStaticKeys(modules)
}
const compiler = createCompiler(baseOptions)
export function compile (
template: string,
options?: WeexCompilerOptions
): WeexCompiledResult {
let generateAltRender = false
if (options && options.recyclable === true) {
generateAltRender = true
options.recyclable = false
}
const result = compiler.compile(template, options)
// generate @render function for <recycle-list>
if (options && generateAltRender) {
options.recyclable = true
// disable static optimizations
options.optimize = false
const { render } = compiler.compile(template, options)
result['@render'] = render
}
return result
}
-13
View File
@@ -1,13 +0,0 @@
import klass from './class'
import style from './style'
import props from './props'
import append from './append'
import recycleList from './recycle-list/index'
export default [
recycleList,
klass,
style,
props,
append
]
@@ -1,16 +0,0 @@
/* @flow */
import { addAttr } from 'compiler/helpers'
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
// mark components as inside recycle-list so that we know we need to invoke
// their special @render function instead of render in create-component.js
export function postTransformComponent (
el: ASTElement,
options: WeexCompilerOptions
) {
// $flow-disable-line (we know isReservedTag is there)
if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') {
addAttr(el, RECYCLE_LIST_MARKER, 'true')
}
}
@@ -1,50 +0,0 @@
/* @flow */
import { parseFor } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
/**
* Map the following syntax to corresponding attrs:
*
* <recycle-list for="(item, i) in longList" switch="cellType">
* <cell-slot case="A"> ... </cell-slot>
* <cell-slot case="B"> ... </cell-slot>
* </recycle-list>
*/
export function preTransformRecycleList (
el: ASTElement,
options: WeexCompilerOptions
) {
const exp = getAndRemoveAttr(el, 'for')
if (!exp) {
if (options.warn) {
options.warn(`Invalid <recycle-list> syntax: missing "for" expression.`)
}
return
}
const res = parseFor(exp)
if (!res) {
if (options.warn) {
options.warn(`Invalid <recycle-list> syntax: ${exp}.`)
}
return
}
addRawAttr(el, ':list-data', res.for)
addRawAttr(el, 'binding-expression', res.for)
addRawAttr(el, 'alias', res.alias)
if (res.iterator2) {
// (item, key, index) for object iteration
// is this even supported?
addRawAttr(el, 'index', res.iterator2)
} else if (res.iterator1) {
addRawAttr(el, 'index', res.iterator1)
}
const switchKey = getAndRemoveAttr(el, 'switch')
if (switchKey) {
addRawAttr(el, 'switch', switchKey)
}
}
@@ -1,33 +0,0 @@
/* @flow */
import { parseFor } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
export function preTransformVFor (el: ASTElement, options: WeexCompilerOptions) {
const exp = getAndRemoveAttr(el, 'v-for')
if (!exp) {
return
}
const res = parseFor(exp)
if (!res) {
if (process.env.NODE_ENV !== 'production' && options.warn) {
options.warn(`Invalid v-for expression: ${exp}`)
}
return
}
const desc: Object = {
'@expression': res.for,
'@alias': res.alias
}
if (res.iterator2) {
desc['@key'] = res.iterator1
desc['@index'] = res.iterator2
} else {
desc['@index'] = res.iterator1
}
delete el.attrsMap['v-for']
addRawAttr(el, '[[repeat]]', desc)
}
@@ -1,63 +0,0 @@
/* @flow */
import { addIfCondition } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
function hasConditionDirective (el: ASTElement): boolean {
for (const attr in el.attrsMap) {
if (/^v\-if|v\-else|v\-else\-if$/.test(attr)) {
return true
}
}
return false
}
function getPreviousConditions (el: ASTElement): Array<string> {
const conditions = []
if (el.parent && el.parent.children) {
for (let c = 0, n = el.parent.children.length; c < n; ++c) {
// $flow-disable-line
const ifConditions = el.parent.children[c].ifConditions
if (ifConditions) {
for (let i = 0, l = ifConditions.length; i < l; ++i) {
const condition = ifConditions[i]
if (condition && condition.exp) {
conditions.push(condition.exp)
}
}
}
}
}
return conditions
}
export function preTransformVIf (el: ASTElement, options: WeexCompilerOptions) {
if (hasConditionDirective(el)) {
let exp
const ifExp = getAndRemoveAttr(el, 'v-if', true /* remove from attrsMap */)
const elseifExp = getAndRemoveAttr(el, 'v-else-if', true)
// don't need the value, but remove it to avoid being generated as a
// custom directive
getAndRemoveAttr(el, 'v-else', true)
if (ifExp) {
exp = ifExp
addIfCondition(el, { exp: ifExp, block: el })
} else {
elseifExp && addIfCondition(el, { exp: elseifExp, block: el })
const prevConditions = getPreviousConditions(el)
if (prevConditions.length) {
const prevMatch = prevConditions.join(' || ')
exp = elseifExp
? `!(${prevMatch}) && (${elseifExp})` // v-else-if
: `!(${prevMatch})` // v-else
} else if (process.env.NODE_ENV !== 'production' && options.warn) {
options.warn(
`v-${elseifExp ? ('else-if="' + elseifExp + '"') : 'else'} ` +
`used on element <${el.tag}> without corresponding v-if.`
)
return
}
}
addRawAttr(el, '[[match]]', exp)
}
}
-187
View File
@@ -1,187 +0,0 @@
/* @flow */
// this will be preserved during build
// $flow-disable-line
const VueFactory = require('./factory')
const instanceOptions: { [key: string]: WeexInstanceOption } = {}
/**
* Create instance context.
*/
export function createInstanceContext (
instanceId: string,
runtimeContext: WeexRuntimeContext,
data: Object = {}
): WeexInstanceContext {
const weex: Weex = runtimeContext.weex
const instance: WeexInstanceOption = instanceOptions[instanceId] = {
instanceId,
config: weex.config,
document: weex.document,
data
}
// Each instance has a independent `Vue` module instance
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
// DEPRECATED
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
const instanceContext = Object.assign({ Vue }, timerAPIs)
Object.freeze(instanceContext)
return instanceContext
}
/**
* Destroy an instance with id. It will make sure all memory of
* this instance released and no more leaks.
*/
export function destroyInstance (instanceId: string): void {
const instance = instanceOptions[instanceId]
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app.$destroy()
instance.document.destroy()
} catch (e) {}
delete instance.document
delete instance.app
}
delete instanceOptions[instanceId]
}
/**
* Refresh an instance with id and new top-level component data.
* It will use `Vue.set` on all keys of the new data. So it's better
* define all possible meaningful keys when instance created.
*/
export function refreshInstance (
instanceId: string,
data: Object
): Error | void {
const instance = instanceOptions[instanceId]
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error(`refreshInstance: instance ${instanceId} not found!`)
}
if (instance.Vue && instance.Vue.set) {
for (const key in data) {
instance.Vue.set(instance.app, key, data[key])
}
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, [])
}
/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance (
instanceId: string,
weex: Weex
): GlobalAPI {
const exports = {}
VueFactory(exports, weex.document)
const Vue = exports.Vue
const instance = instanceOptions[instanceId]
// patch reserved tag detection to account for dynamically registered
// components
const weexRegex = /^weex:/i
const isReservedTag = Vue.config.isReservedTag || (() => false)
const isRuntimeComponent = Vue.config.isRuntimeComponent || (() => false)
Vue.config.isReservedTag = name => {
return (!isRuntimeComponent(name) && weex.supports(`@component/${name}`)) ||
isReservedTag(name) ||
weexRegex.test(name)
}
Vue.config.parsePlatformTagName = name => name.replace(weexRegex, '')
// expose weex-specific info
Vue.prototype.$instanceId = instanceId
Vue.prototype.$document = instance.document
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate () {
const options = this.$options
// root component (vm)
if (options.el) {
// set external data of instance
const dataOption = options.data
const internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {}
options.data = Object.assign(internalData, instance.data)
// record instance by id
instance.app = this
}
},
mounted () {
const options = this.$options
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
} catch (e) {}
}
}
})
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config
}
}
return Vue
}
/**
* DEPRECATED
* Generate HTML5 Timer APIs. An important point is that the callback
* will be converted into callback id when sent to native. So the
* framework can make sure no side effect of the callback happened after
* an instance destroyed.
*/
function getInstanceTimer (
instanceId: string,
moduleGetter: Function
): Object {
const instance = instanceOptions[instanceId]
const timer = moduleGetter('timer')
const timerAPIs = {
setTimeout: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setTimeout(handler, args[1])
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
setInterval: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setInterval(handler, args[1])
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
clearTimeout: (n) => {
timer.clearTimeout(n)
},
clearInterval: (n) => {
timer.clearInterval(n)
}
}
return timerAPIs
}
-6
View File
@@ -1,6 +0,0 @@
// this entry is built and wrapped with a factory function
// used to generate a fresh copy of Vue for every Weex instance.
import Vue from './runtime/index'
exports.Vue = Vue
-9
View File
@@ -1,9 +0,0 @@
import Richtext from './richtext'
import Transition from './transition'
import TransitionGroup from './transition-group'
export default {
Richtext,
Transition,
TransitionGroup
}
-82
View File
@@ -1,82 +0,0 @@
/* @flow */
function getVNodeType (vnode: VNode): string {
if (!vnode.tag) {
return ''
}
return vnode.tag.replace(/vue\-component\-(\d+\-)?/, '')
}
function isSimpleSpan (vnode: VNode): boolean {
return vnode.children &&
vnode.children.length === 1 &&
!vnode.children[0].tag
}
function parseStyle (vnode: VNode): Object | void {
if (!vnode || !vnode.data) {
return
}
const { staticStyle, staticClass } = vnode.data
if (vnode.data.style || vnode.data.class || staticStyle || staticClass) {
const styles = Object.assign({}, staticStyle, vnode.data.style)
const cssMap = vnode.context.$options.style || {}
const classList = [].concat(staticClass, vnode.data.class)
classList.forEach(name => {
if (name && cssMap[name]) {
Object.assign(styles, cssMap[name])
}
})
return styles
}
}
function convertVNodeChildren (children: Array<VNode>): Array<VNode> | void {
if (!children.length) {
return
}
return children.map(vnode => {
const type: string = getVNodeType(vnode)
const props: Object = { type }
// convert raw text node
if (!type) {
props.type = 'span'
props.attr = {
value: (vnode.text || '').trim()
}
} else {
props.style = parseStyle(vnode)
if (vnode.data) {
props.attr = vnode.data.attrs
if (vnode.data.on) {
props.events = vnode.data.on
}
}
if (type === 'span' && isSimpleSpan(vnode)) {
props.attr = props.attr || {}
props.attr.value = vnode.children[0].text.trim()
return props
}
}
if (vnode.children && vnode.children.length) {
props.children = convertVNodeChildren(vnode.children)
}
return props
})
}
export default {
name: 'richtext',
render (h: Function) {
return h('weex:richtext', {
on: this._events,
attrs: {
value: convertVNodeChildren(this.$options._renderChildren || [])
}
})
}
}
@@ -1,148 +0,0 @@
import { warn, extend } from 'core/util/index'
import { transitionProps, extractTransitionData } from './transition'
const props = extend({
tag: String,
moveClass: String
}, transitionProps)
delete props.mode
export default {
props,
created () {
const dom = this.$requireWeexModule('dom')
this.getPosition = el => new Promise((resolve, reject) => {
dom.getComponentRect(el.ref, res => {
if (!res.result) {
reject(new Error(`failed to get rect for element: ${el.tag}`))
} else {
resolve(res.size)
}
})
})
const animation = this.$requireWeexModule('animation')
this.animate = (el, options) => new Promise(resolve => {
animation.transition(el.ref, options, resolve)
})
},
render (h) {
const tag = this.tag || this.$vnode.data.tag || 'span'
const map = Object.create(null)
const prevChildren = this.prevChildren = this.children
const rawChildren = this.$slots.default || []
const children = this.children = []
const transitionData = extractTransitionData(this)
for (let i = 0; i < rawChildren.length; i++) {
const c = rawChildren[i]
if (c.tag) {
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
children.push(c)
map[c.key] = c
;(c.data || (c.data = {})).transition = transitionData
} else if (process.env.NODE_ENV !== 'production') {
const opts = c.componentOptions
const name = opts
? (opts.Ctor.options.name || opts.tag)
: c.tag
warn(`<transition-group> children must be keyed: <${name}>`)
}
}
}
if (prevChildren) {
const kept = []
const removed = []
prevChildren.forEach(c => {
c.data.transition = transitionData
// TODO: record before patch positions
if (map[c.key]) {
kept.push(c)
} else {
removed.push(c)
}
})
this.kept = h(tag, null, kept)
this.removed = removed
}
return h(tag, null, children)
},
beforeUpdate () {
// force removing pass
this.__patch__(
this._vnode,
this.kept,
false, // hydrating
true // removeOnly (!important, avoids unnecessary moves)
)
this._vnode = this.kept
},
updated () {
const children = this.prevChildren
const moveClass = this.moveClass || ((this.name || 'v') + '-move')
const moveData = children.length && this.getMoveData(children[0].context, moveClass)
if (!moveData) {
return
}
// TODO: finish implementing move animations once
// we have access to sync getComponentRect()
// children.forEach(callPendingCbs)
// Promise.all(children.map(c => {
// const oldPos = c.data.pos
// const newPos = c.data.newPos
// const dx = oldPos.left - newPos.left
// const dy = oldPos.top - newPos.top
// if (dx || dy) {
// c.data.moved = true
// return this.animate(c.elm, {
// styles: {
// transform: `translate(${dx}px,${dy}px)`
// }
// })
// }
// })).then(() => {
// children.forEach(c => {
// if (c.data.moved) {
// this.animate(c.elm, {
// styles: {
// transform: ''
// },
// duration: moveData.duration || 0,
// delay: moveData.delay || 0,
// timingFunction: moveData.timingFunction || 'linear'
// })
// }
// })
// })
},
methods: {
getMoveData (context, moveClass) {
const stylesheet = context.$options.style || {}
return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
}
}
}
// function callPendingCbs (c) {
// /* istanbul ignore if */
// if (c.elm._moveCb) {
// c.elm._moveCb()
// }
// /* istanbul ignore if */
// if (c.elm._enterCb) {
// c.elm._enterCb()
// }
// }
-9
View File
@@ -1,9 +0,0 @@
// reuse same transition component logic from web
export {
transitionProps,
extractTransitionData
} from 'web/runtime/components/transition'
import Transition from 'web/runtime/components/transition'
export default Transition
-2
View File
@@ -1,2 +0,0 @@
export default {
}
-42
View File
@@ -1,42 +0,0 @@
/* @flow */
import Vue from 'core/index'
import { patch } from 'weex/runtime/patch'
import { mountComponent } from 'core/instance/lifecycle'
import platformDirectives from 'weex/runtime/directives/index'
import platformComponents from 'weex/runtime/components/index'
import {
query,
mustUseProp,
isReservedTag,
isRuntimeComponent,
isUnknownElement
} from 'weex/util/element'
// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isRuntimeComponent = isRuntimeComponent
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives and components
Vue.options.directives = platformDirectives
Vue.options.components = platformComponents
// install platform patch function
Vue.prototype.__patch__ = patch
// wrap mount
Vue.prototype.$mount = function (
el?: any,
hydrating?: boolean
): Component {
return mountComponent(
this,
el && query(el, this.$document),
hydrating
)
}
export default Vue
-44
View File
@@ -1,44 +0,0 @@
/* @flow */
import { extend } from 'shared/util'
function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (!oldVnode.data.attrs && !vnode.data.attrs) {
return
}
let key, cur, old
const elm = vnode.elm
const oldAttrs = oldVnode.data.attrs || {}
let attrs = vnode.data.attrs || {}
// clone observed objects, as the user probably wants to mutate it
if (attrs.__ob__) {
attrs = vnode.data.attrs = extend({}, attrs)
}
const supportBatchUpdate = typeof elm.setAttrs === 'function'
const batchedAttrs = {}
for (key in attrs) {
cur = attrs[key]
old = oldAttrs[key]
if (old !== cur) {
supportBatchUpdate
? (batchedAttrs[key] = cur)
: elm.setAttr(key, cur)
}
}
for (key in oldAttrs) {
if (attrs[key] == null) {
supportBatchUpdate
? (batchedAttrs[key] = undefined)
: elm.setAttr(key)
}
}
if (supportBatchUpdate) {
elm.setAttrs(batchedAttrs)
}
}
export default {
create: updateAttrs,
update: updateAttrs
}
-13
View File
@@ -1,13 +0,0 @@
import attrs from './attrs'
import klass from './class'
import events from './events'
import style from './style'
import transition from './transition'
export default [
attrs,
klass,
events,
style,
transition
]
-91
View File
@@ -1,91 +0,0 @@
/* @flow */
declare var document: WeexDocument;
import TextNode from 'weex/runtime/text-node'
export const namespaceMap = {}
export function createElement (tagName: string): WeexElement {
return document.createElement(tagName)
}
export function createElementNS (namespace: string, tagName: string): WeexElement {
return document.createElement(namespace + ':' + tagName)
}
export function createTextNode (text: string) {
return new TextNode(text)
}
export function createComment (text: string) {
return document.createComment(text)
}
export function insertBefore (
node: WeexElement,
target: WeexElement,
before: WeexElement
) {
if (target.nodeType === 3) {
if (node.type === 'text') {
node.setAttr('value', target.text)
target.parentNode = node
} else {
const text = createElement('text')
text.setAttr('value', target.text)
node.insertBefore(text, before)
}
return
}
node.insertBefore(target, before)
}
export function removeChild (node: WeexElement, child: WeexElement) {
if (child.nodeType === 3) {
node.setAttr('value', '')
return
}
node.removeChild(child)
}
export function appendChild (node: WeexElement, child: WeexElement) {
if (child.nodeType === 3) {
if (node.type === 'text') {
node.setAttr('value', child.text)
child.parentNode = node
} else {
const text = createElement('text')
text.setAttr('value', child.text)
node.appendChild(text)
}
return
}
node.appendChild(child)
}
export function parentNode (node: WeexElement): WeexElement | void {
return node.parentNode
}
export function nextSibling (node: WeexElement): WeexElement | void {
return node.nextSibling
}
export function tagName (node: WeexElement): string {
return node.type
}
export function setTextContent (node: WeexElement, text: string) {
if (node.parentNode) {
node.parentNode.setAttr('value', text)
}
}
export function setAttribute (node: WeexElement, key: string, val: any) {
node.setAttr(key, val)
}
export function setStyleScope (node: WeexElement, scopeId: string) {
node.setAttr('@styleScope', scopeId)
}
-16
View File
@@ -1,16 +0,0 @@
/* @flow */
import * as nodeOps from 'weex/runtime/node-ops'
import { createPatchFunction } from 'core/vdom/patch'
import baseModules from 'core/vdom/modules/index'
import platformModules from 'weex/runtime/modules/index'
// the directive module should be applied last, after all
// built-in modules have been applied.
const modules = platformModules.concat(baseModules)
export const patch: Function = createPatchFunction({
nodeOps,
modules,
LONG_LIST_THRESHOLD: 10
})
@@ -1,34 +0,0 @@
/* @flow */
import { warn } from 'core/util/debug'
import { handleError } from 'core/util/error'
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
import { resolveVirtualComponent } from './virtual-component'
export function isRecyclableComponent (vnode: VNodeWithData): boolean {
return vnode.data.attrs
? (RECYCLE_LIST_MARKER in vnode.data.attrs)
: false
}
export function renderRecyclableComponentTemplate (vnode: MountedComponentVNode): VNode {
// $flow-disable-line
delete vnode.data.attrs[RECYCLE_LIST_MARKER]
resolveVirtualComponent(vnode)
const vm = createComponentInstanceForVnode(vnode)
const render = (vm.$options: any)['@render']
if (render) {
try {
return render.call(vm)
} catch (err) {
handleError(err, vm, `@render`)
}
} else {
warn(
`@render function not defined on component used in <recycle-list>. ` +
`Make sure to declare \`recyclable="true"\` on the component's template.`,
vm
)
}
}
@@ -1,136 +0,0 @@
/* @flow */
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
import { mergeOptions, isPlainObject, noop } from 'core/util/index'
import Watcher from 'core/observer/watcher'
import { initProxy } from 'core/instance/proxy'
import { initState, getData } from 'core/instance/state'
import { initRender } from 'core/instance/render'
import { initEvents } from 'core/instance/events'
import { initProvide, initInjections } from 'core/instance/inject'
import { initLifecycle, callHook } from 'core/instance/lifecycle'
import { initInternalComponent, resolveConstructorOptions } from 'core/instance/init'
import { registerComponentHook, updateComponentData } from '../../util/index'
let uid = 0
// override Vue.prototype._init
function initVirtualComponent (options: Object = {}) {
const vm: Component = this
const componentId = options.componentId
// virtual component uid
vm._uid = `virtual-component-${uid++}`
// a flag to avoid this being observed
vm._isVue = true
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
// send initial data to native
const data = vm.$options.data
const params = typeof data === 'function'
? getData(data, vm)
: data || {}
if (isPlainObject(params)) {
updateComponentData(componentId, params)
}
registerComponentHook(componentId, 'lifecycle', 'attach', () => {
callHook(vm, 'beforeMount')
const updateComponent = () => {
vm._update(vm._vnode, false)
}
new Watcher(vm, updateComponent, noop, null, true)
vm._isMounted = true
callHook(vm, 'mounted')
})
registerComponentHook(componentId, 'lifecycle', 'detach', () => {
vm.$destroy()
})
}
// override Vue.prototype._update
function updateVirtualComponent (vnode?: VNode) {
const vm: Component = this
const componentId = vm.$options.componentId
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
vm._vnode = vnode
if (vm._isMounted && componentId) {
// TODO: data should be filtered and without bindings
const data = Object.assign({}, vm._data)
updateComponentData(componentId, data, () => {
callHook(vm, 'updated')
})
}
}
// listening on native callback
export function resolveVirtualComponent (vnode: MountedComponentVNode): VNode {
const BaseCtor = vnode.componentOptions.Ctor
const VirtualComponent = BaseCtor.extend({})
const cid = VirtualComponent.cid
VirtualComponent.prototype._init = initVirtualComponent
VirtualComponent.prototype._update = updateVirtualComponent
vnode.componentOptions.Ctor = BaseCtor.extend({
beforeCreate () {
// const vm: Component = this
// TODO: listen on all events and dispatch them to the
// corresponding virtual components according to the componentId.
// vm._virtualComponents = {}
const createVirtualComponent = (componentId, propsData) => {
// create virtual component
// const subVm =
new VirtualComponent({
componentId,
propsData
})
// if (vm._virtualComponents) {
// vm._virtualComponents[componentId] = subVm
// }
}
registerComponentHook(cid, 'lifecycle', 'create', createVirtualComponent)
},
beforeDestroy () {
delete this._virtualComponents
}
})
}
-9
View File
@@ -1,9 +0,0 @@
let latestNodeId = 1
export default function TextNode (text) {
this.instanceId = ''
this.nodeId = latestNodeId++
this.parentNode = null
this.nodeType = 3
this.text = text
}
-40
View File
@@ -1,40 +0,0 @@
/* @flow */
declare var document: WeexDocument;
import { warn } from 'core/util/index'
export const RECYCLE_LIST_MARKER = '@inRecycleList'
// Register the component hook to weex native render engine.
// The hook will be triggered by native, not javascript.
export function registerComponentHook (
componentId: string,
type: string, // hook type, could be "lifecycle" or "instance"
hook: string, // hook name
fn: Function
) {
if (!document || !document.taskCenter) {
warn(`Can't find available "document" or "taskCenter".`)
return
}
if (typeof document.taskCenter.registerHook === 'function') {
return document.taskCenter.registerHook(componentId, type, hook, fn)
}
warn(`Failed to register component hook "${type}@${hook}#${componentId}".`)
}
// Updates the state of the component to weex native render engine.
export function updateComponentData (
componentId: string,
newData: Object | void,
callback?: Function
) {
if (!document || !document.taskCenter) {
warn(`Can't find available "document" or "taskCenter".`)
return
}
if (typeof document.taskCenter.updateData === 'function') {
return document.taskCenter.updateData(componentId, newData, callback)
}
warn(`Failed to update component data (${componentId}).`)
}
-60
View File
@@ -1,60 +0,0 @@
/* @flow */
// import { warn } from 'core/util/index'
// this will be preserved during build
// $flow-disable-line
const acorn = require('acorn') // $flow-disable-line
const walk = require('acorn/dist/walk') // $flow-disable-line
const escodegen = require('escodegen')
export function nodeToBinding (node: Object): any {
switch (node.type) {
case 'Literal': return node.value
case 'Identifier':
case 'UnaryExpression':
case 'BinaryExpression':
case 'LogicalExpression':
case 'ConditionalExpression':
case 'MemberExpression': return { '@binding': escodegen.generate(node) }
case 'ArrayExpression': return node.elements.map(_ => nodeToBinding(_))
case 'ObjectExpression': {
const object = {}
node.properties.forEach(prop => {
if (!prop.key || prop.key.type !== 'Identifier') {
return
}
const key = escodegen.generate(prop.key)
const value = nodeToBinding(prop.value)
if (key && value) {
object[key] = value
}
})
return object
}
default: {
// warn(`Not support ${node.type}: "${escodegen.generate(node)}"`)
return ''
}
}
}
export function generateBinding (exp: ?string): any {
if (exp && typeof exp === 'string') {
let ast = null
try {
ast = acorn.parse(`(${exp})`)
} catch (e) {
// warn(`Failed to parse the expression: "${exp}"`)
return ''
}
let output = ''
walk.simple(ast, {
Expression (node) {
output = nodeToBinding(node)
}
})
return output
}
}
-151
View File
@@ -1,151 +0,0 @@
/* @flow */
import { createPromiseCallback } from '../util'
import { createBundleRunner } from './create-bundle-runner'
import type { Renderer, RenderOptions } from '../create-renderer'
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
const fs = require('fs')
const path = require('path')
const PassThrough = require('stream').PassThrough
const INVALID_MSG =
'Invalid server-rendering bundle format. Should be a string ' +
'or a bundle Object of type:\n\n' +
`{
entry: string;
files: { [filename: string]: string; };
maps: { [filename: string]: string; };
}\n`
// The render bundle can either be a string (single bundled file)
// or a bundle manifest object generated by vue-ssr-webpack-plugin.
type RenderBundle = {
basedir?: string;
entry: string;
files: { [filename: string]: string; };
maps: { [filename: string]: string; };
modules?: { [filename: string]: Array<string> };
};
export function createBundleRendererCreator (
createRenderer: (options?: RenderOptions) => Renderer
) {
return function createBundleRenderer (
bundle: string | RenderBundle,
rendererOptions?: RenderOptions = {}
) {
let files, entry, maps
let basedir = rendererOptions.basedir
// load bundle if given filepath
if (
typeof bundle === 'string' &&
/\.js(on)?$/.test(bundle) &&
path.isAbsolute(bundle)
) {
if (fs.existsSync(bundle)) {
const isJSON = /\.json$/.test(bundle)
basedir = basedir || path.dirname(bundle)
bundle = fs.readFileSync(bundle, 'utf-8')
if (isJSON) {
try {
bundle = JSON.parse(bundle)
} catch (e) {
throw new Error(`Invalid JSON bundle file: ${bundle}`)
}
}
} else {
throw new Error(`Cannot locate bundle file: ${bundle}`)
}
}
if (typeof bundle === 'object') {
entry = bundle.entry
files = bundle.files
basedir = basedir || bundle.basedir
maps = createSourceMapConsumers(bundle.maps)
if (typeof entry !== 'string' || typeof files !== 'object') {
throw new Error(INVALID_MSG)
}
} else if (typeof bundle === 'string') {
entry = '__vue_ssr_bundle__'
files = { '__vue_ssr_bundle__': bundle }
maps = {}
} else {
throw new Error(INVALID_MSG)
}
const renderer = createRenderer(rendererOptions)
const run = createBundleRunner(
entry,
files,
basedir,
rendererOptions.runInNewContext
)
return {
renderToString: (context?: Object, cb: any) => {
if (typeof context === 'function') {
cb = context
context = {}
}
let promise
if (!cb) {
({ promise, cb } = createPromiseCallback())
}
run(context).catch(err => {
rewriteErrorTrace(err, maps)
cb(err)
}).then(app => {
if (app) {
renderer.renderToString(app, context, (err, res) => {
rewriteErrorTrace(err, maps)
cb(err, res)
})
}
})
return promise
},
renderToStream: (context?: Object) => {
const res = new PassThrough()
run(context).catch(err => {
rewriteErrorTrace(err, maps)
// avoid emitting synchronously before user can
// attach error listener
process.nextTick(() => {
res.emit('error', err)
})
}).then(app => {
if (app) {
const renderStream = renderer.renderToStream(app, context)
renderStream.on('error', err => {
rewriteErrorTrace(err, maps)
res.emit('error', err)
})
// relay HTMLStream special events
if (rendererOptions && rendererOptions.template) {
renderStream.on('beforeStart', () => {
res.emit('beforeStart')
})
renderStream.on('beforeEnd', () => {
res.emit('beforeEnd')
})
}
renderStream.pipe(res)
}
})
return res
}
}
}
}
-150
View File
@@ -1,150 +0,0 @@
import { isPlainObject } from 'shared/util'
const vm = require('vm')
const path = require('path')
const resolve = require('resolve')
const NativeModule = require('module')
function createSandbox (context) {
const sandbox = {
Buffer,
console,
process,
setTimeout,
setInterval,
setImmediate,
clearTimeout,
clearInterval,
clearImmediate,
__VUE_SSR_CONTEXT__: context
}
sandbox.global = sandbox
return sandbox
}
function compileModule (files, basedir, runInNewContext) {
const compiledScripts = {}
const resolvedModules = {}
function getCompiledScript (filename) {
if (compiledScripts[filename]) {
return compiledScripts[filename]
}
const code = files[filename]
const wrapper = NativeModule.wrap(code)
const script = new vm.Script(wrapper, {
filename,
displayErrors: true
})
compiledScripts[filename] = script
return script
}
function evaluateModule (filename, sandbox, evaluatedFiles = {}) {
if (evaluatedFiles[filename]) {
return evaluatedFiles[filename]
}
const script = getCompiledScript(filename)
const compiledWrapper = runInNewContext === false
? script.runInThisContext()
: script.runInNewContext(sandbox)
const m = { exports: {}}
const r = file => {
file = path.posix.join('.', file)
if (files[file]) {
return evaluateModule(file, sandbox, evaluatedFiles)
} else if (basedir) {
return require(
resolvedModules[file] ||
(resolvedModules[file] = resolve.sync(file, { basedir }))
)
} else {
return require(file)
}
}
compiledWrapper.call(m.exports, m.exports, r, m)
const res = Object.prototype.hasOwnProperty.call(m.exports, 'default')
? m.exports.default
: m.exports
evaluatedFiles[filename] = res
return res
}
return evaluateModule
}
function deepClone (val) {
if (isPlainObject(val)) {
const res = {}
for (const key in val) {
res[key] = deepClone(val[key])
}
return res
} else if (Array.isArray(val)) {
return val.slice()
} else {
return val
}
}
export function createBundleRunner (entry, files, basedir, runInNewContext) {
const evaluate = compileModule(files, basedir, runInNewContext)
if (runInNewContext !== false && runInNewContext !== 'once') {
// new context mode: creates a fresh context and re-evaluate the bundle
// on each render. Ensures entire application state is fresh for each
// render, but incurs extra evaluation cost.
return (userContext = {}) => new Promise(resolve => {
userContext._registeredComponents = new Set()
const res = evaluate(entry, createSandbox(userContext))
resolve(typeof res === 'function' ? res(userContext) : res)
})
} else {
// direct mode: instead of re-evaluating the whole bundle on
// each render, it simply calls the exported function. This avoids the
// module evaluation costs but requires the source code to be structured
// slightly differently.
let runner // lazy creation so that errors can be caught by user
let initialContext
return (userContext = {}) => new Promise(resolve => {
if (!runner) {
const sandbox = runInNewContext === 'once'
? createSandbox()
: global
// the initial context is only used for collecting possible non-component
// styles injected by vue-style-loader.
initialContext = sandbox.__VUE_SSR_CONTEXT__ = {}
runner = evaluate(entry, sandbox)
// On subsequent renders, __VUE_SSR_CONTEXT__ will not be available
// to prevent cross-request pollution.
delete sandbox.__VUE_SSR_CONTEXT__
if (typeof runner !== 'function') {
throw new Error(
'bundle export should be a function when using ' +
'{ runInNewContext: false }.'
)
}
}
userContext._registeredComponents = new Set()
// vue-style-loader styles imported outside of component lifecycle hooks
if (initialContext._styles) {
userContext._styles = deepClone(initialContext._styles)
// #6353 ensure "styles" is exposed even if no styles are injected
// in component lifecycles.
// the renderStyles fn is exposed by vue-style-loader >= 3.0.3
const renderStyles = initialContext._renderStyles
if (renderStyles) {
Object.defineProperty(userContext, 'styles', {
enumerable: true,
get () {
return renderStyles(userContext._styles)
}
})
}
}
resolve(runner(userContext))
})
}
}
-45
View File
@@ -1,45 +0,0 @@
/* @flow */
const SourceMapConsumer = require('source-map').SourceMapConsumer
const filenameRE = /\(([^)]+\.js):(\d+):(\d+)\)$/
export function createSourceMapConsumers (rawMaps: Object) {
const maps = {}
Object.keys(rawMaps).forEach(file => {
maps[file] = new SourceMapConsumer(rawMaps[file])
})
return maps
}
export function rewriteErrorTrace (e: any, mapConsumers: {
[key: string]: SourceMapConsumer
}) {
if (e && typeof e.stack === 'string') {
e.stack = e.stack.split('\n').map(line => {
return rewriteTraceLine(line, mapConsumers)
}).join('\n')
}
}
function rewriteTraceLine (trace: string, mapConsumers: {
[key: string]: SourceMapConsumer
}) {
const m = trace.match(filenameRE)
const map = m && mapConsumers[m[1]]
if (m != null && map) {
const originalPosition = map.originalPositionFor({
line: Number(m[2]),
column: Number(m[3])
})
if (originalPosition.source != null) {
const { source, line, column } = originalPosition
const mappedPosition = `(${source.replace(/^webpack:\/\/\//, '')}:${String(line)}:${String(column)})`
return trace.replace(filenameRE, mappedPosition)
} else {
return trace
}
} else {
return trace
}
}
-37
View File
@@ -1,37 +0,0 @@
/* @flow */
import { createWriteFunction } from './write'
import { createRenderFunction } from './render'
import type { RenderOptions } from './create-renderer'
export function createBasicRenderer ({
modules = [],
directives = {},
isUnaryTag = (() => false),
cache
}: RenderOptions = {}) {
const render = createRenderFunction(modules, directives, isUnaryTag, cache)
return function renderToString (
component: Component,
context: any,
done: any
): void {
if (typeof context === 'function') {
done = context
context = {}
}
let result = ''
const write = createWriteFunction(text => {
result += text
return false
}, done)
try {
render(component, write, context, () => {
done(null, result)
})
} catch (e) {
done(e)
}
}
}
-20
View File
@@ -1,20 +0,0 @@
/* @flow */
import { parse } from 'compiler/parser/index'
import { generate } from './codegen'
import { optimize } from './optimizer'
import { createCompilerCreator } from 'compiler/create-compiler'
export const createCompiler = createCompilerCreator(function baseCompile (
template: string,
options: CompilerOptions
): CompiledResult {
const ast = parse(template.trim(), options)
optimize(ast, options)
const code = generate(ast, options)
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
-150
View File
@@ -1,150 +0,0 @@
/* @flow */
import { escape, isSSRUnsafeAttr } from 'web/server/util'
import { isObject, extend } from 'shared/util'
import { renderAttr } from 'web/server/modules/attrs'
import { renderClass } from 'web/util/class'
import { genStyle } from 'web/server/modules/style'
import { normalizeStyleBinding } from 'web/util/style'
import {
normalizeChildren,
simpleNormalizeChildren
} from 'core/vdom/helpers/normalize-children'
import {
propsToAttrMap,
isRenderableAttr
} from 'web/server/util'
const ssrHelpers = {
_ssrEscape: escape,
_ssrNode: renderStringNode,
_ssrList: renderStringList,
_ssrAttr: renderAttr,
_ssrAttrs: renderAttrs,
_ssrDOMProps: renderDOMProps,
_ssrClass: renderSSRClass,
_ssrStyle: renderSSRStyle
}
export function installSSRHelpers (vm: Component) {
if (vm._ssrNode) {
return
}
let Vue = vm.constructor
while (Vue.super) {
Vue = Vue.super
}
extend(Vue.prototype, ssrHelpers)
if (Vue.FunctionalRenderContext) {
extend(Vue.FunctionalRenderContext.prototype, ssrHelpers)
}
}
class StringNode {
isString: boolean;
open: string;
close: ?string;
children: ?Array<any>;
constructor (
open: string,
close?: string,
children?: Array<any>,
normalizationType?: number
) {
this.isString = true
this.open = open
this.close = close
if (children) {
this.children = normalizationType === 1
? simpleNormalizeChildren(children)
: normalizationType === 2
? normalizeChildren(children)
: children
} else {
this.children = void 0
}
}
}
function renderStringNode (
open: string,
close?: string,
children?: Array<any>,
normalizationType?: number
): StringNode {
return new StringNode(open, close, children, normalizationType)
}
function renderStringList (
val: any,
render: (
val: any,
keyOrIndex: string | number,
index?: number
) => string
): string {
let ret = ''
let i, l, keys, key
if (Array.isArray(val) || typeof val === 'string') {
for (i = 0, l = val.length; i < l; i++) {
ret += render(val[i], i)
}
} else if (typeof val === 'number') {
for (i = 0; i < val; i++) {
ret += render(i + 1, i)
}
} else if (isObject(val)) {
keys = Object.keys(val)
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i]
ret += render(val[key], key, i)
}
}
return ret
}
function renderAttrs (obj: Object): string {
let res = ''
for (const key in obj) {
if (isSSRUnsafeAttr(key)) {
continue
}
res += renderAttr(key, obj[key])
}
return res
}
function renderDOMProps (obj: Object): string {
let res = ''
for (const key in obj) {
const attr = propsToAttrMap[key] || key.toLowerCase()
if (isRenderableAttr(attr)) {
res += renderAttr(attr, obj[key])
}
}
return res
}
function renderSSRClass (
staticClass: ?string,
dynamic: any
): string {
const res = renderClass(staticClass, dynamic)
return res === '' ? res : ` class="${escape(res)}"`
}
function renderSSRStyle (
staticStyle: ?Object,
dynamic: any,
extra: ?Object
): string {
const style = {}
if (staticStyle) extend(style, staticStyle)
if (dynamic) extend(style, normalizeStyleBinding(dynamic))
if (extra) extend(style, extra)
const res = genStyle(style)
return res === '' ? res : ` style=${JSON.stringify(escape(res))}`
}
-42
View File
@@ -1,42 +0,0 @@
/* @flow */
const compile = require('lodash.template')
const compileOptions = {
escape: /{{([^{][\s\S]+?[^}])}}/g,
interpolate: /{{{([\s\S]+?)}}}/g
}
export type ParsedTemplate = {
head: (data: any) => string;
neck: (data: any) => string;
tail: (data: any) => string;
};
export function parseTemplate (
template: string,
contentPlaceholder?: string = '<!--vue-ssr-outlet-->'
): ParsedTemplate {
if (typeof template === 'object') {
return template
}
let i = template.indexOf('</head>')
const j = template.indexOf(contentPlaceholder)
if (j < 0) {
throw new Error(`Content placeholder not found in template.`)
}
if (i < 0) {
i = template.indexOf('<body>')
if (i < 0) {
i = j
}
}
return {
head: compile(template.slice(0, i), compileOptions),
neck: compile(template.slice(i, j), compileOptions),
tail: compile(template.slice(j + contentPlaceholder.length), compileOptions)
}
}
-82
View File
@@ -1,82 +0,0 @@
/* @flow */
const Transform = require('stream').Transform
import type TemplateRenderer from './index'
import type { ParsedTemplate } from './parse-template'
export default class TemplateStream extends Transform {
started: boolean;
renderer: TemplateRenderer;
template: ParsedTemplate;
context: Object;
inject: boolean;
constructor (
renderer: TemplateRenderer,
template: ParsedTemplate,
context: Object
) {
super()
this.started = false
this.renderer = renderer
this.template = template
this.context = context || {}
this.inject = renderer.inject
}
_transform (data: Buffer | string, encoding: string, done: Function) {
if (!this.started) {
this.emit('beforeStart')
this.start()
}
this.push(data)
done()
}
start () {
this.started = true
this.push(this.template.head(this.context))
if (this.inject) {
// inline server-rendered head meta information
if (this.context.head) {
this.push(this.context.head)
}
// inline preload/prefetch directives for initial/async chunks
const links = this.renderer.renderResourceHints(this.context)
if (links) {
this.push(links)
}
// CSS files and inline server-rendered CSS collected by vue-style-loader
const styles = this.renderer.renderStyles(this.context)
if (styles) {
this.push(styles)
}
}
this.push(this.template.neck(this.context))
}
_flush (done: Function) {
this.emit('beforeEnd')
if (this.inject) {
// inline initial store state
const state = this.renderer.renderState(this.context)
if (state) {
this.push(state)
}
// embed scripts needed
const scripts = this.renderer.renderScripts(this.context)
if (scripts) {
this.push(scripts)
}
}
this.push(this.template.tail(this.context))
done()
}
}
-18
View File
@@ -1,18 +0,0 @@
/* @flow */
export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file)
export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file)
export function createPromiseCallback () {
let resolve, reject
const promise: Promise<string> = new Promise((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})
const cb = (err: Error, res?: string) => {
if (err) return reject(err)
resolve(res || '')
}
return { promise, cb }
}
-8
View File
@@ -1,8 +0,0 @@
import { Vue as _Vue } from "./vue";
export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
export interface PluginObject<T> {
install: PluginFunction<T>;
[key: string]: any;
}