@atom-vue/shared
Advanced tools
+215
-151
@@ -5,7 +5,9 @@ 'use strict'; | ||
| // Make a map and return a function for checking if a key | ||
| // is in that map. | ||
| // | ||
| // IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/ | ||
| // So that rollup can tree-shake them if necessary. | ||
| /** | ||
| * Make a map and return a function for checking if a key | ||
| * is in that map. | ||
| * IMPORTANT: all calls of this function must be prefixed with | ||
| * \/\*#\_\_PURE\_\_\*\/ | ||
| * So that rollup can tree-shake them if necessary. | ||
| */ | ||
| function makeMap(str, expectsLowerCase) { | ||
@@ -68,3 +70,3 @@ const map = Object.create(null); | ||
| const line = j + 1; | ||
| res.push(`${line}${' '.repeat(3 - String(line).length)}| ${lines[j]}`); | ||
| res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); | ||
| const lineLength = lines[j].length; | ||
@@ -91,99 +93,18 @@ if (j === i) { | ||
| const mockError = () => mockWarn(true); | ||
| function mockWarn(asError = false) { | ||
| expect.extend({ | ||
| toHaveBeenWarned(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls.some(args => args[0].indexOf(received) > -1); | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedLast(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1; | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned last.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedTimes(received, n) { | ||
| asserted.add(received); | ||
| let found = 0; | ||
| warn.mock.calls.forEach(args => { | ||
| if (args[0].indexOf(received) > -1) { | ||
| found++; | ||
| } | ||
| }); | ||
| if (found === n) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" to have been warned ${n} times.` | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned ${n} times but got ${found}.` | ||
| }; | ||
| } | ||
| } | ||
| }); | ||
| let warn; | ||
| const asserted = new Set(); | ||
| beforeEach(() => { | ||
| asserted.clear(); | ||
| warn = jest.spyOn(console, asError ? 'error' : 'warn'); | ||
| warn.mockImplementation(() => { }); | ||
| }); | ||
| afterEach(() => { | ||
| const assertedArray = Array.from(asserted); | ||
| const nonAssertedWarnings = warn.mock.calls | ||
| .map(args => args[0]) | ||
| .filter(received => { | ||
| return !assertedArray.some(assertedMsg => { | ||
| return received.indexOf(assertedMsg) > -1; | ||
| }); | ||
| }); | ||
| warn.mockRestore(); | ||
| if (nonAssertedWarnings.length) { | ||
| nonAssertedWarnings.forEach(warning => { | ||
| console.warn(warning); | ||
| }); | ||
| throw new Error(`test case threw unexpected warnings.`); | ||
| } | ||
| }); | ||
| } | ||
| // On the client we only need to offer special cases for boolean attributes that | ||
| // have different names from their corresponding dom properties: | ||
| // - itemscope -> N/A | ||
| // - allowfullscreen -> allowFullscreen | ||
| // - formnovalidate -> formNoValidate | ||
| // - ismap -> isMap | ||
| // - nomodule -> noModule | ||
| // - novalidate -> noValidate | ||
| // - readonly -> readOnly | ||
| /** | ||
| * On the client we only need to offer special cases for boolean attributes that | ||
| * have different names from their corresponding dom properties: | ||
| * - itemscope -> N/A | ||
| * - allowfullscreen -> allowFullscreen | ||
| * - formnovalidate -> formNoValidate | ||
| * - ismap -> isMap | ||
| * - nomodule -> noModule | ||
| * - novalidate -> noValidate | ||
| * - readonly -> readOnly | ||
| */ | ||
| const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; | ||
| const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); | ||
| // The full list is needed during SSR to produce the correct initial markup. | ||
| /** | ||
| * The full list is needed during SSR to produce the correct initial markup. | ||
| */ | ||
| const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + | ||
@@ -211,3 +132,5 @@ `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + | ||
| }; | ||
| // CSS properties that accept plain numbers | ||
| /** | ||
| * CSS properties that accept plain numbers | ||
| */ | ||
| const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + | ||
@@ -222,2 +145,23 @@ `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + | ||
| `stroke-miterlimit,stroke-opacity,stroke-width`); | ||
| /** | ||
| * Known attributes, this is used for stringification of runtime static nodes | ||
| * so that we don't stringify bindings that cannot be set from HTML. | ||
| * Don't also forget to allow `data-*` and `aria-*`! | ||
| * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes | ||
| */ | ||
| const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + | ||
| `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + | ||
| `border,buffered,capture,challenge,charset,checked,cite,class,code,` + | ||
| `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + | ||
| `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + | ||
| `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + | ||
| `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + | ||
| `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + | ||
| `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + | ||
| `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + | ||
| `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + | ||
| `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + | ||
| `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + | ||
| `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + | ||
| `value,width,wrap`); | ||
@@ -228,3 +172,4 @@ function normalizeStyle(value) { | ||
| for (let i = 0; i < value.length; i++) { | ||
| const normalized = normalizeStyle(value[i]); | ||
| const item = value[i]; | ||
| const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); | ||
| if (normalized) { | ||
@@ -242,2 +187,14 @@ for (const key in normalized) { | ||
| } | ||
| const listDelimiterRE = /;(?![^(]*\))/g; | ||
| const propertyDelimiterRE = /:(.+)/; | ||
| function parseStringStyle(cssText) { | ||
| const ret = {}; | ||
| cssText.split(listDelimiterRE).forEach(item => { | ||
| if (item) { | ||
| const tmp = item.split(propertyDelimiterRE); | ||
| tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); | ||
| } | ||
| }); | ||
| return ret; | ||
| } | ||
| function stringifyStyle(styles) { | ||
@@ -259,12 +216,51 @@ let ret = ''; | ||
| } | ||
| // wangyan51: 比较class对象 | ||
| // class结构 {s:[], d:[]} | ||
| // 在被merge后会增加ms部分 {s:[], d:[], ms:[]} | ||
| function compareClass(valueA, valueB) { | ||
| if (valueA && valueB && valueA.length === valueB.length) { | ||
| for (let i = 0; i < valueA.length; i++) { | ||
| if (valueA[i] !== valueB[i]) { | ||
| // A不存在 或 B不存在 | ||
| if (!valueA || !valueB) { | ||
| return false; | ||
| } | ||
| // 有数组对象,且长度不为0时才认为是存在 | ||
| // 先比较静态部分 | ||
| let valueAs = valueA.s && valueA.s.length > 0; | ||
| let valueBs = valueB.s && valueB.s.length > 0; | ||
| // 静态部分一个存在一个不存在 或 都存在但不一致 | ||
| if (valueAs != valueBs || (valueAs && valueA.s != valueB.s)) { | ||
| return false; | ||
| } | ||
| // 比较merged静态部分 | ||
| let valueAms = valueA.ms && valueA.ms.length > 0; | ||
| let valueBms = valueB.ms && valueB.ms.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAms != valueBms || (valueAms && valueA.ms.length != valueB.ms.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAms) { | ||
| for (let i = 0; i < valueA.ms.length; i++) { | ||
| if (valueA.ms[i] !== valueB.ms[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| // 比较动态部分 | ||
| let valueAd = valueA.d && valueA.d.length > 0; | ||
| let valueBd = valueB.d && valueB.d.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAd != valueBd || (valueAd && valueA.d.length != valueB.d.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAd) { | ||
| for (let i = 0; i < valueA.d.length; i++) { | ||
| if (valueA.d[i] !== valueB.d[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
@@ -284,3 +280,3 @@ function innerNormalizeClass(value, result) { | ||
| function normalizeClass(value) { | ||
| // TODO: 目前动态class和静态class会在编译时merge到一起,normalizeClass时会进行递归处理,后续不再merge时换用更简单的逻辑 | ||
| // TODO: 换用更简单的逻辑 | ||
| let res = []; | ||
@@ -340,40 +336,47 @@ innerNormalizeClass(value, res); | ||
| function looseCompareArrays(a, b) { | ||
| if (a.length !== b.length) | ||
| return false; | ||
| let equal = true; | ||
| for (let i = 0; equal && i < a.length; i++) { | ||
| equal = looseEqual(a[i], b[i]); | ||
| } | ||
| return equal; | ||
| } | ||
| function looseEqual(a, b) { | ||
| if (a === b) | ||
| return true; | ||
| const isObjectA = isObject(a); | ||
| const isObjectB = isObject(b); | ||
| if (isObjectA && isObjectB) { | ||
| try { | ||
| const isArrayA = isArray(a); | ||
| const isArrayB = isArray(b); | ||
| if (isArrayA && isArrayB) { | ||
| return (a.length === b.length && | ||
| a.every((e, i) => looseEqual(e, b[i]))); | ||
| } | ||
| else if (a instanceof Date && b instanceof Date) { | ||
| return a.getTime() === b.getTime(); | ||
| } | ||
| else if (!isArrayA && !isArrayB) { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| return (keysA.length === keysB.length && | ||
| keysA.every(key => looseEqual(a[key], b[key]))); | ||
| } | ||
| else { | ||
| /* istanbul ignore next */ | ||
| let aValidType = isDate(a); | ||
| let bValidType = isDate(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? a.getTime() === b.getTime() : false; | ||
| } | ||
| aValidType = isArray(a); | ||
| bValidType = isArray(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? looseCompareArrays(a, b) : false; | ||
| } | ||
| aValidType = isObject(a); | ||
| bValidType = isObject(b); | ||
| if (aValidType || bValidType) { | ||
| /* istanbul ignore if: this if will probably never be called */ | ||
| if (!aValidType || !bValidType) { | ||
| return false; | ||
| } | ||
| const aKeysCount = Object.keys(a).length; | ||
| const bKeysCount = Object.keys(b).length; | ||
| if (aKeysCount !== bKeysCount) { | ||
| return false; | ||
| } | ||
| for (const key in a) { | ||
| const aHasKey = a.hasOwnProperty(key); | ||
| const bHasKey = b.hasOwnProperty(key); | ||
| if ((aHasKey && !bHasKey) || | ||
| (!aHasKey && bHasKey) || | ||
| !looseEqual(a[key], b[key])) { | ||
| return false; | ||
| } | ||
| } | ||
| catch (e) { | ||
| /* istanbul ignore next */ | ||
| return false; | ||
| } | ||
| } | ||
| else if (!isObjectA && !isObjectB) { | ||
| return String(a) === String(b); | ||
| } | ||
| else { | ||
| return false; | ||
| } | ||
| return String(a) === String(b); | ||
| } | ||
@@ -383,4 +386,14 @@ function looseIndexOf(arr, val) { | ||
| } | ||
| function looseHas(set, val) { | ||
| for (let item of set) { | ||
| if (looseEqual(item, val)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| // For converting {{ interpolation }} values to displayed strings. | ||
| /** | ||
| * For converting {{ interpolation }} values to displayed strings. | ||
| * @private | ||
| */ | ||
| const toDisplayString = (val) => { | ||
@@ -394,3 +407,3 @@ return val == null | ||
| const replacer = (_key, val) => { | ||
| if (val instanceof Map) { | ||
| if (isMap(val)) { | ||
| return { | ||
@@ -403,3 +416,3 @@ [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { | ||
| } | ||
| else if (val instanceof Set) { | ||
| else if (isSet(val)) { | ||
| return { | ||
@@ -415,2 +428,13 @@ [`Set(${val.size})`]: [...val.values()] | ||
| /** | ||
| * List of @babel/parser plugins that are used for template expression | ||
| * transforms and SFC script transforms. By default we enable proposals slated | ||
| * for ES2020. This will need to be updated as the spec moves forward. | ||
| * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins | ||
| */ | ||
| const babelParserDefaultPlugins = [ | ||
| 'bigInt', | ||
| 'optionalChaining', | ||
| 'nullishCoalescingOperator' | ||
| ]; | ||
| const EMPTY_OBJ = Object.freeze({}) | ||
@@ -426,8 +450,4 @@ ; | ||
| const isOn = (key) => onRE.test(key); | ||
| const extend = (a, b) => { | ||
| for (const key in b) { | ||
| a[key] = b[key]; | ||
| } | ||
| return a; | ||
| }; | ||
| const isModelListener = (key) => key.startsWith('onUpdate:'); | ||
| const extend = Object.assign; | ||
| const remove = (arr, el) => { | ||
@@ -442,2 +462,5 @@ const i = arr.indexOf(el); | ||
| const isArray = Array.isArray; | ||
| const isMap = (val) => toTypeString(val) === '[object Map]'; | ||
| const isSet = (val) => toTypeString(val) === '[object Set]'; | ||
| const isDate = (val) => val instanceof Date; | ||
| const isFunction = (val) => typeof val === 'function'; | ||
@@ -456,2 +479,6 @@ const isString = (val) => typeof val === 'string'; | ||
| const isPlainObject = (val) => toTypeString(val) === '[object Object]'; | ||
| const isIntegerKey = (key) => isString(key) && | ||
| key !== 'NaN' && | ||
| key[0] !== '-' && | ||
| '' + parseInt(key, 10) === key; | ||
| const isReservedProp = /*#__PURE__*/ makeMap('key,ref,' + | ||
@@ -469,2 +496,5 @@ 'onVnodeBeforeMount,onVnodeMounted,' + | ||
| const camelizeRE = /-(\w)/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const camelize = cacheStringFunction((str) => { | ||
@@ -474,5 +504,11 @@ return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); | ||
| const hyphenateRE = /\B([A-Z])/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const hyphenate = cacheStringFunction((str) => { | ||
| return str.replace(hyphenateRE, '-$1').toLowerCase(); | ||
| }); | ||
| /** | ||
| * @private | ||
| */ | ||
| const capitalize = cacheStringFunction((str) => { | ||
@@ -491,5 +527,24 @@ return str.charAt(0).toUpperCase() + str.slice(1); | ||
| configurable: true, | ||
| enumerable: false, | ||
| value | ||
| }); | ||
| }; | ||
| const toNumber = (val) => { | ||
| const n = parseFloat(val); | ||
| return isNaN(n) ? val : n; | ||
| }; | ||
| let _globalThis; | ||
| const getGlobalThis = () => { | ||
| return (_globalThis || | ||
| (_globalThis = | ||
| typeof globalThis !== 'undefined' | ||
| ? globalThis | ||
| : typeof self !== 'undefined' | ||
| ? self | ||
| : typeof window !== 'undefined' | ||
| ? window | ||
| : typeof global !== 'undefined' | ||
| ? global | ||
| : {})); | ||
| }; | ||
@@ -501,2 +556,3 @@ exports.EMPTY_ARR = EMPTY_ARR; | ||
| exports.PatchFlagNames = PatchFlagNames; | ||
| exports.babelParserDefaultPlugins = babelParserDefaultPlugins; | ||
| exports.camelize = camelize; | ||
@@ -510,2 +566,3 @@ exports.capitalize = capitalize; | ||
| exports.generateCodeFrame = generateCodeFrame; | ||
| exports.getGlobalThis = getGlobalThis; | ||
| exports.hasChanged = hasChanged; | ||
@@ -517,4 +574,9 @@ exports.hasOwn = hasOwn; | ||
| exports.isBooleanAttr = isBooleanAttr; | ||
| exports.isDate = isDate; | ||
| exports.isFunction = isFunction; | ||
| exports.isGloballyWhitelisted = isGloballyWhitelisted; | ||
| exports.isIntegerKey = isIntegerKey; | ||
| exports.isKnownAttr = isKnownAttr; | ||
| exports.isMap = isMap; | ||
| exports.isModelListener = isModelListener; | ||
| exports.isNoUnitNumericStyleProp = isNoUnitNumericStyleProp; | ||
@@ -527,2 +589,3 @@ exports.isObject = isObject; | ||
| exports.isSSRSafeAttrName = isSSRSafeAttrName; | ||
| exports.isSet = isSet; | ||
| exports.isSpecialBooleanAttr = isSpecialBooleanAttr; | ||
@@ -533,9 +596,9 @@ exports.isString = isString; | ||
| exports.looseEqual = looseEqual; | ||
| exports.looseHas = looseHas; | ||
| exports.looseIndexOf = looseIndexOf; | ||
| exports.makeMap = makeMap; | ||
| exports.mockError = mockError; | ||
| exports.mockWarn = mockWarn; | ||
| exports.normalizeClass = normalizeClass; | ||
| exports.normalizeStyle = normalizeStyle; | ||
| exports.objectToString = objectToString; | ||
| exports.parseStringStyle = parseStringStyle; | ||
| exports.propsToAttrMap = propsToAttrMap; | ||
@@ -546,3 +609,4 @@ exports.remove = remove; | ||
| exports.toDisplayString = toDisplayString; | ||
| exports.toNumber = toNumber; | ||
| exports.toRawType = toRawType; | ||
| exports.toTypeString = toTypeString; |
+215
-151
@@ -5,7 +5,9 @@ 'use strict'; | ||
| // Make a map and return a function for checking if a key | ||
| // is in that map. | ||
| // | ||
| // IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/ | ||
| // So that rollup can tree-shake them if necessary. | ||
| /** | ||
| * Make a map and return a function for checking if a key | ||
| * is in that map. | ||
| * IMPORTANT: all calls of this function must be prefixed with | ||
| * \/\*#\_\_PURE\_\_\*\/ | ||
| * So that rollup can tree-shake them if necessary. | ||
| */ | ||
| function makeMap(str, expectsLowerCase) { | ||
@@ -68,3 +70,3 @@ const map = Object.create(null); | ||
| const line = j + 1; | ||
| res.push(`${line}${' '.repeat(3 - String(line).length)}| ${lines[j]}`); | ||
| res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); | ||
| const lineLength = lines[j].length; | ||
@@ -91,99 +93,18 @@ if (j === i) { | ||
| const mockError = () => mockWarn(true); | ||
| function mockWarn(asError = false) { | ||
| expect.extend({ | ||
| toHaveBeenWarned(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls.some(args => args[0].indexOf(received) > -1); | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedLast(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1; | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned last.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedTimes(received, n) { | ||
| asserted.add(received); | ||
| let found = 0; | ||
| warn.mock.calls.forEach(args => { | ||
| if (args[0].indexOf(received) > -1) { | ||
| found++; | ||
| } | ||
| }); | ||
| if (found === n) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" to have been warned ${n} times.` | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned ${n} times but got ${found}.` | ||
| }; | ||
| } | ||
| } | ||
| }); | ||
| let warn; | ||
| const asserted = new Set(); | ||
| beforeEach(() => { | ||
| asserted.clear(); | ||
| warn = jest.spyOn(console, asError ? 'error' : 'warn'); | ||
| warn.mockImplementation(() => { }); | ||
| }); | ||
| afterEach(() => { | ||
| const assertedArray = Array.from(asserted); | ||
| const nonAssertedWarnings = warn.mock.calls | ||
| .map(args => args[0]) | ||
| .filter(received => { | ||
| return !assertedArray.some(assertedMsg => { | ||
| return received.indexOf(assertedMsg) > -1; | ||
| }); | ||
| }); | ||
| warn.mockRestore(); | ||
| if (nonAssertedWarnings.length) { | ||
| nonAssertedWarnings.forEach(warning => { | ||
| console.warn(warning); | ||
| }); | ||
| throw new Error(`test case threw unexpected warnings.`); | ||
| } | ||
| }); | ||
| } | ||
| // On the client we only need to offer special cases for boolean attributes that | ||
| // have different names from their corresponding dom properties: | ||
| // - itemscope -> N/A | ||
| // - allowfullscreen -> allowFullscreen | ||
| // - formnovalidate -> formNoValidate | ||
| // - ismap -> isMap | ||
| // - nomodule -> noModule | ||
| // - novalidate -> noValidate | ||
| // - readonly -> readOnly | ||
| /** | ||
| * On the client we only need to offer special cases for boolean attributes that | ||
| * have different names from their corresponding dom properties: | ||
| * - itemscope -> N/A | ||
| * - allowfullscreen -> allowFullscreen | ||
| * - formnovalidate -> formNoValidate | ||
| * - ismap -> isMap | ||
| * - nomodule -> noModule | ||
| * - novalidate -> noValidate | ||
| * - readonly -> readOnly | ||
| */ | ||
| const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; | ||
| const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); | ||
| // The full list is needed during SSR to produce the correct initial markup. | ||
| /** | ||
| * The full list is needed during SSR to produce the correct initial markup. | ||
| */ | ||
| const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + | ||
@@ -211,3 +132,5 @@ `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + | ||
| }; | ||
| // CSS properties that accept plain numbers | ||
| /** | ||
| * CSS properties that accept plain numbers | ||
| */ | ||
| const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + | ||
@@ -222,2 +145,23 @@ `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + | ||
| `stroke-miterlimit,stroke-opacity,stroke-width`); | ||
| /** | ||
| * Known attributes, this is used for stringification of runtime static nodes | ||
| * so that we don't stringify bindings that cannot be set from HTML. | ||
| * Don't also forget to allow `data-*` and `aria-*`! | ||
| * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes | ||
| */ | ||
| const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + | ||
| `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + | ||
| `border,buffered,capture,challenge,charset,checked,cite,class,code,` + | ||
| `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + | ||
| `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + | ||
| `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + | ||
| `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + | ||
| `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + | ||
| `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + | ||
| `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + | ||
| `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + | ||
| `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + | ||
| `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + | ||
| `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + | ||
| `value,width,wrap`); | ||
@@ -228,3 +172,4 @@ function normalizeStyle(value) { | ||
| for (let i = 0; i < value.length; i++) { | ||
| const normalized = normalizeStyle(value[i]); | ||
| const item = value[i]; | ||
| const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); | ||
| if (normalized) { | ||
@@ -242,2 +187,14 @@ for (const key in normalized) { | ||
| } | ||
| const listDelimiterRE = /;(?![^(]*\))/g; | ||
| const propertyDelimiterRE = /:(.+)/; | ||
| function parseStringStyle(cssText) { | ||
| const ret = {}; | ||
| cssText.split(listDelimiterRE).forEach(item => { | ||
| if (item) { | ||
| const tmp = item.split(propertyDelimiterRE); | ||
| tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); | ||
| } | ||
| }); | ||
| return ret; | ||
| } | ||
| function stringifyStyle(styles) { | ||
@@ -259,12 +216,51 @@ let ret = ''; | ||
| } | ||
| // wangyan51: 比较class对象 | ||
| // class结构 {s:[], d:[]} | ||
| // 在被merge后会增加ms部分 {s:[], d:[], ms:[]} | ||
| function compareClass(valueA, valueB) { | ||
| if (valueA && valueB && valueA.length === valueB.length) { | ||
| for (let i = 0; i < valueA.length; i++) { | ||
| if (valueA[i] !== valueB[i]) { | ||
| // A不存在 或 B不存在 | ||
| if (!valueA || !valueB) { | ||
| return false; | ||
| } | ||
| // 有数组对象,且长度不为0时才认为是存在 | ||
| // 先比较静态部分 | ||
| let valueAs = valueA.s && valueA.s.length > 0; | ||
| let valueBs = valueB.s && valueB.s.length > 0; | ||
| // 静态部分一个存在一个不存在 或 都存在但不一致 | ||
| if (valueAs != valueBs || (valueAs && valueA.s != valueB.s)) { | ||
| return false; | ||
| } | ||
| // 比较merged静态部分 | ||
| let valueAms = valueA.ms && valueA.ms.length > 0; | ||
| let valueBms = valueB.ms && valueB.ms.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAms != valueBms || (valueAms && valueA.ms.length != valueB.ms.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAms) { | ||
| for (let i = 0; i < valueA.ms.length; i++) { | ||
| if (valueA.ms[i] !== valueB.ms[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| // 比较动态部分 | ||
| let valueAd = valueA.d && valueA.d.length > 0; | ||
| let valueBd = valueB.d && valueB.d.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAd != valueBd || (valueAd && valueA.d.length != valueB.d.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAd) { | ||
| for (let i = 0; i < valueA.d.length; i++) { | ||
| if (valueA.d[i] !== valueB.d[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
@@ -284,3 +280,3 @@ function innerNormalizeClass(value, result) { | ||
| function normalizeClass(value) { | ||
| // TODO: 目前动态class和静态class会在编译时merge到一起,normalizeClass时会进行递归处理,后续不再merge时换用更简单的逻辑 | ||
| // TODO: 换用更简单的逻辑 | ||
| let res = []; | ||
@@ -340,40 +336,47 @@ innerNormalizeClass(value, res); | ||
| function looseCompareArrays(a, b) { | ||
| if (a.length !== b.length) | ||
| return false; | ||
| let equal = true; | ||
| for (let i = 0; equal && i < a.length; i++) { | ||
| equal = looseEqual(a[i], b[i]); | ||
| } | ||
| return equal; | ||
| } | ||
| function looseEqual(a, b) { | ||
| if (a === b) | ||
| return true; | ||
| const isObjectA = isObject(a); | ||
| const isObjectB = isObject(b); | ||
| if (isObjectA && isObjectB) { | ||
| try { | ||
| const isArrayA = isArray(a); | ||
| const isArrayB = isArray(b); | ||
| if (isArrayA && isArrayB) { | ||
| return (a.length === b.length && | ||
| a.every((e, i) => looseEqual(e, b[i]))); | ||
| } | ||
| else if (a instanceof Date && b instanceof Date) { | ||
| return a.getTime() === b.getTime(); | ||
| } | ||
| else if (!isArrayA && !isArrayB) { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| return (keysA.length === keysB.length && | ||
| keysA.every(key => looseEqual(a[key], b[key]))); | ||
| } | ||
| else { | ||
| /* istanbul ignore next */ | ||
| let aValidType = isDate(a); | ||
| let bValidType = isDate(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? a.getTime() === b.getTime() : false; | ||
| } | ||
| aValidType = isArray(a); | ||
| bValidType = isArray(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? looseCompareArrays(a, b) : false; | ||
| } | ||
| aValidType = isObject(a); | ||
| bValidType = isObject(b); | ||
| if (aValidType || bValidType) { | ||
| /* istanbul ignore if: this if will probably never be called */ | ||
| if (!aValidType || !bValidType) { | ||
| return false; | ||
| } | ||
| const aKeysCount = Object.keys(a).length; | ||
| const bKeysCount = Object.keys(b).length; | ||
| if (aKeysCount !== bKeysCount) { | ||
| return false; | ||
| } | ||
| for (const key in a) { | ||
| const aHasKey = a.hasOwnProperty(key); | ||
| const bHasKey = b.hasOwnProperty(key); | ||
| if ((aHasKey && !bHasKey) || | ||
| (!aHasKey && bHasKey) || | ||
| !looseEqual(a[key], b[key])) { | ||
| return false; | ||
| } | ||
| } | ||
| catch (e) { | ||
| /* istanbul ignore next */ | ||
| return false; | ||
| } | ||
| } | ||
| else if (!isObjectA && !isObjectB) { | ||
| return String(a) === String(b); | ||
| } | ||
| else { | ||
| return false; | ||
| } | ||
| return String(a) === String(b); | ||
| } | ||
@@ -383,4 +386,14 @@ function looseIndexOf(arr, val) { | ||
| } | ||
| function looseHas(set, val) { | ||
| for (let item of set) { | ||
| if (looseEqual(item, val)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| // For converting {{ interpolation }} values to displayed strings. | ||
| /** | ||
| * For converting {{ interpolation }} values to displayed strings. | ||
| * @private | ||
| */ | ||
| const toDisplayString = (val) => { | ||
@@ -394,3 +407,3 @@ return val == null | ||
| const replacer = (_key, val) => { | ||
| if (val instanceof Map) { | ||
| if (isMap(val)) { | ||
| return { | ||
@@ -403,3 +416,3 @@ [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { | ||
| } | ||
| else if (val instanceof Set) { | ||
| else if (isSet(val)) { | ||
| return { | ||
@@ -415,2 +428,13 @@ [`Set(${val.size})`]: [...val.values()] | ||
| /** | ||
| * List of @babel/parser plugins that are used for template expression | ||
| * transforms and SFC script transforms. By default we enable proposals slated | ||
| * for ES2020. This will need to be updated as the spec moves forward. | ||
| * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins | ||
| */ | ||
| const babelParserDefaultPlugins = [ | ||
| 'bigInt', | ||
| 'optionalChaining', | ||
| 'nullishCoalescingOperator' | ||
| ]; | ||
| const EMPTY_OBJ = {}; | ||
@@ -425,8 +449,4 @@ const EMPTY_ARR = []; | ||
| const isOn = (key) => onRE.test(key); | ||
| const extend = (a, b) => { | ||
| for (const key in b) { | ||
| a[key] = b[key]; | ||
| } | ||
| return a; | ||
| }; | ||
| const isModelListener = (key) => key.startsWith('onUpdate:'); | ||
| const extend = Object.assign; | ||
| const remove = (arr, el) => { | ||
@@ -441,2 +461,5 @@ const i = arr.indexOf(el); | ||
| const isArray = Array.isArray; | ||
| const isMap = (val) => toTypeString(val) === '[object Map]'; | ||
| const isSet = (val) => toTypeString(val) === '[object Set]'; | ||
| const isDate = (val) => val instanceof Date; | ||
| const isFunction = (val) => typeof val === 'function'; | ||
@@ -455,2 +478,6 @@ const isString = (val) => typeof val === 'string'; | ||
| const isPlainObject = (val) => toTypeString(val) === '[object Object]'; | ||
| const isIntegerKey = (key) => isString(key) && | ||
| key !== 'NaN' && | ||
| key[0] !== '-' && | ||
| '' + parseInt(key, 10) === key; | ||
| const isReservedProp = /*#__PURE__*/ makeMap('key,ref,' + | ||
@@ -468,2 +495,5 @@ 'onVnodeBeforeMount,onVnodeMounted,' + | ||
| const camelizeRE = /-(\w)/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const camelize = cacheStringFunction((str) => { | ||
@@ -473,5 +503,11 @@ return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); | ||
| const hyphenateRE = /\B([A-Z])/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const hyphenate = cacheStringFunction((str) => { | ||
| return str.replace(hyphenateRE, '-$1').toLowerCase(); | ||
| }); | ||
| /** | ||
| * @private | ||
| */ | ||
| const capitalize = cacheStringFunction((str) => { | ||
@@ -490,5 +526,24 @@ return str.charAt(0).toUpperCase() + str.slice(1); | ||
| configurable: true, | ||
| enumerable: false, | ||
| value | ||
| }); | ||
| }; | ||
| const toNumber = (val) => { | ||
| const n = parseFloat(val); | ||
| return isNaN(n) ? val : n; | ||
| }; | ||
| let _globalThis; | ||
| const getGlobalThis = () => { | ||
| return (_globalThis || | ||
| (_globalThis = | ||
| typeof globalThis !== 'undefined' | ||
| ? globalThis | ||
| : typeof self !== 'undefined' | ||
| ? self | ||
| : typeof window !== 'undefined' | ||
| ? window | ||
| : typeof global !== 'undefined' | ||
| ? global | ||
| : {})); | ||
| }; | ||
@@ -500,2 +555,3 @@ exports.EMPTY_ARR = EMPTY_ARR; | ||
| exports.PatchFlagNames = PatchFlagNames; | ||
| exports.babelParserDefaultPlugins = babelParserDefaultPlugins; | ||
| exports.camelize = camelize; | ||
@@ -509,2 +565,3 @@ exports.capitalize = capitalize; | ||
| exports.generateCodeFrame = generateCodeFrame; | ||
| exports.getGlobalThis = getGlobalThis; | ||
| exports.hasChanged = hasChanged; | ||
@@ -516,4 +573,9 @@ exports.hasOwn = hasOwn; | ||
| exports.isBooleanAttr = isBooleanAttr; | ||
| exports.isDate = isDate; | ||
| exports.isFunction = isFunction; | ||
| exports.isGloballyWhitelisted = isGloballyWhitelisted; | ||
| exports.isIntegerKey = isIntegerKey; | ||
| exports.isKnownAttr = isKnownAttr; | ||
| exports.isMap = isMap; | ||
| exports.isModelListener = isModelListener; | ||
| exports.isNoUnitNumericStyleProp = isNoUnitNumericStyleProp; | ||
@@ -526,2 +588,3 @@ exports.isObject = isObject; | ||
| exports.isSSRSafeAttrName = isSSRSafeAttrName; | ||
| exports.isSet = isSet; | ||
| exports.isSpecialBooleanAttr = isSpecialBooleanAttr; | ||
@@ -532,9 +595,9 @@ exports.isString = isString; | ||
| exports.looseEqual = looseEqual; | ||
| exports.looseHas = looseHas; | ||
| exports.looseIndexOf = looseIndexOf; | ||
| exports.makeMap = makeMap; | ||
| exports.mockError = mockError; | ||
| exports.mockWarn = mockWarn; | ||
| exports.normalizeClass = normalizeClass; | ||
| exports.normalizeStyle = normalizeStyle; | ||
| exports.objectToString = objectToString; | ||
| exports.parseStringStyle = parseStringStyle; | ||
| exports.propsToAttrMap = propsToAttrMap; | ||
@@ -545,3 +608,4 @@ exports.remove = remove; | ||
| exports.toDisplayString = toDisplayString; | ||
| exports.toNumber = toNumber; | ||
| exports.toRawType = toRawType; | ||
| exports.toTypeString = toTypeString; |
+94
-8
| /** | ||
| * List of @babel/parser plugins that are used for template expression | ||
| * transforms and SFC script transforms. By default we enable proposals slated | ||
| * for ES2020. This will need to be updated as the spec moves forward. | ||
| * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins | ||
| */ | ||
| export declare const babelParserDefaultPlugins: readonly ["bigInt", "optionalChaining", "nullishCoalescingOperator"]; | ||
| /** | ||
| * @private | ||
| */ | ||
| export declare const camelize: (str: string) => string; | ||
| /** | ||
| * @private | ||
| */ | ||
| export declare const capitalize: (str: string) => string; | ||
| export declare function compareClass(valueA: Array<Number>, valueB: Array<Number>): Boolean; | ||
| export declare function compareClass(valueA: any, valueB: any): Boolean; | ||
@@ -20,6 +34,13 @@ export declare const def: (obj: object, key: string | symbol, value: any) => void; | ||
| export declare const extend: <T extends object, U extends object>(a: T, b: U) => T & U; | ||
| export declare const extend: { | ||
| <T, U>(target: T, source: U): T & U; | ||
| <T_1, U_1, V>(target: T_1, source1: U_1, source2: V): T_1 & U_1 & V; | ||
| <T_2, U_2, V_1, W>(target: T_2, source1: U_2, source2: V_1, source3: W): T_2 & U_2 & V_1 & W; | ||
| (target: object, ...sources: any[]): any; | ||
| }; | ||
| export declare function generateCodeFrame(source: string, start?: number, end?: number): string; | ||
| export declare const getGlobalThis: () => any; | ||
| export declare const hasChanged: (value: any, oldValue: any) => boolean; | ||
@@ -29,2 +50,5 @@ | ||
| /** | ||
| * @private | ||
| */ | ||
| export declare const hyphenate: (str: string) => string; | ||
@@ -36,4 +60,9 @@ | ||
| /** | ||
| * The full list is needed during SSR to produce the correct initial markup. | ||
| */ | ||
| export declare const isBooleanAttr: (key: string) => boolean; | ||
| export declare const isDate: (val: unknown) => val is Date; | ||
| export declare const isFunction: (val: unknown) => val is Function; | ||
@@ -43,2 +72,19 @@ | ||
| export declare const isIntegerKey: (key: unknown) => boolean; | ||
| /** | ||
| * Known attributes, this is used for stringification of runtime static nodes | ||
| * so that we don't stringify bindings that cannot be set from HTML. | ||
| * Don't also forget to allow `data-*` and `aria-*`! | ||
| * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes | ||
| */ | ||
| export declare const isKnownAttr: (key: string) => boolean; | ||
| export declare const isMap: (val: unknown) => val is Map<any, any>; | ||
| export declare const isModelListener: (key: string) => boolean; | ||
| /** | ||
| * CSS properties that accept plain numbers | ||
| */ | ||
| export declare const isNoUnitNumericStyleProp: (key: string) => boolean; | ||
@@ -56,2 +102,4 @@ | ||
| export declare const isSet: (val: unknown) => val is Set<any>; | ||
| export declare const isSpecialBooleanAttr: (key: string) => boolean; | ||
@@ -69,10 +117,15 @@ | ||
| export declare function looseHas(set: Set<any>, val: any): boolean; | ||
| export declare function looseIndexOf(arr: any[], val: any): number; | ||
| /** | ||
| * Make a map and return a function for checking if a key | ||
| * is in that map. | ||
| * IMPORTANT: all calls of this function must be prefixed with | ||
| * \/\*#\_\_PURE\_\_\*\/ | ||
| * So that rollup can tree-shake them if necessary. | ||
| */ | ||
| export declare function makeMap(str: string, expectsLowerCase?: boolean): (key: string) => boolean; | ||
| export declare const mockError: () => void; | ||
| export declare function mockWarn(asError?: boolean): void; | ||
| /** | ||
@@ -87,6 +140,10 @@ * Always return false. | ||
| export declare function normalizeStyle(value: unknown): Record<string, string | number> | undefined; | ||
| export declare type NormalizedStyle = Record<string, string | number>; | ||
| export declare function normalizeStyle(value: unknown): NormalizedStyle | undefined; | ||
| export declare const objectToString: () => string; | ||
| export declare function parseStringStyle(cssText: string): NormalizedStyle; | ||
| export declare const PatchFlagNames: { | ||
@@ -109,2 +166,3 @@ [x: number]: string; | ||
| ACTIVE_CLASS = 2048, | ||
| FOCUSED_CLASS = 4096, | ||
| HOISTED = -1, | ||
@@ -134,6 +192,34 @@ BAIL = -2 | ||
| export declare function stringifyStyle(styles: Record<string, string | number> | undefined): string; | ||
| export declare const enum SlotFlags { | ||
| /** | ||
| * Stable slots that only reference slot props or context state. The slot | ||
| * can fully capture its own dependencies so when passed down the parent won't | ||
| * need to force the child to update. | ||
| */ | ||
| STABLE = 1, | ||
| /** | ||
| * Slots that reference scope variables (v-for or an outer slot prop), or | ||
| * has conditional structure (v-if, v-for). The parent will need to force | ||
| * the child to update because the slot does not fully capture its dependencies. | ||
| */ | ||
| DYNAMIC = 2, | ||
| /** | ||
| * `<slot/>` being forwarded into a child component. Whether the parent needs | ||
| * to update the child is dependent on what kind of slots the parent itself | ||
| * received. This has to be refined at runtime, when the child's vnode | ||
| * is being created (in `normalizeChildren`) | ||
| */ | ||
| FORWARDED = 3 | ||
| } | ||
| export declare function stringifyStyle(styles: NormalizedStyle | undefined): string; | ||
| /** | ||
| * For converting {{ interpolation }} values to displayed strings. | ||
| * @private | ||
| */ | ||
| export declare const toDisplayString: (val: unknown) => string; | ||
| export declare const toNumber: (val: any) => any; | ||
| export declare const toRawType: (value: unknown) => string; | ||
@@ -140,0 +226,0 @@ |
+205
-150
@@ -1,6 +0,8 @@ | ||
| // Make a map and return a function for checking if a key | ||
| // is in that map. | ||
| // | ||
| // IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/ | ||
| // So that rollup can tree-shake them if necessary. | ||
| /** | ||
| * Make a map and return a function for checking if a key | ||
| * is in that map. | ||
| * IMPORTANT: all calls of this function must be prefixed with | ||
| * \/\*#\_\_PURE\_\_\*\/ | ||
| * So that rollup can tree-shake them if necessary. | ||
| */ | ||
| function makeMap(str, expectsLowerCase) { | ||
@@ -63,3 +65,3 @@ const map = Object.create(null); | ||
| const line = j + 1; | ||
| res.push(`${line}${' '.repeat(3 - String(line).length)}| ${lines[j]}`); | ||
| res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`); | ||
| const lineLength = lines[j].length; | ||
@@ -86,99 +88,18 @@ if (j === i) { | ||
| const mockError = () => mockWarn(true); | ||
| function mockWarn(asError = false) { | ||
| expect.extend({ | ||
| toHaveBeenWarned(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls.some(args => args[0].indexOf(received) > -1); | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedLast(received) { | ||
| asserted.add(received); | ||
| const passed = warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1; | ||
| if (passed) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" not to have been warned last.` | ||
| }; | ||
| } | ||
| else { | ||
| const msgs = warn.mock.calls.map(args => args[0]).join('\n - '); | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}` | ||
| }; | ||
| } | ||
| }, | ||
| toHaveBeenWarnedTimes(received, n) { | ||
| asserted.add(received); | ||
| let found = 0; | ||
| warn.mock.calls.forEach(args => { | ||
| if (args[0].indexOf(received) > -1) { | ||
| found++; | ||
| } | ||
| }); | ||
| if (found === n) { | ||
| return { | ||
| pass: true, | ||
| message: () => `expected "${received}" to have been warned ${n} times.` | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| pass: false, | ||
| message: () => `expected "${received}" to have been warned ${n} times but got ${found}.` | ||
| }; | ||
| } | ||
| } | ||
| }); | ||
| let warn; | ||
| const asserted = new Set(); | ||
| beforeEach(() => { | ||
| asserted.clear(); | ||
| warn = jest.spyOn(console, asError ? 'error' : 'warn'); | ||
| warn.mockImplementation(() => { }); | ||
| }); | ||
| afterEach(() => { | ||
| const assertedArray = Array.from(asserted); | ||
| const nonAssertedWarnings = warn.mock.calls | ||
| .map(args => args[0]) | ||
| .filter(received => { | ||
| return !assertedArray.some(assertedMsg => { | ||
| return received.indexOf(assertedMsg) > -1; | ||
| }); | ||
| }); | ||
| warn.mockRestore(); | ||
| if (nonAssertedWarnings.length) { | ||
| nonAssertedWarnings.forEach(warning => { | ||
| console.warn(warning); | ||
| }); | ||
| throw new Error(`test case threw unexpected warnings.`); | ||
| } | ||
| }); | ||
| } | ||
| // On the client we only need to offer special cases for boolean attributes that | ||
| // have different names from their corresponding dom properties: | ||
| // - itemscope -> N/A | ||
| // - allowfullscreen -> allowFullscreen | ||
| // - formnovalidate -> formNoValidate | ||
| // - ismap -> isMap | ||
| // - nomodule -> noModule | ||
| // - novalidate -> noValidate | ||
| // - readonly -> readOnly | ||
| /** | ||
| * On the client we only need to offer special cases for boolean attributes that | ||
| * have different names from their corresponding dom properties: | ||
| * - itemscope -> N/A | ||
| * - allowfullscreen -> allowFullscreen | ||
| * - formnovalidate -> formNoValidate | ||
| * - ismap -> isMap | ||
| * - nomodule -> noModule | ||
| * - novalidate -> noValidate | ||
| * - readonly -> readOnly | ||
| */ | ||
| const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; | ||
| const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); | ||
| // The full list is needed during SSR to produce the correct initial markup. | ||
| /** | ||
| * The full list is needed during SSR to produce the correct initial markup. | ||
| */ | ||
| const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + | ||
@@ -206,3 +127,5 @@ `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + | ||
| }; | ||
| // CSS properties that accept plain numbers | ||
| /** | ||
| * CSS properties that accept plain numbers | ||
| */ | ||
| const isNoUnitNumericStyleProp = /*#__PURE__*/ makeMap(`animation-iteration-count,border-image-outset,border-image-slice,` + | ||
@@ -217,2 +140,23 @@ `border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,` + | ||
| `stroke-miterlimit,stroke-opacity,stroke-width`); | ||
| /** | ||
| * Known attributes, this is used for stringification of runtime static nodes | ||
| * so that we don't stringify bindings that cannot be set from HTML. | ||
| * Don't also forget to allow `data-*` and `aria-*`! | ||
| * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes | ||
| */ | ||
| const isKnownAttr = /*#__PURE__*/ makeMap(`accept,accept-charset,accesskey,action,align,allow,alt,async,` + | ||
| `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` + | ||
| `border,buffered,capture,challenge,charset,checked,cite,class,code,` + | ||
| `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` + | ||
| `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` + | ||
| `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` + | ||
| `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` + | ||
| `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,` + | ||
| `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` + | ||
| `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` + | ||
| `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` + | ||
| `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` + | ||
| `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` + | ||
| `start,step,style,summary,tabindex,target,title,translate,type,usemap,` + | ||
| `value,width,wrap`); | ||
@@ -223,3 +167,4 @@ function normalizeStyle(value) { | ||
| for (let i = 0; i < value.length; i++) { | ||
| const normalized = normalizeStyle(value[i]); | ||
| const item = value[i]; | ||
| const normalized = normalizeStyle(isString(item) ? parseStringStyle(item) : item); | ||
| if (normalized) { | ||
@@ -237,2 +182,14 @@ for (const key in normalized) { | ||
| } | ||
| const listDelimiterRE = /;(?![^(]*\))/g; | ||
| const propertyDelimiterRE = /:(.+)/; | ||
| function parseStringStyle(cssText) { | ||
| const ret = {}; | ||
| cssText.split(listDelimiterRE).forEach(item => { | ||
| if (item) { | ||
| const tmp = item.split(propertyDelimiterRE); | ||
| tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); | ||
| } | ||
| }); | ||
| return ret; | ||
| } | ||
| function stringifyStyle(styles) { | ||
@@ -254,12 +211,51 @@ let ret = ''; | ||
| } | ||
| // wangyan51: 比较class对象 | ||
| // class结构 {s:[], d:[]} | ||
| // 在被merge后会增加ms部分 {s:[], d:[], ms:[]} | ||
| function compareClass(valueA, valueB) { | ||
| if (valueA && valueB && valueA.length === valueB.length) { | ||
| for (let i = 0; i < valueA.length; i++) { | ||
| if (valueA[i] !== valueB[i]) { | ||
| // A不存在 或 B不存在 | ||
| if (!valueA || !valueB) { | ||
| return false; | ||
| } | ||
| // 有数组对象,且长度不为0时才认为是存在 | ||
| // 先比较静态部分 | ||
| let valueAs = valueA.s && valueA.s.length > 0; | ||
| let valueBs = valueB.s && valueB.s.length > 0; | ||
| // 静态部分一个存在一个不存在 或 都存在但不一致 | ||
| if (valueAs != valueBs || (valueAs && valueA.s != valueB.s)) { | ||
| return false; | ||
| } | ||
| // 比较merged静态部分 | ||
| let valueAms = valueA.ms && valueA.ms.length > 0; | ||
| let valueBms = valueB.ms && valueB.ms.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAms != valueBms || (valueAms && valueA.ms.length != valueB.ms.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAms) { | ||
| for (let i = 0; i < valueA.ms.length; i++) { | ||
| if (valueA.ms[i] !== valueB.ms[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| // 比较动态部分 | ||
| let valueAd = valueA.d && valueA.d.length > 0; | ||
| let valueBd = valueB.d && valueB.d.length > 0; | ||
| // 一个存在一个不存在 或 都存在但长度不同 | ||
| if (valueAd != valueBd || (valueAd && valueA.d.length != valueB.d.length)) { | ||
| return false; | ||
| } | ||
| // 都存在且长度相同时,依次比较 | ||
| if (valueAd) { | ||
| for (let i = 0; i < valueA.d.length; i++) { | ||
| if (valueA.d[i] !== valueB.d[i]) { | ||
| // A、B不一致 | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
@@ -279,3 +275,3 @@ function innerNormalizeClass(value, result) { | ||
| function normalizeClass(value) { | ||
| // TODO: 目前动态class和静态class会在编译时merge到一起,normalizeClass时会进行递归处理,后续不再merge时换用更简单的逻辑 | ||
| // TODO: 换用更简单的逻辑 | ||
| let res = []; | ||
@@ -335,40 +331,47 @@ innerNormalizeClass(value, res); | ||
| function looseCompareArrays(a, b) { | ||
| if (a.length !== b.length) | ||
| return false; | ||
| let equal = true; | ||
| for (let i = 0; equal && i < a.length; i++) { | ||
| equal = looseEqual(a[i], b[i]); | ||
| } | ||
| return equal; | ||
| } | ||
| function looseEqual(a, b) { | ||
| if (a === b) | ||
| return true; | ||
| const isObjectA = isObject(a); | ||
| const isObjectB = isObject(b); | ||
| if (isObjectA && isObjectB) { | ||
| try { | ||
| const isArrayA = isArray(a); | ||
| const isArrayB = isArray(b); | ||
| if (isArrayA && isArrayB) { | ||
| return (a.length === b.length && | ||
| a.every((e, i) => looseEqual(e, b[i]))); | ||
| } | ||
| else if (a instanceof Date && b instanceof Date) { | ||
| return a.getTime() === b.getTime(); | ||
| } | ||
| else if (!isArrayA && !isArrayB) { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| return (keysA.length === keysB.length && | ||
| keysA.every(key => looseEqual(a[key], b[key]))); | ||
| } | ||
| else { | ||
| /* istanbul ignore next */ | ||
| let aValidType = isDate(a); | ||
| let bValidType = isDate(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? a.getTime() === b.getTime() : false; | ||
| } | ||
| aValidType = isArray(a); | ||
| bValidType = isArray(b); | ||
| if (aValidType || bValidType) { | ||
| return aValidType && bValidType ? looseCompareArrays(a, b) : false; | ||
| } | ||
| aValidType = isObject(a); | ||
| bValidType = isObject(b); | ||
| if (aValidType || bValidType) { | ||
| /* istanbul ignore if: this if will probably never be called */ | ||
| if (!aValidType || !bValidType) { | ||
| return false; | ||
| } | ||
| const aKeysCount = Object.keys(a).length; | ||
| const bKeysCount = Object.keys(b).length; | ||
| if (aKeysCount !== bKeysCount) { | ||
| return false; | ||
| } | ||
| for (const key in a) { | ||
| const aHasKey = a.hasOwnProperty(key); | ||
| const bHasKey = b.hasOwnProperty(key); | ||
| if ((aHasKey && !bHasKey) || | ||
| (!aHasKey && bHasKey) || | ||
| !looseEqual(a[key], b[key])) { | ||
| return false; | ||
| } | ||
| } | ||
| catch (e) { | ||
| /* istanbul ignore next */ | ||
| return false; | ||
| } | ||
| } | ||
| else if (!isObjectA && !isObjectB) { | ||
| return String(a) === String(b); | ||
| } | ||
| else { | ||
| return false; | ||
| } | ||
| return String(a) === String(b); | ||
| } | ||
@@ -378,4 +381,14 @@ function looseIndexOf(arr, val) { | ||
| } | ||
| function looseHas(set, val) { | ||
| for (let item of set) { | ||
| if (looseEqual(item, val)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| // For converting {{ interpolation }} values to displayed strings. | ||
| /** | ||
| * For converting {{ interpolation }} values to displayed strings. | ||
| * @private | ||
| */ | ||
| const toDisplayString = (val) => { | ||
@@ -389,3 +402,3 @@ return val == null | ||
| const replacer = (_key, val) => { | ||
| if (val instanceof Map) { | ||
| if (isMap(val)) { | ||
| return { | ||
@@ -398,3 +411,3 @@ [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => { | ||
| } | ||
| else if (val instanceof Set) { | ||
| else if (isSet(val)) { | ||
| return { | ||
@@ -410,2 +423,13 @@ [`Set(${val.size})`]: [...val.values()] | ||
| /** | ||
| * List of @babel/parser plugins that are used for template expression | ||
| * transforms and SFC script transforms. By default we enable proposals slated | ||
| * for ES2020. This will need to be updated as the spec moves forward. | ||
| * Full list at https://babeljs.io/docs/en/next/babel-parser#plugins | ||
| */ | ||
| const babelParserDefaultPlugins = [ | ||
| 'bigInt', | ||
| 'optionalChaining', | ||
| 'nullishCoalescingOperator' | ||
| ]; | ||
| const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') | ||
@@ -422,8 +446,4 @@ ? Object.freeze({}) | ||
| const isOn = (key) => onRE.test(key); | ||
| const extend = (a, b) => { | ||
| for (const key in b) { | ||
| a[key] = b[key]; | ||
| } | ||
| return a; | ||
| }; | ||
| const isModelListener = (key) => key.startsWith('onUpdate:'); | ||
| const extend = Object.assign; | ||
| const remove = (arr, el) => { | ||
@@ -438,2 +458,5 @@ const i = arr.indexOf(el); | ||
| const isArray = Array.isArray; | ||
| const isMap = (val) => toTypeString(val) === '[object Map]'; | ||
| const isSet = (val) => toTypeString(val) === '[object Set]'; | ||
| const isDate = (val) => val instanceof Date; | ||
| const isFunction = (val) => typeof val === 'function'; | ||
@@ -452,2 +475,6 @@ const isString = (val) => typeof val === 'string'; | ||
| const isPlainObject = (val) => toTypeString(val) === '[object Object]'; | ||
| const isIntegerKey = (key) => isString(key) && | ||
| key !== 'NaN' && | ||
| key[0] !== '-' && | ||
| '' + parseInt(key, 10) === key; | ||
| const isReservedProp = /*#__PURE__*/ makeMap('key,ref,' + | ||
@@ -465,2 +492,5 @@ 'onVnodeBeforeMount,onVnodeMounted,' + | ||
| const camelizeRE = /-(\w)/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const camelize = cacheStringFunction((str) => { | ||
@@ -470,5 +500,11 @@ return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); | ||
| const hyphenateRE = /\B([A-Z])/g; | ||
| /** | ||
| * @private | ||
| */ | ||
| const hyphenate = cacheStringFunction((str) => { | ||
| return str.replace(hyphenateRE, '-$1').toLowerCase(); | ||
| }); | ||
| /** | ||
| * @private | ||
| */ | ||
| const capitalize = cacheStringFunction((str) => { | ||
@@ -487,6 +523,25 @@ return str.charAt(0).toUpperCase() + str.slice(1); | ||
| configurable: true, | ||
| enumerable: false, | ||
| value | ||
| }); | ||
| }; | ||
| const toNumber = (val) => { | ||
| const n = parseFloat(val); | ||
| return isNaN(n) ? val : n; | ||
| }; | ||
| let _globalThis; | ||
| const getGlobalThis = () => { | ||
| return (_globalThis || | ||
| (_globalThis = | ||
| typeof globalThis !== 'undefined' | ||
| ? globalThis | ||
| : typeof self !== 'undefined' | ||
| ? self | ||
| : typeof window !== 'undefined' | ||
| ? window | ||
| : typeof global !== 'undefined' | ||
| ? global | ||
| : {})); | ||
| }; | ||
| export { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, camelize, capitalize, compareClass, def, escapeHtml, escapeHtmlComment, extend, generateCodeFrame, hasChanged, hasOwn, hyphenate, invokeArrayFns, isArray, isBooleanAttr, isFunction, isGloballyWhitelisted, isNoUnitNumericStyleProp, isObject, isOn, isPlainObject, isPromise, isReservedProp, isSSRSafeAttrName, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, makeMap, mockError, mockWarn, normalizeClass, normalizeStyle, objectToString, propsToAttrMap, remove, setExternGlobals, stringifyStyle, toDisplayString, toRawType, toTypeString }; | ||
| export { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, babelParserDefaultPlugins, camelize, capitalize, compareClass, def, escapeHtml, escapeHtmlComment, extend, generateCodeFrame, getGlobalThis, hasChanged, hasOwn, hyphenate, invokeArrayFns, isArray, isBooleanAttr, isDate, isFunction, isGloballyWhitelisted, isIntegerKey, isKnownAttr, isMap, isModelListener, isNoUnitNumericStyleProp, isObject, isOn, isPlainObject, isPromise, isReservedProp, isSSRSafeAttrName, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseHas, looseIndexOf, makeMap, normalizeClass, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, setExternGlobals, stringifyStyle, toDisplayString, toNumber, toRawType, toTypeString }; |
+3
-2
| { | ||
| "name": "@atom-vue/shared", | ||
| "version": "3.0.1-alpha.1", | ||
| "version": "3.0.1-beta.0", | ||
| "description": "internal utils shared across @vue packages", | ||
@@ -20,3 +20,4 @@ "main": "index.js", | ||
| "type": "git", | ||
| "url": "git+https://github.com/vuejs/vue-next.git" | ||
| "url": "git+https://github.com/vuejs/vue-next.git", | ||
| "directory": "packages/shared" | ||
| }, | ||
@@ -23,0 +24,0 @@ "keywords": [ |
69293
16.84%1829
16.65%