]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(shared): support Map and Set in toDisplayString
authorEvan You <yyx990803@gmail.com>
Mon, 4 May 2020 14:38:03 +0000 (10:38 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 4 May 2020 14:38:03 +0000 (10:38 -0400)
close #1067, close #1100

packages/shared/__tests__/toDisplayString.spec.ts [new file with mode: 0644]
packages/shared/src/index.ts
packages/shared/src/toDisplayString.ts [new file with mode: 0644]

diff --git a/packages/shared/__tests__/toDisplayString.spec.ts b/packages/shared/__tests__/toDisplayString.spec.ts
new file mode 100644 (file)
index 0000000..a998904
--- /dev/null
@@ -0,0 +1,107 @@
+import { toDisplayString } from '../src'
+
+describe('toDisplayString', () => {
+  test('nullish values', () => {
+    expect(toDisplayString(null)).toBe('')
+    expect(toDisplayString(undefined)).toBe('')
+  })
+
+  test('primitive values', () => {
+    expect(toDisplayString(1)).toBe('1')
+    expect(toDisplayString(true)).toBe('true')
+    expect(toDisplayString(false)).toBe('false')
+    expect(toDisplayString('hello')).toBe('hello')
+  })
+
+  test('Object and Arrays', () => {
+    const obj = { foo: 123 }
+    expect(toDisplayString(obj)).toBe(JSON.stringify(obj, null, 2))
+    const arr = [obj]
+    expect(toDisplayString(arr)).toBe(JSON.stringify(arr, null, 2))
+  })
+
+  test('native objects', () => {
+    const div = document.createElement('div')
+    expect(toDisplayString(div)).toBe(`"[object HTMLDivElement]"`)
+    expect(toDisplayString({ div })).toMatchInlineSnapshot(`
+      "{
+        \\"div\\": \\"[object HTMLDivElement]\\"
+      }"
+    `)
+  })
+
+  test('Map and Set', () => {
+    const m = new Map<any, any>([
+      [1, 'foo'],
+      [{ baz: 1 }, { foo: 'bar', qux: 2 }]
+    ])
+    const s = new Set<any>([1, { foo: 'bar' }, m])
+
+    expect(toDisplayString(m)).toMatchInlineSnapshot(`
+      "{
+        \\"Map(2)\\": {
+          \\"1 =>\\": \\"foo\\",
+          \\"[object Object] =>\\": {
+            \\"foo\\": \\"bar\\",
+            \\"qux\\": 2
+          }
+        }
+      }"
+    `)
+    expect(toDisplayString(s)).toMatchInlineSnapshot(`
+      "{
+        \\"Set(3)\\": [
+          1,
+          {
+            \\"foo\\": \\"bar\\"
+          },
+          {
+            \\"Map(2)\\": {
+              \\"1 =>\\": \\"foo\\",
+              \\"[object Object] =>\\": {
+                \\"foo\\": \\"bar\\",
+                \\"qux\\": 2
+              }
+            }
+          }
+        ]
+      }"
+    `)
+
+    expect(
+      toDisplayString({
+        m,
+        s
+      })
+    ).toMatchInlineSnapshot(`
+      "{
+        \\"m\\": {
+          \\"Map(2)\\": {
+            \\"1 =>\\": \\"foo\\",
+            \\"[object Object] =>\\": {
+              \\"foo\\": \\"bar\\",
+              \\"qux\\": 2
+            }
+          }
+        },
+        \\"s\\": {
+          \\"Set(3)\\": [
+            1,
+            {
+              \\"foo\\": \\"bar\\"
+            },
+            {
+              \\"Map(2)\\": {
+                \\"1 =>\\": \\"foo\\",
+                \\"[object Object] =>\\": {
+                  \\"foo\\": \\"bar\\",
+                  \\"qux\\": 2
+                }
+              }
+            }
+          ]
+        }
+      }"
+    `)
+  })
+})
index c679dfe6d11033ddd0d0c267bd1b3a87e133d4d9..066132c8a9a013341012cf9ff403811f2b89548a 100644 (file)
@@ -11,6 +11,7 @@ export * from './domTagConfig'
 export * from './domAttrConfig'
 export * from './escapeHtml'
 export * from './looseEqual'
+export * from './toDisplayString'
 
 export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
   ? Object.freeze({})
@@ -112,15 +113,6 @@ export const capitalize = cacheStringFunction(
 export const hasChanged = (value: any, oldValue: any): boolean =>
   value !== oldValue && (value === value || oldValue === oldValue)
 
-// For converting {{ interpolation }} values to displayed strings.
-export const toDisplayString = (val: unknown): string => {
-  return val == null
-    ? ''
-    : isArray(val) || (isPlainObject(val) && val.toString === objectToString)
-      ? JSON.stringify(val, null, 2)
-      : String(val)
-}
-
 export const invokeArrayFns = (fns: Function[], arg?: any) => {
   for (let i = 0; i < fns.length; i++) {
     fns[i](arg)
diff --git a/packages/shared/src/toDisplayString.ts b/packages/shared/src/toDisplayString.ts
new file mode 100644 (file)
index 0000000..bd19cdd
--- /dev/null
@@ -0,0 +1,28 @@
+import { isArray, isObject, isPlainObject } from './index'
+
+// For converting {{ interpolation }} values to displayed strings.
+export const toDisplayString = (val: unknown): string => {
+  return val == null
+    ? ''
+    : isObject(val)
+      ? JSON.stringify(val, replacer, 2)
+      : String(val)
+}
+
+const replacer = (_key: string, val: any) => {
+  if (val instanceof Map) {
+    return {
+      [`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => {
+        ;(entries as any)[`${key} =>`] = val
+        return entries
+      }, {})
+    }
+  } else if (val instanceof Set) {
+    return {
+      [`Set(${val.size})`]: [...val.values()]
+    }
+  } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {
+    return String(val)
+  }
+  return val
+}