@cicada/render
Advanced tools
Comparing version 1.1.21 to 1.1.22-alpha1
@@ -11,2 +11,4 @@ 'use strict'; | ||
require('raf/polyfill'); | ||
var _enzyme = require('enzyme'); | ||
@@ -350,7 +352,9 @@ | ||
expect(Button.getRendered()).toBe(2); | ||
expect(Button.getRendered()).toBe(1); | ||
expect(Input.getRendered()).toBe(2); | ||
}); | ||
test('change with mapBackgroundToState', function () {}); | ||
// | ||
// test('change with mapBackgroundToState', () => { | ||
// | ||
// }) | ||
}); |
@@ -7,2 +7,6 @@ 'use strict'; | ||
var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); | ||
var _defineProperty3 = _interopRequireDefault(_defineProperty2); | ||
var _extends2 = require('babel-runtime/helpers/extends'); | ||
@@ -131,2 +135,21 @@ | ||
function syncChange(statePath, changes) { | ||
var stateId = stateTree.getWithDetail(statePath).stateId; | ||
if (changesGroupById[stateId] === undefined) { | ||
changesGroupById[stateId] = []; | ||
} | ||
var changesToReturn = (0, _defineProperty3.default)({}, stateId, []); | ||
changes.forEach(function (change) { | ||
changesGroupById[stateId].push((0, _extends3.default)({}, change, { | ||
stateId: stateId, | ||
statePath: statePath | ||
})); | ||
changesToReturn[stateId].push((0, _extends3.default)({}, change, { | ||
stateId: stateId, | ||
statePath: statePath | ||
})); | ||
}); | ||
return changesToReturn; | ||
} | ||
return (0, _extends3.default)({ | ||
@@ -145,2 +168,8 @@ origin: stateTree | ||
resetHardById: cacheInSession(saveChangesGroupById(stateTree.resetHardById, 1)), | ||
// 专门针对有 stateProxy | ||
syncChange: cacheInSession(syncChange), | ||
getChanges: function getChanges() { | ||
return (0, _extends3.default)({}, changesGroupById); | ||
}, | ||
subscribe: subscribe, | ||
@@ -147,0 +176,0 @@ forceSubscribe: forceSubscribe, |
@@ -312,3 +312,5 @@ 'use strict'; | ||
if (typeof value === 'function') { | ||
/* eslint-disable no-console */ | ||
console.error('business.set(\'' + statePath + path + '\', value) should not be set a function.'); | ||
/* eslint-enable no-console */ | ||
return false; | ||
@@ -324,3 +326,5 @@ } | ||
if (!Array.isArray(value) && !(0, _isPlainObject2.default)(value)) { | ||
/* eslint-disable no-console */ | ||
console.error('business.set(\'' + statePath + path + '\', value) should be set a plain value.'); | ||
/* eslint-enable no-console */ | ||
return false; | ||
@@ -327,0 +331,0 @@ } |
@@ -84,2 +84,12 @@ 'use strict'; | ||
function wrapWithInstance(instance, fn) { | ||
return fn !== undefined ? function () { | ||
for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) { | ||
arg[_key] = arguments[_key]; | ||
} | ||
return fn.apply(undefined, [{ instance: instance }].concat(arg)); | ||
} : undefined; | ||
} | ||
var createComponentId = (0, _util.createUniqueIdGenerator)(); | ||
@@ -109,3 +119,4 @@ | ||
_DeclarativeComponent7 = DeclarativeComponent.display, | ||
display = _DeclarativeComponent7 === undefined ? _constant.DISPLAY_BLOCK : _DeclarativeComponent7; | ||
display = _DeclarativeComponent7 === undefined ? _constant.DISPLAY_BLOCK : _DeclarativeComponent7, | ||
getStateProxy = DeclarativeComponent.getStateProxy; | ||
@@ -177,3 +188,3 @@ var primitiveFns = (0, _util.pick)(DeclarativeComponent, _constant.primitiveFnNames); | ||
var _stateTree$register = stateTree.register(statePath, finalGetInitialState, displayName, pathGetter), | ||
var _stateTree$register = stateTree.register(statePath, finalGetInitialState, displayName, pathGetter, wrapWithInstance(this.instance, getStateProxy)), | ||
stateId = _stateTree$register.stateId, | ||
@@ -238,4 +249,4 @@ cancelStateTree = _stateTree$register.cancel; | ||
return function () { | ||
for (var _len = arguments.length, runtimeArgs = Array(_len), _key = 0; _key < _len; _key++) { | ||
runtimeArgs[_key] = arguments[_key]; | ||
for (var _len2 = arguments.length, runtimeArgs = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
runtimeArgs[_key2] = arguments[_key2]; | ||
} | ||
@@ -245,2 +256,5 @@ | ||
var nextState = defaultListener.apply(undefined, [_this4.getRenderArg(statePath)].concat(runtimeArgs)); | ||
// 如果组件有 stateProxy,说明不需要外部 stateTree 的 merge。只需要收到通知就够了。注意,此时 nexState 返回的其实是 changes。 | ||
if (getStateProxy !== undefined) return _this4.context.stateTree.syncChange(_this4.getResolvedStatePath(), nextState); | ||
if (nextState !== undefined && nextState !== null && _this4.registeredStateTree) { | ||
@@ -311,4 +325,4 @@ _this4.context.stateTree.merge(_this4.getResolvedStatePath(), nextState, { | ||
for (var _len2 = arguments.length, runtimeArgs = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
runtimeArgs[_key2] = arguments[_key2]; | ||
for (var _len3 = arguments.length, runtimeArgs = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
runtimeArgs[_key3] = arguments[_key3]; | ||
} | ||
@@ -425,3 +439,3 @@ | ||
} | ||
// 新增的声明周期函数 | ||
// 新增的声明周期函数,专门针对复合组件和动态组件。 | ||
if (type === _constant.CHANGE_STATETREE && typeof componentWillReceiveState === 'function') { | ||
@@ -428,0 +442,0 @@ componentWillReceiveState(_this6.getRenderArg(), changes); |
@@ -7,5 +7,5 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _extends2 = require('babel-runtime/helpers/extends'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _extends3 = _interopRequireDefault(_extends2); | ||
@@ -22,2 +22,6 @@ exports.default = createDynamicRender; | ||
var _cloneDeep = require('lodash/cloneDeep'); | ||
var _cloneDeep2 = _interopRequireDefault(_cloneDeep); | ||
var _Render = require('./Render'); | ||
@@ -27,4 +31,2 @@ | ||
var _constant = require('./constant'); | ||
var _exist = require('./exist'); | ||
@@ -34,20 +36,11 @@ | ||
var _util = require('./util'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function cheapClone(obj) { | ||
return JSON.parse((0, _stringify2.default)(obj)); | ||
function removePathHeader(path, header) { | ||
var result = path.slice(header.length); | ||
return result[0] === '.' ? result.slice(1) : result; | ||
} | ||
function startWith(str, toTest) { | ||
return str.slice(0, toTest.length) === toTest; | ||
} | ||
function isConfigChanged(changes) { | ||
return changes.some(function (_ref) { | ||
var valuePath = _ref.valuePath; | ||
return startWith(valuePath, 'config'); | ||
}); | ||
} | ||
function createDynamicRender(createStateTree, createAppearance, createBackground, backgroundDef) { | ||
@@ -67,6 +60,9 @@ var getDefaultState = function getDefaultState() { | ||
var defaultListeners = { | ||
onChange: function onChange(_ref2, changeFn, name, path) { | ||
var instance = _ref2.instance; | ||
onChange: function onChange(_ref, changeFn, name, path) { | ||
var instance = _ref.instance, | ||
state = _ref.state, | ||
statePath = _ref.statePath; | ||
if (changeFn === undefined) return; | ||
instance.stateTree.cache(); | ||
@@ -78,45 +74,100 @@ for (var _len = arguments.length, runtimeArgs = Array(_len > 4 ? _len - 4 : 0), _key = 4; _key < _len; _key++) { | ||
changeFn.apply(undefined, runtimeArgs); | ||
// 如果 stateTree 都没变, 那么 return undefined 只是通知一下外部 | ||
return instance.stateTreeVersion === instance.stateTree.getVersion() ? undefined : { value: cheapClone(instance.stateTree.get()) }; | ||
// 如果 stateTree 都没变, 那么 return 空数组只是通知一下外部,注意,dynamic 是有 stateProxy,所以这里 return 的是 changes。 | ||
var changesGroupById = instance.stateTree.getChanges(); | ||
var changesReplaced = []; | ||
(0, _util.each)(changesGroupById, function (changes) { | ||
changes.forEach(function (change) { | ||
changesReplaced.push((0, _extends3.default)({ | ||
valuePath: 'value.' + change.valuePath | ||
}, change)); | ||
}); | ||
}); | ||
return changesReplaced; | ||
} | ||
}; | ||
var shouldComponentUpdate = function shouldComponentUpdate(_, type, changes) { | ||
// 收到 config 变化才 return true | ||
return type === _constant.CHANGE_STATETREE && isConfigChanged(changes); | ||
}; | ||
// state 的 proxy 模式,可以接管 stateTree 的变化 | ||
var getStateProxy = function getStateProxy(_ref2) { | ||
var instance = _ref2.instance; | ||
var initialValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var componentWillReceiveState = function componentWillReceiveState(_ref3, changes) { | ||
var instance = _ref3.instance, | ||
state = _ref3.state; | ||
instance.stateTree = createStateTree(initialValue.value || {}); | ||
instance.config = initialValue.config ? (0, _extends3.default)({}, initialValue.config) : {}; | ||
return { | ||
get: function get(statePath) { | ||
var _instance$stateTree; | ||
// CAUTION 如果 config 数据变化了,那么肯定会进入重新渲染的流程。 | ||
if (isConfigChanged(changes)) return; | ||
for (var _len2 = arguments.length, arg = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | ||
arg[_key2 - 1] = arguments[_key2]; | ||
} | ||
// 收到数据变化,那么对 stateTree 进行操作 | ||
var valuePathsToChange = changes.reduce(function (last, _ref4) { | ||
var valuePath = _ref4.valuePath, | ||
inputStatePath = _ref4.inputStatePath; | ||
if (/^value/.test(statePath)) return (_instance$stateTree = instance.stateTree).get.apply(_instance$stateTree, [removePathHeader(statePath, 'value')].concat(arg)); | ||
if (/^config/.test(statePath)) return _exist2.default.get.apply(_exist2.default, [instance.config, removePathHeader(statePath, 'config')].concat(arg)); | ||
throw new Error('get unknown state name: ' + statePath); | ||
}, | ||
set: function set(statePath, value) { | ||
for (var _len3 = arguments.length, arg = Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) { | ||
arg[_key3 - 2] = arguments[_key3]; | ||
} | ||
// inputStatePath 为 undefined 的是内部变化,所以忽略掉 | ||
if (inputStatePath === undefined) return last; | ||
// 如果改的不是 value | ||
if (!startWith(valuePath, 'value')) return last; | ||
if (/^value/.test(statePath)) { | ||
var path = removePathHeader(statePath, 'value'); | ||
if (path) { | ||
var _instance$stateTree2; | ||
// 去掉前面的 'value.' 就得到了 value 下的改变的 path | ||
var inputValuePath = valuePath.slice(6); | ||
var isParentSaved = last.some(function (parent) { | ||
return inputValuePath.slice(0, parent.length) === parent; | ||
}); | ||
return isParentSaved ? last : last.concat(inputValuePath); | ||
}, []); | ||
(_instance$stateTree2 = instance.stateTree).set.apply(_instance$stateTree2, [removePathHeader(statePath, 'value'), value].concat(arg)); | ||
} else { | ||
(0, _util.each)(value, function (v, k) { | ||
var _instance$stateTree3; | ||
valuePathsToChange.forEach(function (inputValuePath) { | ||
instance.stateTree.merge(inputValuePath, _exist2.default.get(state.value, inputValuePath)); | ||
}); | ||
(_instance$stateTree3 = instance.stateTree).set.apply(_instance$stateTree3, [k, v].concat(arg)); | ||
}); | ||
} | ||
return; | ||
} | ||
// 注意,config 没有 merge,只是创建不存在的路径 | ||
if (/^config/.test(statePath)) { | ||
// 对于外界的 set,记录一下,之后要用。 | ||
instance.isConfigChanged = true; | ||
var _path = removePathHeader(statePath, 'config'); | ||
if (!_path) { | ||
instance.config = value; | ||
} else { | ||
_exist2.default.set(instance.config, removePathHeader(statePath, 'config'), value, true); | ||
} | ||
return; | ||
} | ||
throw new Error('set unknown state name: ' + statePath); | ||
} | ||
}; | ||
}; | ||
instance.stateTreeVersion = instance.stateTree.getVersion(); | ||
instance.backgroundVersion = instance.background.getVersion(); | ||
// CAUTION 这是提高效率的关键,只有当 config 变化时,我们才完全从头渲染 | ||
// 当只有 stateTree 变化时,使用内部的机制更新。 | ||
var shouldComponentUpdate = function shouldComponentUpdate(_ref3) { | ||
var instance = _ref3.instance; | ||
return instance.isConfigChanged; | ||
}; | ||
var componentWillReceiveState = function componentWillReceiveState(_ref4) { | ||
var instance = _ref4.instance; | ||
// 不管是外部的 set,还是内部的变化,都会走到这里来。 | ||
// 1. 引起 config 变化的,只可能是外部的 listener。由于外部在 set 上做了个记号,所以可以短路。 | ||
// config 变化了,那么一定要完全重新渲染,所有东西都要重建,因此不用管数据了。 | ||
if (instance.isConfigChanged) { | ||
return; | ||
} | ||
// 2. config 没变化,只有 stateTree 发生了变化,那么有两种情况: | ||
// 2.1 外部通过 set 也改变了 state,那么应该合并进来。 | ||
// 这种情况在 stateProxy 中已经合并到 stateTree 里了 | ||
// 2.2 只有内部改变了 stateTree。这种情况在调用 onChange 的时候就已经真实触发了 | ||
// 无论哪种情况,这个时候都应该准确地通知到界面更新了,因此不需要再做其他操作。 | ||
instance.stateTree.flush(); | ||
}; | ||
return { | ||
@@ -127,17 +178,18 @@ getDefaultState: getDefaultState, | ||
componentWillReceiveState: componentWillReceiveState, | ||
getStateProxy: getStateProxy, | ||
defaultListeners: defaultListeners, | ||
render: function render(_ref5) { | ||
var state = _ref5.state, | ||
instance = _ref5.instance, | ||
var instance = _ref5.instance, | ||
listeners = _ref5.listeners; | ||
var config = state.config, | ||
value = state.value; | ||
instance.stateTree = createStateTree(value); | ||
var config = instance.config; | ||
// 清空一下这个标记,这是用来记录是否要重新渲染的 | ||
if (instance.isConfigChanged) { | ||
// 如果是二次渲染,stateTree 要重做,否则的 getProxy 的时候已经创建了,不用管 | ||
instance.isConfigChanged = false; | ||
instance.stateTree = createStateTree((0, _cloneDeep2.default)(instance.stateTree.get(''))); | ||
} | ||
instance.appearance = createAppearance(); | ||
instance.background = createBackground(backgroundDef, instance.stateTree, instance.appearance); | ||
instance.stateTreeVersion = instance.stateTree.getVersion(); | ||
instance.backgroundVersion = instance.background.getVersion(); | ||
return _react2.default.createElement(_Render2.default, { | ||
@@ -144,0 +196,0 @@ config: config, |
@@ -72,3 +72,5 @@ 'use strict'; | ||
if (statePath.split('.').length !== detectArr.length) { | ||
/* eslint-disable no-console */ | ||
console.error('Warning: ' + new _errors.ErrorWrongStateTreePath(statePath, detectArr.join('.'))); | ||
/* eslint-enable no-console */ | ||
} | ||
@@ -82,3 +84,16 @@ } | ||
function get(statePath, defaultValue) { | ||
return _exist2.default.get(stateTree, statePath, defaultValue); | ||
if (!statePath) return stateTree; | ||
var path = statePath.split(_exist.rxAccess); | ||
var result = stateTree; | ||
while (path.length !== 0) { | ||
result = result[path.shift()]; | ||
if (result === undefined && path.length !== 0) { | ||
if (defaultValue === undefined) throw new _errors.ErrorWrongStateTreePath(statePath, path); | ||
return defaultValue; | ||
} | ||
// 如果碰到 stateProxy,就都交给 proxy 处理 | ||
if (result && result._isStateProxy && path.length !== 0) return result.get(path.join('.')); | ||
} | ||
return result === undefined ? defaultValue : result; | ||
} | ||
@@ -100,2 +115,3 @@ | ||
var pathGetters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var isStateProxy = arguments[3]; | ||
@@ -106,2 +122,8 @@ Object.defineProperty(state, '_id', { | ||
if (isStateProxy) { | ||
Object.defineProperty(state, '_isStateProxy', { | ||
value: true | ||
}); | ||
} | ||
// CAUTION 目前 pathGetter 必须要有 getStatePath | ||
@@ -116,8 +138,14 @@ // 除此还有 getRootStatePath/getScopes/getRenderScopes | ||
function registerToStateTree(statePath, getInitialState, pathGetters) { | ||
complete(statePath, getInitialState()); | ||
function registerToStateTree(statePath, getInitialState, pathGetters, getStateProxy) { | ||
if (getStateProxy !== undefined) { | ||
// 有 stateProxy 的情况下,就用这个 Proxy | ||
_exist2.default.set(stateTree, statePath, getStateProxy(_exist2.default.get(stateTree, statePath))); | ||
} else { | ||
complete(statePath, getInitialState()); | ||
} | ||
var stateId = createStateId(); | ||
var state = get(statePath); | ||
try { | ||
defineState(state, stateId, pathGetters); | ||
defineState(state, stateId, pathGetters, getStateProxy !== undefined); | ||
} catch (e) { | ||
@@ -159,6 +187,4 @@ throw new _errors.ErrorDuplicateOriginDataPath(statePath); | ||
function setNaive(stateNodePath, relativePath, value, inputStateId, inputStatePath) { | ||
var stateId = inputStateId || get(stateNodePath)._id; | ||
_exist2.default.set(stateTree, (0, _common.joinPath)([stateNodePath, relativePath]), value, true); | ||
return [{ | ||
function createChange(stateId, stateNodePath, relativePath, inputStatePath) { | ||
return { | ||
stateId: stateId, | ||
@@ -168,5 +194,11 @@ statePath: stateNodePath, | ||
inputStatePath: inputStatePath | ||
}]; | ||
}; | ||
} | ||
function setNaive(stateNodePath, relativePath, value, inputStateId, inputStatePath) { | ||
var stateId = inputStateId || get(stateNodePath)._id; | ||
_exist2.default.set(stateTree, (0, _common.joinPath)([stateNodePath, relativePath]), value, true); | ||
return [createChange(stateId, stateNodePath, relativePath, inputStatePath)]; | ||
} | ||
function shapeObject(stateNodePath, relativePath, nextValue) { | ||
@@ -191,6 +223,7 @@ var origin = _exist2.default.get(stateTree, (0, _common.joinPath)([stateNodePath, relativePath])); | ||
var stateId = inputStateId || get(stateNodePath)._id; | ||
// 需要更新子组件 | ||
// 在处理对象时,有可能碰到了递归的子组件 | ||
if (targetStateId && stateId !== targetStateId) { | ||
return setObject((0, _common.joinPath)([stateNodePath, relativePath]), '', inputValue, targetStateId, mergeLastState, initialValue, inputStatePath); | ||
return setStateNode((0, _common.joinPath)([stateNodePath, relativePath]), inputValue, mergeLastState, inputStatePath); | ||
} | ||
var changes = [{ stateId: stateId, statePath: stateNodePath, valuePath: relativePath }]; | ||
@@ -257,4 +290,11 @@ var nextValue = mergeLastState ? inputValue : (0, _extends3.default)({}, initialValue, inputValue); | ||
function setStateNode(statePath, inputState, mergeLastState, inputStatePath, stupid) { | ||
var state = get(statePath); | ||
var stateId = state._id; | ||
if (state._isStateProxy) { | ||
// 如果是 proxy,就直接交给 proxy 操作了,里面的细节不管 | ||
state.set(findRelativePath(statePath, inputStatePath), inputState, mergeLastState, inputStatePath); | ||
return [createChange(stateId, statePath, '', inputStatePath)]; | ||
} | ||
var changes = []; | ||
var stateId = get(statePath)._id; | ||
var initialState = initialStates[stateId].getInitialState(); | ||
@@ -283,4 +323,12 @@ var finalState = mergeLastState ? inputState : (0, _extends3.default)({}, initialState, inputState); | ||
var stateNodePath = findClosestInitialPath(inputStatePath); | ||
var stateId = get(stateNodePath)._id; | ||
var state = get(stateNodePath); | ||
var stateId = state._id; | ||
if (!stateId || !initialStates[stateId]) throw new _errors.ErrorWrongStateTreePath(inputStatePath.split('.')[0], inputStatePath); | ||
if (state._isStateProxy) { | ||
// 如果是 proxy,就直接交给 proxy 操作了,里面的细节不管 | ||
state.set(findRelativePath(stateNodePath, inputStatePath), inputState, mergeLastState, inputStatePath); | ||
return [createChange(stateId, stateNodePath, '', inputStatePath)]; | ||
} | ||
var initialState = initialStates[stateId].getInitialState(); | ||
@@ -376,5 +424,6 @@ var relativeChildPath = findRelativePath(stateNodePath, inputStatePath); | ||
defaults: guardWithPathDetect(defaults), | ||
// 用于同步 stateProxy | ||
// CAUTION register 对外暴露的接口会自动补全数据 | ||
register: function register(statePath, getInitialState, type, pathGetters) { | ||
var stateId = registerToStateTree(statePath, getInitialState, pathGetters); | ||
register: function register(statePath, getInitialState, type, pathGetters, getStateProxy) { | ||
var stateId = registerToStateTree(statePath, getInitialState, pathGetters, getStateProxy); | ||
var cancelInitialState = registerInitialState(stateId, getInitialState, type); | ||
@@ -381,0 +430,0 @@ return { |
@@ -6,2 +6,3 @@ 'use strict'; | ||
}); | ||
exports.rxAccess = undefined; | ||
@@ -23,3 +24,3 @@ var _assign = require('babel-runtime/core-js/object/assign'); | ||
/* eslint-disable no-useless-escape */ | ||
var rxAccess = /[\[\]\.]+/; | ||
var rxAccess = exports.rxAccess = /[\[\]\.]+/; | ||
/* eslint-enable no-useless-escape */ | ||
@@ -26,0 +27,0 @@ |
@@ -140,5 +140,3 @@ 'use strict'; | ||
// 这里才真的通知子组件开始渲染 | ||
if (!this.isControlled) { | ||
this.stateTree.flush(); | ||
} | ||
this.stateTree.flush(); | ||
} | ||
@@ -145,0 +143,0 @@ }, { |
{ | ||
"name": "@cicada/render", | ||
"version": "1.1.21", | ||
"version": "1.1.22-alpha1", | ||
"main": "./lib/index.js", | ||
@@ -14,3 +14,4 @@ "scripts": { | ||
"exist.js": "^0.3.0", | ||
"lodash": "^4.17.4" | ||
"lodash": "^4.17.4", | ||
"raf": "^3.4.0" | ||
}, | ||
@@ -61,2 +62,3 @@ "peerDependencies": { | ||
"setupFiles": [ | ||
"raf/polyfill", | ||
"<rootDir>/src/__test__/_setup.js" | ||
@@ -74,4 +76,4 @@ ] | ||
"babel-preset-stage-0": "^6.22.0", | ||
"enzyme": "^3.3.0", | ||
"enzyme-adapter-react-16": "^1.1.1", | ||
"enzyme": "^3.7.0", | ||
"enzyme-adapter-react-16": "^1.6.0", | ||
"eslint-plugin-markdown": "^1.0.0-beta.4", | ||
@@ -78,0 +80,0 @@ "jest": "^19.0.2", |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
409085
9882
5
70
2
+ Addedraf@^3.4.0
+ Addedperformance-now@2.1.0(transitive)
+ Addedraf@3.4.1(transitive)