Skip to content

Commit

Permalink
feat: 🎉 optimize some logic of util
Browse files Browse the repository at this point in the history
  • Loading branch information
chantouchsek committed May 18, 2023
1 parent 0bb4ef1 commit ad4fd10
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 59 deletions.
5 changes: 1 addition & 4 deletions src/__tests__/object.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { hasFiles, hasOwnProperty, isFile } from '../util'
import { hasFiles, isFile } from '../util'

describe('Object Test', () => {
// const { window, File } = global
Expand All @@ -10,9 +10,6 @@ describe('Object Test', () => {
const file = new File(['hello world!'], 'myfile')
expect(isFile(file)).toBeTruthy()
})
it('should check has own property', function () {
expect(hasOwnProperty({ dev: null }, '')).toBeFalsy()
})
it('check if window is undefined', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Expand Down
21 changes: 11 additions & 10 deletions src/core/BaseService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AxiosError, AxiosInstance, Method, AxiosRequestConfig, AxiosResponse } from 'axios'
import type { IParseOptions } from 'qs'
import { isObject, isArray } from 'lodash'
import { isObject } from 'lodash'
import qs from 'qs'
import Validator from './Validator'
import { hasFiles, objectToFormData } from '../util'
Expand Down Expand Up @@ -86,11 +86,12 @@ export default class BaseService {
$submit<T = any, F = any>(method: Method, param?: string | number, form?: F, config?: AxiosRequestConfig) {
this.beforeSubmit()
return new Promise<AxiosResponse<T>>((resolve, reject) => {
const data = hasFiles(form) ? objectToFormData(form) : form
const endpoint = param ? `/${this.endpoint}/${param}` : `/${this.endpoint}`
const url = this.__getParameterString(endpoint.replace(/\/\//g, '/'))
config = Object.assign({}, config, { url, data, method })
this.$http(config)
const formData = hasFiles(form) ? objectToFormData(form) : form
const endpointPath = param ? `/${this.endpoint}/${param}` : `/${this.endpoint}`
const endpoint = endpointPath.replace(/\/\//g, '/')
const url = this.__getParameterString(endpoint)
const axiosConfig = { url, data: formData, method, ...config }
this.$http(axiosConfig)
.then((response) => {
this.onSuccess()
resolve(response)
Expand All @@ -101,9 +102,9 @@ export default class BaseService {
const { response } = error
if (response && response.status === UNPROCESSABLE_ENTITY) {
const { data } = response
const errors: Record<string, any> = {}
Object.assign(errors, data[this.$errorProperty])
this.onFail(errors)
const validationErrors: Record<string, any> = {}
Object.assign(validationErrors, data[this.$errorProperty])
this.onFail(validationErrors)
}
reject(error)
})
Expand Down Expand Up @@ -148,7 +149,7 @@ export default class BaseService {
removeParameters(parameters: string[] = []) {
if (!parameters || !parameters.length) {
this.parameters = {}
} else if (isArray(parameters)) {
} else if (Array.isArray(parameters)) {
for (const parameter of parameters) delete this.parameters[parameter]
}
return this
Expand Down
2 changes: 1 addition & 1 deletion src/core/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class Validator {
}

fields(field: string | string[]): string[] {
const fields = []
const fields: string[] = []
if (Array.isArray(field)) {
for (const f of field) {
fields.push(toCamelCase(f), toSnakeCase(f))
Expand Down
40 changes: 18 additions & 22 deletions src/util/formData.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { hasOwnProperty, isArray, isFile } from './objects'
import { isFile } from './objects'

const getKey = (parent: any, property: any) => (parent ? parent + '[' + property + ']' : property)
export function objectToFormData(obj: any, formData = new FormData(), parent = ''): FormData {
if (obj === null || obj === 'undefined' || obj.length === 0) {
if (obj == null || (Array.isArray(obj) && obj.length === 0)) {
formData.append(parent, obj)
} else {
for (const property in obj) {
if (hasOwnProperty(obj, property)) {
appendToFormData(formData, getKey(parent, property), obj[property])
}
const propertyMap = new Map(Object.entries(obj))
for (const [property, value] of propertyMap) {
const key = parent ? `${parent}[${property}]` : property
appendToFormData(formData, key, value)
}
}
return formData
Expand All @@ -19,37 +18,34 @@ function appendToFormData(formData: FormData, key: string, value: any) {
if (typeof value === 'boolean') return formData.append(key, value ? '1' : '0')
if (value === null) return formData.append(key, '')
if (typeof value !== 'object') return formData.append(key, value)
if (isArray(value) && hasFilesDeep(value)) {
if (Array.isArray(value) && hasFilesDeep(value)) {
for (let i = 0; i < value.length; i++) {
formData.append(key + '[' + i + ']', value[i], value[i].name)
}
return formData
}
objectToFormData(value, formData, key)
if (typeof value === 'object') return objectToFormData(value, formData, key)
throw new Error(`Unexpected value type: ${typeof value}`)
}
export function hasFilesDeep(obj: any): boolean {
if (obj === null) return false
if (typeof obj === 'object') {
for (const key in obj) {
if (isFile(obj[key])) return true
const values = Object.values(obj)
for (let i = 0; i < values.length; i++) {
if (isFile(values[i])) return true
}
}
if (isArray(obj)) {
let f = ''
for (const key in obj) {
if (hasOwnProperty(obj, key)) {
f = key
break
}
}
return hasFilesDeep(obj[f])
if (Array.isArray(obj)) {
const firstNonNullElement = obj.find((el) => el !== null)
return firstNonNullElement ? hasFilesDeep(firstNonNullElement) : false
}
return isFile(obj)
}
export function hasFiles(form: any) {
for (const prop in form) {
const hasProp = hasOwnProperty(form, prop) || typeof window !== 'undefined'
if (hasProp && hasFilesDeep(form[prop])) return true
if (Object.prototype.hasOwnProperty.call(form, prop) && hasFilesDeep(form[prop])) {
return true
}
}
return false
}
17 changes: 2 additions & 15 deletions src/util/objects.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
export function isArray(object: any): boolean {
return Object.prototype.toString.call(object) === '[object Array]'
}

export function hasOwnProperty(obj: any, key: any) {
if (!obj || !key) return false
return Object.prototype.hasOwnProperty.call(obj, key)
}

export function isFile(object: any): boolean {
if (typeof window === 'undefined' || typeof File !== 'function' || typeof FileList !== 'function') {
return false
}
return object instanceof File || object instanceof FileList
}

export function is(errors: any, error: any): boolean {
return isArray(error) ? error.some((w: string) => is(errors, w)) : errors.includes(error)
export function is(errors: string[], errorsToCheck: string[] | string): boolean {
return Array.isArray(errorsToCheck) ? errorsToCheck.some((w) => is(errors, w)) : errors.includes(errorsToCheck)
}
9 changes: 2 additions & 7 deletions src/util/string.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
export const toCamelCase = (e: string) => {
return e.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
}
export const toSnakeCase = (e: string) => {
if (!e.match(/([A-Z])/g)) return e
return e.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
}
export const toCamelCase = (e: string) => e.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
export const toSnakeCase = (e: string) => (e.match(/([A-Z])/g) ? e.replace(/[A-Z]/g, (l) => `_${l.toLowerCase()}`) : e)

0 comments on commit ad4fd10

Please sign in to comment.