Repository: baianat/vee-validate
Pull request #2029 (2019-04-17 13:49:22)

refactor: tag name (vue best practices), new slots

codecov[bot]: # [Codecov](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=h1) Report
> Merging [#2029](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=desc) into [master](https://codecov.io/gh/baianat/vee-validate/commit/3b762f5a8fe1146a569567efe15afc27ddfb9ad8?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/baianat/vee-validate/pull/2029/graphs/tree.svg?width=650&token=XFzlvHKFP5&height=150&src=pr)](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #2029   +/-   ##
=======================================
  Coverage   96.01%   96.01%           
=======================================
  Files          62       62           
  Lines        2356     2356           
  Branches      736      736           
=======================================
  Hits         2262     2262           
  Misses         85       85           
  Partials        9        9
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=footer). Last update [3b762f5...99a80be](https://codecov.io/gh/baianat/vee-validate/pull/2029?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index 96fdadcc..54543c53 100644
--- a/README.md
+++ b/README.md
@@ -88,13 +88,26 @@ export default {
 
 All the JavaScript work is done. Next in the template add the inputs you want to validate them:
 
+**With Vue 2.6.0+**
+
+```vue
+<validation-provider name="email" rules="required|email">
+  <template #default="{ errors }">
+    <input v-model="email">
+    <p>{{ errors[0] }}</p>
+  </template>
+</validation-provider>
+```
+
+**Before Vue 2.6.0**
+
 ```vue
-<ValidationProvider name="email" rules="required|email">
+<validation-provider name="email" rules="required|email">
   <div slot-scope="{ errors }">
     <input v-model="email">
     <p>{{ errors[0] }}</p>
   </div>
-</ValidationProvider>
+</validation-provider>
 ```
 
 The validation provider accepts two props: `rules` which is in its simplest form, a string containing the validation rules separated by a `|` character, and a `name` prop which is the field name that will be used in error messages.
diff --git a/locale/ar.js b/locale/ar.js
index 5e895296..eec09297 100644
--- a/locale/ar.js
+++ b/locale/ar.js
@@ -29,7 +29,7 @@ const messages = {
   decimal: (field, [decimals = '*'] = []) => `${field} يجب ان يكون قيمة رقمية وقد يحتوي على${decimals === '*' ? '' : ' ' + decimals} ارقام عشرية.`,
   digits: (field, [length]) => `${field} يجب ان تحتوي فقط على ارقام والا يزيد عددها عن ${length} رقم.`,
   dimensions: (field, [width, height]) => `${field} يجب ان تكون بمقاس ${width} بكسل في ${height} بكسل.`,
-  email: (field) => `${field} يجب ان يكون بريدا اليكتروني صحيح.`,
+  email: (field) => `${field} يجب ان يكون بريداً اليكتروناً صحيحاً.`,
   excluded: (field) => `الحقل ${field} غير صحيح.`,
   ext: (field) => `نوع ملف ${field} غير صحيح.`,
   image: (field) => `${field} يجب ان تكون صورة.`,
diff --git a/src/rules/dimensions.js b/src/rules/dimensions.js
index 3506a42f..d3e937cf 100644
--- a/src/rules/dimensions.js
+++ b/src/rules/dimensions.js
@@ -1,3 +1,7 @@
+import { ensureArray } from '../utils';
+
+const imageRegex = /\.(jpg|svg|jpeg|png|bmp|gif)$/i;
+
 const validateImage = (file, width, height) => {
   const URL = window.URL || window.webkitURL;
   return new Promise(resolve => {
@@ -12,17 +16,11 @@ const validateImage = (file, width, height) => {
 };
 
 const validate = (files, [width, height]) => {
-  const list = [];
-  for (let i = 0; i < files.length; i++) {
-    // if file is not an image, reject.
-    if (! /\.(jpg|svg|jpeg|png|bmp|gif)$/i.test(files[i].name)) {
-      return false;
-    }
-
-    list.push(files[i]);
+  const images = ensureArray(files).filter(file => imageRegex.test(file.name));
+  if (images.length === 0) {
+    return false;
   }
-
-  return Promise.all(list.map(file => validateImage(file, width, height)));
+  return Promise.all(images.map(image => validateImage(image, width, height)));
 };
 
 export {
diff --git a/src/rules/ext.js b/src/rules/ext.js
index c886cb45..a5ebde7a 100644
--- a/src/rules/ext.js
+++ b/src/rules/ext.js
@@ -1,7 +1,8 @@
+import { ensureArray } from '../utils';
+
 const validate = (files, extensions) => {
   const regex = new RegExp(`.(${extensions.join('|')})$`, 'i');
-
-  return files.every(file => regex.test(file.name));
+  return ensureArray(files).every(file => regex.test(file.name));
 };
 
 export {
diff --git a/src/rules/image.js b/src/rules/image.js
index 4b7fbd83..1023a44a 100644
--- a/src/rules/image.js
+++ b/src/rules/image.js
@@ -1,4 +1,4 @@
-const validate = (files) => files.every(file => /\.(jpg|svg|jpeg|png|bmp|gif)$/i.test(file.name));
+const validate = (files) => (Array.isArray(files) ? files : [files]).every(file => /\.(jpg|svg|jpeg|png|bmp|gif)$/i.test(file.name));
 
 export {
   validate
diff --git a/src/rules/mimes.js b/src/rules/mimes.js
index c1201d3a..d3d555fa 100644
--- a/src/rules/mimes.js
+++ b/src/rules/mimes.js
@@ -1,7 +1,8 @@
+import { ensureArray } from '../utils';
+
 const validate = (files, mimes) => {
   const regex = new RegExp(`${mimes.join('|').replace('*', '.+')}$`, 'i');
-
-  return files.every(file => regex.test(file.type));
+  return ensureArray(files).every(file => regex.test(file.type));
 };
 
 export {
diff --git a/src/rules/size.js b/src/rules/size.js
index 0d26f230..67a80439 100644
--- a/src/rules/size.js
+++ b/src/rules/size.js
@@ -1,16 +1,11 @@
+import { ensureArray } from '../utils';
+
 const validate = (files, [size]) => {
   if (isNaN(size)) {
     return false;
   }
-
   const nSize = Number(size) * 1024;
-  for (let i = 0; i < files.length; i++) {
-    if (files[i].size > nSize) {
-      return false;
-    }
-  }
-
-  return true;
+  return ensureArray(files).every(file => file.size <= nSize);
 };
 
 export {
diff --git a/src/utils/index.js b/src/utils/index.js
index 9ec885f7..3da38e49 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -380,6 +380,17 @@ export const toArray = (arrayLike: { length: number }) => {
   return array;
 };
 
+/**
+ * Converts an array-like object to array and place other elements in an array
+ */
+export const ensureArray = (arrayLike: any): array => {
+  if (Array.isArray(arrayLike)) {
+    return [...arrayLike];
+  }
+  const array = toArray(arrayLike);
+  return isEmptyArray(array) ? [arrayLike] : array;
+};
+
 /**
  * Assign polyfill from the mdn.
  */


Test patch:
diff --git a/tests/helpers/index.js b/tests/helpers/index.js
index 8799a4ed..ba580763 100644
--- a/tests/helpers/index.js
+++ b/tests/helpers/index.js
@@ -44,9 +44,10 @@ export default {
       }
     };
   },
-  file: (name, type, size = 1) => ({
-    name,
-    type,
-    size: size * 1024
+  file: (name, type, size = 1) => new File([new ArrayBuffer(size * 1024)], name, { type }),
+  fileList: (files) => ({
+    length: files.length,
+    item: (index) => files[index],
+    ...files
   })
 };
diff --git a/tests/unit/utils.js b/tests/unit/utils.js
index 2ae9cbc4..53cc55f9 100644
--- a/tests/unit/utils.js
+++ b/tests/unit/utils.js
@@ -2,6 +2,7 @@ import * as utils from '@/utils';
 import * as dateUtils from '@/utils/date';
 import * as i18Utils from '../../locale/utils';
 import * as eventUtils from '@/utils/events';
+import helpers from '../helpers';
 
 test('gets the data attribute prefixed with the plugin', () => {
   document.body.innerHTML =
@@ -198,6 +199,17 @@ test('converts array like objects to arrays', () => {
   expect(Array.isArray(array)).toBe(true);
 });
 
+test('converts file list or single file to array of files', () => {
+  const file = helpers.file('file.jpg', 'image/jpeg', 10);
+  expect(Array.isArray(file)).toBe(false);
+
+  const fileList = helpers.fileList([file]);
+  expect(Array.isArray(fileList)).toBe(false);
+
+  expect(Array.isArray(utils.ensureArray(file))).toBe(true);
+  expect(Array.isArray(utils.ensureArray(fileList))).toBe(true);
+});
+
 test('checks if a value path with exists', () => {
   const some = {
     value: {