UNPKG

vue-function-api-sd

Version:

Provide logic composition capabilities for Vue.

963 lines (931 loc) 32.6 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) : typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) : (global = global || self, factory(global.vueFunctionApi = {}, global.Vue)); }(this, function (exports, Vue) { 'use strict'; Vue = Vue && Vue.hasOwnProperty('default') ? Vue['default'] : Vue; var toString = function (x) { return Object.prototype.toString.call(x); }; function isNative(Ctor) { return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); } var hasSymbol = typeof Symbol !== 'undefined' && isNative(Symbol) && typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); var noopFn = function (_) { return _; }; var sharedPropertyDefinition = { enumerable: true, configurable: true, get: noopFn, set: noopFn, }; function proxy(target, key, _a) { var get = _a.get, set = _a.set; sharedPropertyDefinition.get = get || noopFn; sharedPropertyDefinition.set = set || noopFn; Object.defineProperty(target, key, sharedPropertyDefinition); } function def(obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true, }); } var hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) { return hasOwnProperty.call(obj, key); } function assert(condition, msg) { if (!condition) throw new Error("[vue-function-api] " + msg); } function isArray(x) { return Array.isArray(x); } function isObject(val) { return val !== null && typeof val === 'object'; } function isPlainObject(x) { return toString(x) === '[object Object]'; } function isFunction(x) { return typeof x === 'function'; } function warn(msg, vm) { Vue.util.warn(msg, vm); } function logError(err, vm, info) { { warn("Error in " + info + ": \"" + err.toString() + "\"", vm); } if (typeof window !== 'undefined' && typeof console !== 'undefined') { console.error(err); } else { throw err; } } var currentVue = null; var currentVM = null; function getCurrentVue() { { assert(currentVue, "must call Vue.use(plugin) before using any function."); } return currentVue; } function setCurrentVue(vue) { currentVue = vue; } function getCurrentVM() { return currentVM; } function setCurrentVM(vm) { currentVM = vm; } var AbstractWrapper = /** @class */ (function () { function AbstractWrapper() { } AbstractWrapper.prototype.setVmProperty = function (vm, propName) { var _this = this; def(this, '_vm', vm); def(this, '_propName', propName); var props = vm.$options.props; if (!(propName in vm) && !(props && hasOwn(props, propName))) { proxy(vm, propName, { get: function () { return _this.value; }, set: function (val) { _this.value = val; }, }); { // expose bindings after state has been resolved to prevent repeated works vm.$nextTick(function () { _this.exposeToDevtool(); }); } } else { if (props && hasOwn(props, propName)) { warn("The setup binding property \"" + propName + "\" is already declared as a prop.", vm); } else { warn("The setup binding property \"" + propName + "\" is already declared.", vm); } } }; return AbstractWrapper; }()); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } var ValueWrapper = /** @class */ (function (_super) { __extends(ValueWrapper, _super); function ValueWrapper(internal) { var _this = _super.call(this) || this; def(_this, '_internal', internal); return _this; } Object.defineProperty(ValueWrapper.prototype, "value", { get: function () { return this._internal.$$state; }, set: function (v) { this._internal.$$state = v; }, enumerable: true, configurable: true }); ValueWrapper.prototype.exposeToDevtool = function () { var _this = this; { var vm = this._vm; var name_1 = this._propName; proxy(vm._data, name_1, { get: function () { return _this.value; }, set: function (val) { _this.value = val; }, }); } }; return ValueWrapper; }(AbstractWrapper)); var ComputedWrapper = /** @class */ (function (_super) { __extends(ComputedWrapper, _super); function ComputedWrapper(internal) { var _this = _super.call(this) || this; def(_this, '_internal', internal); return _this; } Object.defineProperty(ComputedWrapper.prototype, "value", { get: function () { return this._internal.read(); }, set: function (val) { if (!this._internal.write) { { warn('Computed property' + (this._propName ? " \"" + this._propName + "\"" : '') + ' was assigned to but it has no setter.', this._vm); } } else { this._internal.write(val); } }, enumerable: true, configurable: true }); ComputedWrapper.prototype.exposeToDevtool = function () { var _this = this; { var vm = this._vm; var name_1 = this._propName; if (!vm.$options.computed) { vm.$options.computed = {}; } proxy(vm.$options.computed, name_1, { get: function () { return ({ get: function () { return _this.value; }, set: function (val) { _this.value = val; }, }); }, }); } }; return ComputedWrapper; }(AbstractWrapper)); function isWrapper(obj) { return obj instanceof AbstractWrapper; } /** * Helper that recursively merges two data objects together. */ function mergeData(to, from) { if (!from) return to; var key; var toVal; var fromVal; var keys = hasSymbol ? Reflect.ownKeys(from) : Object.keys(from); for (var i = 0; i < keys.length; i++) { key = keys[i]; // in case the object is already observed... if (key === '__ob__') continue; toVal = to[key]; fromVal = from[key]; if (!hasOwn(to, key)) { to[key] = fromVal; } else if (toVal !== fromVal && (isPlainObject(toVal) && !isWrapper(toVal)) && (isPlainObject(fromVal) && !isWrapper(toVal))) { mergeData(toVal, fromVal); } } return to; } function install(Vue, _install) { if (currentVue && currentVue === Vue) { { assert(false, 'already installed. Vue.use(plugin) should be called only once'); } return; } Vue.config.optionMergeStrategies.setup = function (parent, child) { return function mergedSetupFn(props, context) { return mergeData(typeof child === 'function' ? child(props, context) || {} : {}, typeof parent === 'function' ? parent(props, context) || {} : {}); }; }; setCurrentVue(Vue); _install(Vue); } function ensureCurrentVMInFn(hook) { var vm = getCurrentVM(); { assert(vm, "\"" + hook + "\" get called outside of \"setup()\""); } return vm; } function createComponentInstance(Ctor, options) { if (options === void 0) { options = {}; } var silent = Ctor.config.silent; Ctor.config.silent = true; var vm = new Ctor(options); Ctor.config.silent = silent; return vm; } function isComponentInstance(obj) { return currentVue && obj instanceof currentVue; } function createSymbol(name) { return hasSymbol ? Symbol.for(name) : name; } var WatcherPreFlushQueueKey = createSymbol('vfa.key.preFlushQueue'); var WatcherPostFlushQueueKey = createSymbol('vfa.key.postFlushQueue'); var AccessControIdentifierlKey = createSymbol('vfa.key.accessControIdentifier'); var ObservableIdentifierKey = createSymbol('vfa.key.observableIdentifier'); var AccessControlIdentifier = {}; var ObservableIdentifier = {}; /** * Proxing property access of target. * We can do unwrapping and other things here. */ function setupAccessControl(target) { if (!isObject(target) || Array.isArray(target) || isWrapper(target) || isComponentInstance(target)) { return; } if (hasOwn(target, AccessControIdentifierlKey) && target[AccessControIdentifierlKey] === AccessControlIdentifier) { return; } if (Object.isExtensible(target)) { def(target, AccessControIdentifierlKey, AccessControlIdentifier); } var keys = Object.keys(target); for (var i = 0; i < keys.length; i++) { defineAccessControl(target, keys[i]); } } function isObservable(obj) { return (hasOwn(obj, ObservableIdentifierKey) && obj[ObservableIdentifierKey] === ObservableIdentifier); } /** * Auto unwrapping when acccess property */ function defineAccessControl(target, key, val) { if (key === '__ob__') return; var getter; var setter; var property = Object.getOwnPropertyDescriptor(target, key); if (property) { if (property.configurable === false) { return; } getter = property.get; setter = property.set; if ((!getter || setter) /* not only have getter */ && arguments.length === 2) { val = target[key]; } } setupAccessControl(val); Object.defineProperty(target, key, { enumerable: true, configurable: true, get: function getterHandler() { var value = getter ? getter.call(target) : val; if (isWrapper(value)) { return value.value; } else { return value; } }, set: function setterHandler(newVal) { if (getter && !setter) return; var value = getter ? getter.call(target) : val; if (isWrapper(value)) { if (isWrapper(newVal)) { val = newVal; } else { value.value = newVal; } } else if (setter) { setter.call(target, newVal); } else if (isWrapper(newVal)) { val = newVal; } setupAccessControl(newVal); }, }); } /** * Make obj reactivity */ function observable(obj) { if (!isObject(obj) || isObservable(obj)) { return obj; } var Vue = getCurrentVue(); var observed; if (Vue.observable) { observed = Vue.observable(obj); } else { var vm = createComponentInstance(Vue, { data: { $$state: obj, }, }); observed = vm._data.$$state; } if (Object.isExtensible(observed)) { def(observed, ObservableIdentifierKey, ObservableIdentifier); } setupAccessControl(observed); return observed; } function isUndef(v) { return v === undefined || v === null; } function isPrimitive(value) { return (typeof value === 'string' || typeof value === 'number' || // $flow-disable-line typeof value === 'symbol' || typeof value === 'boolean'); } function isValidArrayIndex(val) { var n = parseFloat(String(val)); return n >= 0 && Math.floor(n) === n && isFinite(val); } /** * Set a property on an object. Adds the new property, triggers change * notification and intercept it's subsequent access if the property doesn't * already exist. */ function set(target, key, val) { var Vue = getCurrentVue(); var _a = Vue.util, warn = _a.warn, defineReactive = _a.defineReactive; if (isUndef(target) || isPrimitive(target)) { warn("Cannot set reactive property on undefined, null, or primitive value: " + target); } if (isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); return val; } if (key in target && !(key in Object.prototype)) { target[key] = val; return val; } var ob = target.__ob__; if (target._isVue || (ob && ob.vmCount)) { warn('Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.'); return val; } if (!ob) { target[key] = val; return val; } defineReactive(ob.value, key, val); // IMPORTANT: define access control before trigger watcher defineAccessControl(target, key, val); ob.dep.notify(); return val; } function state(value) { return observable(value); } function value(value) { return new ValueWrapper(state({ $$state: value })); } function mixin(Vue) { Vue.mixin({ beforeCreate: functionApiInit, }); /** * Vuex init hook, injected into each instances init hooks list. */ function functionApiInit() { var vm = this; var $options = vm.$options; var setup = $options.setup; if (!setup) { return; } if (typeof setup !== 'function') { { warn('The "setup" option should be a function that returns a object in component definitions.', vm); } return; } var data = $options.data; // wapper the data option, so we can invoke setup before data get resolved $options.data = function wrappedData() { initSetup(vm, vm.$props); return typeof data === 'function' ? data.call(vm, vm) : data || {}; }; } function initSetup(vm, props) { if (props === void 0) { props = {}; } var setup = vm.$options.setup; var ctx = createSetupContext(vm); var binding; var preVm = getCurrentVM(); setCurrentVM(vm); try { binding = setup(props, ctx); } catch (err) { logError(err, vm, 'setup()'); } finally { setCurrentVM(preVm); } if (!binding) return; if (isFunction(binding)) { vm.$options.render = function () { return binding(vm.$props, ctx); }; return; } if (isPlainObject(binding)) { Object.keys(binding).forEach(function (name) { var bindingValue = binding[name]; // make plain value reactive if (!isWrapper(bindingValue)) { bindingValue = value(bindingValue); } // bind to vm bindingValue.setVmProperty(vm, name); }); return; } { assert(false, "\"setup\" must return a \"Object\" or a \"Function\", get \"" + Object.prototype.toString .call(binding) .slice(8, -1) + "\""); } } function createSetupContext(vm) { var ctx = {}; var props = [ 'root', 'parent', 'refs', ['slots', 'scopedSlots'], 'attrs', ]; var methodReturnVoid = ['emit']; props.forEach(function (key) { var _a; var targetKey; var srcKey; if (Array.isArray(key)) { _a = __read(key, 2), targetKey = _a[0], srcKey = _a[1]; } else { targetKey = srcKey = key; } srcKey = "$" + srcKey; proxy(ctx, targetKey, { get: function () { return vm[srcKey]; }, set: function () { warn("Cannot assign to '" + targetKey + "' because it is a read-only property", vm); }, }); }); methodReturnVoid.forEach(function (key) { var srcKey = "$" + key; proxy(ctx, key, { get: function () { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var fn = vm[srcKey]; fn.apply(vm, args); }; }, }); }); return ctx; } } var fallbackCreateElement; var createElement = function createElement() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!currentVM) { if (!fallbackCreateElement) { fallbackCreateElement = createComponentInstance(getCurrentVue()).$createElement; } return fallbackCreateElement.apply(null, args); } return currentVM.$createElement.apply(null, args); }; // implementation, close to no-op function createComponent(options) { return options; } var genName = function (name) { return "on" + (name[0].toUpperCase() + name.slice(1)); }; function createLifeCycle(lifeCyclehook) { return function (callback) { var vm = ensureCurrentVMInFn(genName(lifeCyclehook)); injectHookOption(getCurrentVue(), vm, lifeCyclehook, callback); }; } function createLifeCycles(lifeCyclehooks, name) { return function (callback) { var currentVue = getCurrentVue(); var vm = ensureCurrentVMInFn(name); lifeCyclehooks.forEach(function (lifeCyclehook) { return injectHookOption(currentVue, vm, lifeCyclehook, callback); }); }; } function injectHookOption(Vue, vm, hook, val) { var options = vm.$options; var mergeFn = Vue.config.optionMergeStrategies[hook]; options[hook] = mergeFn(options[hook], val); } var onCreated = createLifeCycle('created'); var onBeforeMount = createLifeCycle('beforeMount'); var onMounted = createLifeCycle('mounted'); var onBeforeUpdate = createLifeCycle('beforeUpdate'); var onUpdated = createLifeCycle('updated'); var onActivated = createLifeCycle('activated'); var onDeactivated = createLifeCycle('deactivated'); var onBeforeDestroy = createLifeCycle('beforeDestroy'); var onDestroyed = createLifeCycle('destroyed'); var onErrorCaptured = createLifeCycle('errorCaptured'); // only one event will be fired between destroyed and deactivated when an unmount occurs var onUnmounted = createLifeCycles(['destroyed', 'deactivated'], genName('unmounted')); var INIT_VALUE = {}; var fallbackVM; function flushPreQueue() { flushQueue(this, WatcherPreFlushQueueKey); } function flushPostQueue() { flushQueue(this, WatcherPostFlushQueueKey); } function hasWatchEnv(vm) { return vm[WatcherPreFlushQueueKey] !== undefined; } function installWatchEnv(vm) { vm[WatcherPreFlushQueueKey] = []; vm[WatcherPostFlushQueueKey] = []; vm.$on('hook:beforeUpdate', flushPreQueue); vm.$on('hook:updated', flushPostQueue); } function flushQueue(vm, key) { var queue = vm[key]; for (var index = 0; index < queue.length; index++) { queue[index](); } queue.length = 0; } function scheduleFlush(vm, fn, mode) { if (vm === fallbackVM) { // no render pipeline, ignore flush mode fn(); } else { // flush all when beforeUpdate and updated are not fired var fallbackFlush = function () { vm.$nextTick(function () { if (vm[WatcherPreFlushQueueKey].length) { flushQueue(vm, WatcherPreFlushQueueKey); } if (vm[WatcherPostFlushQueueKey].length) { flushQueue(vm, WatcherPostFlushQueueKey); } }); }; switch (mode) { case 'pre': fallbackFlush(); vm[WatcherPreFlushQueueKey].push(fn); break; case 'post': fallbackFlush(); vm[WatcherPostFlushQueueKey].push(fn); break; default: assert(false, "flush must be one of [\"post\", \"pre\", \"sync\"], but got " + mode); break; } } } function createSingleSourceWatcher(vm, source, cb, options) { var getter; if (isWrapper(source)) { getter = function () { return source.value; }; } else { getter = source; } // `callbackRef` is used to handle firty sync callbck. // The subsequent callbcks will redirect to `flush`. var callbackRef = function (n, o) { callbackRef = flush; if (!options.lazy) { cb(n, o); } else { flush(n, o); } }; var flushMode = options.flush; var flush = flushMode === 'sync' ? function (n, o) { return cb(n, o); } : function (n, o) { scheduleFlush(vm, function () { cb(n, o); }, flushMode); }; return vm.$watch(getter, function (n, o) { callbackRef(n, o); }, { immediate: !options.lazy, deep: options.deep, // @ts-ignore sync: flushMode === 'sync', }); } function createMuiltSourceWatcher(vm, sources, cb, options) { var watcherContext = []; var execCallback = function () { cb.apply(vm, watcherContext.reduce(function (acc, ctx) { var newVal = (ctx.value = (ctx.value === INIT_VALUE ? ctx.getter() : ctx.value)); var oldVal = (ctx.oldValue === INIT_VALUE ? newVal : ctx.oldValue); ctx.oldValue = newVal; acc[0].push(newVal); acc[1].push(oldVal); return acc; }, [[], []])); }; var stop = function () { return watcherContext.forEach(function (ctx) { return ctx.watcherStopHandle(); }); }; var execCallbackAfterNumRun = options.lazy ? false : sources.length; // `callbackRef` is used to handle firty sync callbck. // The subsequent callbcks will redirect to `flush`. var callbackRef = function () { if (execCallbackAfterNumRun !== false) { if (--execCallbackAfterNumRun === 0) { execCallbackAfterNumRun = false; callbackRef = flush; execCallback(); } } else { callbackRef = flush; flush(); } }; var pendingCallback = false; var flushMode = options.flush; var flush = flushMode === 'sync' ? execCallback : function () { if (!pendingCallback) { pendingCallback = true; vm.$nextTick(function () { scheduleFlush(vm, function () { pendingCallback = false; execCallback(); }, flushMode); }); } }; sources.forEach(function (source) { var getter; if (isWrapper(source)) { getter = function () { return source.value; }; } else { getter = source; } var watcherCtx = { getter: getter, value: INIT_VALUE, oldValue: INIT_VALUE, }; // must push watcherCtx before create watcherStopHandle watcherContext.push(watcherCtx); watcherCtx.watcherStopHandle = vm.$watch(getter, function (n, o) { watcherCtx.value = n; // only update oldValue at frist, susquent updates at execCallback if (watcherCtx.oldValue === INIT_VALUE) { watcherCtx.oldValue = o; } callbackRef(); }, { immediate: !options.lazy, deep: options.deep, // @ts-ignore // always set to true, so we can fully control the schedule sync: true, }); }); return stop; } function watch(source, cb, options) { if (options === void 0) { options = {}; } var opts = __assign({ lazy: false, deep: false, flush: 'post', }, options); var vm = getCurrentVM(); if (!vm) { if (!fallbackVM) { fallbackVM = createComponentInstance(getCurrentVue()); } vm = fallbackVM; } else if (!hasWatchEnv(vm)) { installWatchEnv(vm); } if (isArray(source)) { return createMuiltSourceWatcher(vm, source, cb, opts); } return createSingleSourceWatcher(vm, source, cb, opts); } function computed(getter, setter) { var computedHost = createComponentInstance(getCurrentVue(), { computed: { $$state: { get: getter, set: setter, }, }, }); return new ComputedWrapper(__assign({ read: function () { return computedHost.$$state; } }, (setter && { write: function (v) { computedHost.$$state = v; }, }))); } var UNRESOLVED_INJECT = {}; function resolveInject(provideKey, vm) { var source = vm; while (source) { // @ts-ignore if (source._provided && hasOwn(source._provided, provideKey)) { //@ts-ignore return source._provided[provideKey]; } source = source.$parent; } return UNRESOLVED_INJECT; } function provide(keyOrData, value) { var vm = ensureCurrentVMInFn('provide'); if (!vm._provided) { vm._provided = {}; } if (isObject(keyOrData)) { Object.assign(vm._provided, keyOrData); } else { vm._provided[keyOrData] = value; } } function inject(key) { if (!key) { return; } var vm = ensureCurrentVMInFn('inject'); var val = resolveInject(key, vm); if (val !== UNRESOLVED_INJECT) { if (isWrapper(val)) { return val; } return new ComputedWrapper({ read: function () { return val; }, write: function () { warn("The injectd value can't be re-assigned", vm); }, }); } else { warn("Injection \"" + String(key) + "\" not found", vm); } } var _install = function (Vue) { return install(Vue, mixin); }; var plugin = { install: _install, }; // Auto install if it is not done yet and `window` has `Vue`. // To allow users to avoid auto-installation in some cases, if (currentVue && typeof window !== 'undefined' && window.Vue) { _install(window.Vue); } exports.computed = computed; exports.createComponent = createComponent; exports.createElement = createElement; exports.inject = inject; exports.onActivated = onActivated; exports.onBeforeDestroy = onBeforeDestroy; exports.onBeforeMount = onBeforeMount; exports.onBeforeUpdate = onBeforeUpdate; exports.onCreated = onCreated; exports.onDeactivated = onDeactivated; exports.onDestroyed = onDestroyed; exports.onErrorCaptured = onErrorCaptured; exports.onMounted = onMounted; exports.onUnmounted = onUnmounted; exports.onUpdated = onUpdated; exports.plugin = plugin; exports.provide = provide; exports.set = set; exports.state = state; exports.value = value; exports.watch = watch; Object.defineProperty(exports, '__esModule', { value: true }); }));