Browse Source

fix(runtime-core): warn about negative number in v-for (#12308)

cyril 3 months ago
parent
commit
9438cc5450

+ 20 - 4
packages/runtime-core/__tests__/helpers/renderList.spec.ts

@@ -29,14 +29,26 @@ describe('renderList', () => {
   })
   })
 
 
   it('should warn when given a non-integer N', () => {
   it('should warn when given a non-integer N', () => {
-    try {
-      renderList(3.1, () => {})
-    } catch (e) {}
+    expect(renderList(3.1, () => {})).toEqual([])
     expect(
     expect(
-      `The v-for range expect an integer value but got 3.1.`,
+      `The v-for range expects a positive integer value but got 3.1.`,
     ).toHaveBeenWarned()
     ).toHaveBeenWarned()
   })
   })
 
 
+  it('should warn when given a negative N', () => {
+    expect(renderList(-1, () => {})).toEqual([])
+    expect(
+      `The v-for range expects a positive integer value but got -1.`,
+    ).toHaveBeenWarned()
+  })
+
+  it('should not warn when given 0', () => {
+    renderList(0, () => {})
+    expect(
+      `The v-for range expects a positive integer value but got 0.`,
+    ).not.toHaveBeenWarned()
+  })
+
   it('should render properties in an object', () => {
   it('should render properties in an object', () => {
     expect(
     expect(
       renderList(
       renderList(
@@ -58,6 +70,10 @@ describe('renderList', () => {
     ).toEqual(['node 0: 1', 'node 1: 2', 'node 2: 3'])
     ).toEqual(['node 0: 1', 'node 1: 2', 'node 2: 3'])
   })
   })
 
 
+  it('should return empty array when source is 0', () => {
+    expect(renderList(0, (item, index) => `node ${index}: ${item}`)).toEqual([])
+  })
+
   it('should return empty array when source is undefined', () => {
   it('should return empty array when source is undefined', () => {
     expect(
     expect(
       renderList(undefined, (item, index) => `node ${index}: ${item}`),
       renderList(undefined, (item, index) => `node ${index}: ${item}`),

+ 10 - 6
packages/runtime-core/src/helpers/renderList.ts

@@ -91,12 +91,16 @@ export function renderList(
       )
       )
     }
     }
   } else if (typeof source === 'number') {
   } else if (typeof source === 'number') {
-    if (__DEV__ && !Number.isInteger(source)) {
-      warn(`The v-for range expect an integer value but got ${source}.`)
-    }
-    ret = new Array(source)
-    for (let i = 0; i < source; i++) {
-      ret[i] = renderItem(i + 1, i, undefined, cached && cached[i])
+    if (__DEV__ && (!Number.isInteger(source) || source < 0)) {
+      warn(
+        `The v-for range expects a positive integer value but got ${source}.`,
+      )
+      ret = []
+    } else {
+      ret = new Array(source)
+      for (let i = 0; i < source; i++) {
+        ret[i] = renderItem(i + 1, i, undefined, cached && cached[i])
+      }
     }
     }
   } else if (isObject(source)) {
   } else if (isObject(source)) {
     if (source[Symbol.iterator as any]) {
     if (source[Symbol.iterator as any]) {

+ 20 - 1
packages/server-renderer/__tests__/ssrRenderList.spec.ts

@@ -27,10 +27,24 @@ describe('ssr: renderList', () => {
   it('should warn when given a non-integer N', () => {
   it('should warn when given a non-integer N', () => {
     ssrRenderList(3.1, () => {})
     ssrRenderList(3.1, () => {})
     expect(
     expect(
-      `The v-for range expect an integer value but got 3.1.`,
+      `The v-for range expects a positive integer value but got 3.1.`,
     ).toHaveBeenWarned()
     ).toHaveBeenWarned()
   })
   })
 
 
+  it('should warn when given a negative N', () => {
+    ssrRenderList(-1, () => {})
+    expect(
+      `The v-for range expects a positive integer value but got -1.`,
+    ).toHaveBeenWarned()
+  })
+
+  it('should not warn when given 0', () => {
+    ssrRenderList(0, () => {})
+    expect(
+      `The v-for range expects a positive integer value but got 0.`,
+    ).not.toHaveBeenWarned()
+  })
+
   it('should render properties in an object', () => {
   it('should render properties in an object', () => {
     ssrRenderList({ a: 1, b: 2, c: 3 }, (item, key, index) =>
     ssrRenderList({ a: 1, b: 2, c: 3 }, (item, key, index) =>
       stack.push(`node ${index}/${key}: ${item}`),
       stack.push(`node ${index}/${key}: ${item}`),
@@ -51,6 +65,11 @@ describe('ssr: renderList', () => {
     expect(stack).toEqual(['node 0: 1', 'node 1: 2', 'node 2: 3'])
     expect(stack).toEqual(['node 0: 1', 'node 1: 2', 'node 2: 3'])
   })
   })
 
 
+  it('should not render items when source is 0', () => {
+    ssrRenderList(0, (item, index) => stack.push(`node ${index}: ${item}`))
+    expect(stack).toEqual([])
+  })
+
   it('should not render items when source is undefined', () => {
   it('should not render items when source is undefined', () => {
     ssrRenderList(undefined, (item, index) =>
     ssrRenderList(undefined, (item, index) =>
       stack.push(`node ${index}: ${item}`),
       stack.push(`node ${index}: ${item}`),

+ 4 - 2
packages/server-renderer/src/helpers/ssrRenderList.ts

@@ -10,8 +10,10 @@ export function ssrRenderList(
       renderItem(source[i], i)
       renderItem(source[i], i)
     }
     }
   } else if (typeof source === 'number') {
   } else if (typeof source === 'number') {
-    if (__DEV__ && !Number.isInteger(source)) {
-      warn(`The v-for range expect an integer value but got ${source}.`)
+    if (__DEV__ && (!Number.isInteger(source) || source < 0)) {
+      warn(
+        `The v-for range expects a positive integer value but got ${source}.`,
+      )
       return
       return
     }
     }
     for (let i = 0; i < source; i++) {
     for (let i = 0; i < source; i++) {