UNPKG

@fishertsau/moonlight

Version:

Various helpers or lib for javascript projects

783 lines (624 loc) 17.9 kB
# moonlight - 提供JavaScript常用的功能,類似helper或是utility,讓javascript專案使用 - 可用於Server-side專案,如node.js,或是Client-side專案,如vue,react中 - 發佈於npm中,使用時當作一個package使用 - 可用於es6與commonjs中 ## Main functions 1. Validator 2. time 3. array 4. hostname 5. Checker 6. Utils 7. MoonUse 8. Model ### Input Validator - check the input validity with specified rules - only the validated attribute(s) are returned - convert data type on validating, e.g '100' to 100 for 'type:number' - rules - required - type:[string|date|datetime|isoDatetime|number|email|bool|boolean|null|nonEmptyString|object] - same:attributeName - validator:: obj -> obj -> obj - examples ```javascript const rules = { foo: 'required|type:null', // null boo: 'type:bool', // true, false, 'true', 'false' boo: 'type:boolean', // true, false, 'true', 'false' // string moo: 'type:string', // string moo: 'required|type:emptyString', // '' moo: 'required|type:nonEmptyString', // non empty string moo: 'required|type:lowerCaseOrNumberString', // lower case or number string (e.g. 'abc123') moo: 'required|type:isNumberString', // number string (e.g. '123') // object boo: 'type:object', // object boo: 'type:emptyObject', // {} // same content bar: 'required|same:foo', // valid values loo: 'validValues:[v1,v2,v3]', aoo: 'type:array', // array aoo: 'type:emptyArray', // [] aoo: 'type:arrayOfString', // ['a','b'] aoo: 'type:arrayOfInt', // [1,2] aoo: 'type:arrayOfNull', // [null, null] // multiple types soo: 'type:[number,null,nonEmptyString]', // number, null, non empty string // number & integer foo: 'required|type:number', // number (e.g. 1.2) aoo: 'type:int', // integer (e.g. 1) aoo: 'type:positiveInt', // > 0 aoo: 'type:positiveNum', // > 0 aoo: 'type:positiveNumWithZero', // >= 0 // date & datetime too: 'type:datetime', // yyyy-mm-dd hh:mm:ss (e.g. '2000-01-01 12:00:00') too: 'type:isoDatetime', // yyyy-mm-ddThh:mm:ss+08:00 (e.g. '2000-01-01T12:00:00+08:00') too: 'type:date', // yyyy-mm-dd (e.g. '2000-01-01') too: 'type:yearMonthDay', // {year:1, month: 1, day: 1} // application type foo:'type:twInvoiceDonationOrgCode', // 愛心碼 Taiwan invoice donation code 3 至 7 位數字 (e.g. '12345') // credit card foo: 'type:creditCardNum', // credit card number (e.g. '1234567890123456') foo: 'type:creditCardCvvCvc', // credit card cvv/cvc (e.g. '123') foo: 'type:creditCardExpDate', // credit card expiration date (e.g. '01/23') // length: same length foo: 'sameLengthArr:bar', // same length as bar (e.g. '123' and 'abc') foo: 'minLen:3', // min length (e.g. '123') foo: 'maxLen:5', // max length (e.g. '12345') // range foo: 'range:1,10', // 1 <= foo <= 10 (for int only) // requiredWhenExists foo: 'requiredWhenExists:boo', // required when boo is not empty (e.g. 'foo' is required when 'boo' is not empty) foo: 'requiredIfValueIs:bar:1', // required when bar is 1 (e.g. 'foo' is required when 'bar' is 1) // requiredIfValueIs foo: 'requiredIfValueIs:bar:true', // required when bar is true (e.g. 'foo' is required when 'bar' is 1) foo: 'requiredIfValueIs:bar:10', // required when bar is 10 (e.g. 'foo' is required when 'bar' is 10) // regex foo: 'regex:/^\\d{3}-\\d{3}-\\d{4}$/', // regex (e.g. '123-456-7890') foo: 'regex:/^\\d+$/', // numbers only (e.g. '1234567890') // app types koo: 'type:email', // email koo: 'type:hostname', // hostname (e.g. 'www.google.com') koo: 'type:hostnameWithPath', // hostname with path (e.g. 'www.google.com/path') koo: 'type:lineId', // line id (e.g. 'U1234567890abcdef1234567890abcdef') koo: 'type:twTaxId', // Taiwan tax id (8 digits) (e.g. '12345678') koo: 'type:twMobileNo', // Taiwan mobile number (10 digits) (e.g. '0912345678') koo: 'type:twLandPhoneNo', // Taiwan land phone number (9 digits) (e.g. '022345678') koo: 'type:addressWithDefault', // address with default value (e.g. {city:1, area:1, street:'abc'}) }; const validatedData = { foo: 123, bar: 123, koo: '2000-01-01', loo: 'invalidValue', moo: '', aoo:'notArray'}; let result = validator(rules)(validatedData); // => { validated: true , values:{foo:123, bar:123,koo:'2000-01-01'}} // => { validated: false , // errors: { // foo: ['foo should be a number.'], // koo: ['koo should be a string.'] // loo: ['loo should be in one of the values: v1,v2,v3.'] // moo: ['moo should be an non empty string.'] // aoo: ['aoo should be in array format.'] // } // } ``` ### time - now :: null -> DateTime ```javascript now(); //=> current time ``` - isoStrToUtcStr:: isoDatetimeString -> utcDatetimeString ```javascript isoStrToUtcStr('1997-07-16T19:20:35+03:00'); //=> '1997-07-16 16:20:35' ``` - isoStrToTaipeiStr :: isoDatetimeString -> taipeiDatetimeString ```javascript isoStrToTaipeiStr('1997-07-16T19:20:35+03:00'); // utc: 1997-07-16T16:20:35 //=> '1997-07-17 00:20:35' ``` ```js { // base Dayjs, now, // string to object toTimeObj, fromIsoTimeStrToObj, fromTimeStrAtTZ, fromTpeTimeStr, // datetime string utcDatetimeStrNow, // 2000-01-01 12:00:00 isoStrNow, // string to string isoStrToUtcStr, // 2000-01-01T12:00:00.000Z -> 2000-01-01 12:00:00 utcStrToIsoStr, isoStrToTaipeiStr, // 2000-01-01T12:00:00.000Z -> 2000-01-01 20:00:00 datetimeStrToDateStr, // 2000-01-01 12:00:00 -> 2000-01-01 isoStrToTpeDateStr, // 2000-01-01T12:00:00.000Z -> 2000-01-01 // date|datetime string dateAtTZ, todayStartInTpeStr, todayEndInTpeStr, todayEndInIsoStr, todayInTpeStrDateOnly, // time obj todayStartInTpe, todayEndInTpe, // type check isIsoFormat, // time zone TZ, TZ_TYPE, // comparison isBefore, isAfter, isBetween, isSame, // duration getDuration, // status getStatusByTimeFrame, STATUS_BY_TIME_FRAME, REF_TIME_STATUS_TYPE, // time manipulation minAgoFromNow } ``` ### array - shuffle :: array -> array - re-order the array items randomly ### hostname - isValidHostname :: String -> Boolean - To validate a give hostname ### Checker ``` isTrue, isEmpty, isValidBool, isFunction, isUndefined, // object isObject, isEmptyObject, // string isString, isNonEmptyString, isNumberString, isEmptyString, isLowerCaseOrNumberString, isNumberOrString, isNumberOrNumberString, // number isIntBetween, isNumber, isValidInteger, isPositiveInteger, isUnsignedInteger, isSameNumOrNumStr, // number format ifOnlyNumberAndLetter, ifHexNumberStr, ifDecimalNumberStr, // time isYMDStr, isDatetimeStr, isIsoFormat, isIsoFormatWithZeroOffset, // array isArray, isEmptyArray, isNonEmptyArray, isArrayOfString, isArrayOfInt, isArrayOfArray, // [[], []] isArrayOfNumber, isArrayOfNull, // application isValidLineId, isValidEmail, isValidTwTaxId, isValidTwMobileNo, isValidTwLandPhoneNo, isValidTwNationalId, isValidTwInvoiceDonationCode, isValidTwMobileInvoiceBarcode, isValidCreditCardNum, isValidCreditCardCvvCvc, isValidCreditCardExpDate, isValidHostname, isValidHostnameWithPath, ``` - isTrue :: a -> boolean - To check if a given value is true - isEmpty :: a -> boolean - To check is a given value is empty - isIntBetween:: int a -> int b -> int c -> boolean - To check is a given int or value is between the specified range - isNumber:: a -> boolean - To check is given value is a number - isString:: a -> boolean - To check is given value is a string - isObject:: a -> boolean - To check is given value is an object - null and array are excluded - isValidEmail:: a -> boolean - To check is given value is a valid email - isValidBool:: a -> boolean - To check is given value is a valid boolean value - isFunction:: a -> boolean - To check is given value a Function - isValidHostname:: a -> boolean - To check if a given value a valid hostname - isYMDStr:: str a -> boolean - To check is given string is in date format - valid date format: yyyy-mm-dd (time is not included) - isDateTime:: str a -> boolean - To check is given string is in datetime format - valid datetime format includes: unix time (integer), date+time, UTC - isIsoFormat:: a -> boolean - To check is given value is in ISO 8601 format - isIsoFormatWithZeroOffset:: a -> boolean - To check is given value is in ISO 8601 format with zero offset ### Utils - clearSpace:: string -> string - To clear or remove space in a string - trim - To trim the string(s) in object properties and values - To trim string(s) in list - Can trim string(s) in nested objects or nested array ```js trim({ 'p1 ': 'foo ', p2: [' abc', ' def '], p3: { p3_1: ['p31 '] }, p4: { p4_1: ['p41 ', ' p42'], 'p4_2': {} }, p5: 100, }); //=> { p1: 'foo', p2: ['abc', 'def'], p3: { p3_1: ['p31'] }, p4: { p4_1: ['p41', 'p42'], 'p4_2' : {} }, p5: 100, } ``` - extractByPath - To extract a value from a structured collection object - Object structure ```javascript { k1: { k1a: {} k1b: {} }, k2: { k2a: {} k2b: {} } } ``` - example: ```javascript extractByPath(['info', 'age'])({'person1':{info:{age:10}}, 'person2':{info:{age:20}}}); //=> {'person1':10, 'person2':20} ``` - getDirty - To get the values in new object which differ from that in the original object - The function is auto-curry - example: ```javascript oriObj = {a:1, b:3} newObj = {a:1, b:5, c:7} getDirty(oriObj)(newObj); //=> {b:5, c:7} ``` - renameKey - To change a key name - example: ```javascript oriObj = {foo:1} renameKey('foo','bar')(oriObj); //=> {bar:1} ``` - createEventEmitter - To create an event emitter - example: ```javascript const em = createEventEmitter(); // register event handler em.on('someEvent', someHandler); // remove event handler // A. remove specific handler em.remove('someEvent', someHandler); // B. remove all handlers em.remove('someEvent'); // send out event em.emit('someEvent', payload); ``` - pluckObjProp - To pluck a nested obj prop - example: ```javascript // Functor f => k -> {k:v} -> {k:v} const obj = { prop1: { foo: 123, bar: 'abc' }, prop2: { foo: 999, bar: 'abc' } } pluckObjProp('foo')(obj) //=> {prop1: 123, prop2: 999} ``` - clean - To remove obj props if value is undefined/null/emptyString - Applicable to nested object ```javascript clean({ foo: 123, bar: undefined, koo: { k1: 'abc', k2: undefined, }, poo: null, moo: '', }) //=> { foo: 123, koo: { k1:'abc'} } ``` - cleanNilUndefined - To remove obj props if value is undefined/null - Applicable to nested object ```javascript clean({ foo: 123, bar: undefined, koo: { k1: 'abc', k2: undefined, }, poo: null, moo: '', }) //=> { foo: 123, koo: { k1:'abc'} moo: '' } ``` - hasValue - To check if an object has specified value - Applicable to simple object ```javascript hasValue(123, { foo: 123 }) //=> true hasValue('abc', { foo: 123 }) //=> false ``` - rmArrSquareInReqParamsKey ```javascript harmArrSquareInReqParamsKeys( { from: 0, 'ids[]': [ 'abc1705548556993', 'abc1705558802725'] }); //=> { from: 0, 'ids': [ 'abc1705548556993' , 'abc1705558802725'] }; ``` - getObjectDifference ```js const obj1 = { a: 1, b: { c: 2, d: { e: 3, }, }, f: { g: 5, }, }; const obj2 = { a: 1, b: { c: 3, d: { e: 4, }, }, }; getObjectDifference(obj1, obj2); //=> { { 'b.c' : [2, 3], 'b.d.e'; : [3, 4], f; : [{ g: 5 }, undefined]; } ``` - parseObj :: obj -> QueryString - convert an object to query string - example: ```javascript parsrStr({a:'foo',b:'bar'}) //=> a=foo&b=bar ``` - parseStr :: QueryString -> obj - convert a query string to an object - example: ```javascript parsrObj('a=foo&b=bar') //=> {a:'foo',b:'bar'} ``` - convertKeyValue :: [a] -> obj (a: 'str=str') - convert a key-value array to an object ```javascript convertKeyValue(['foo=bar', 'fiz=fuz']); //=> {foo:'bar', fiz:'fuz'} ``` - convertObjToArr :: obj -> [a] (a: 'str=str') - convert an object to a key-value array ```javascript convertKeyValue({ foo: 'bar', fiz: 'fuz' }); //=> ['foo=bar', 'fiz=fuz'] ``` - snakeToCamel :: str -> str - convert a snake-string to camel-case string ```javascript snakeToCamel('abc_def_ghi') //=> 'abcDefGhi' ``` - objKeyToCamel :: obj -> obj - convert all keys in an object from snake to camel string - nested object is supported ```javascript objKeyToCamel({this_is_key: val}) //=> {thisIsKey: val} ``` - camelToSnake :: str -> str - convert a camel-case string to snake-case string ```javascript camelToSnake('abcDefGhi') //=> 'abc_def_ghi' ``` - objKeyToSnake :: obj -> obj - convert all keys in an object from camel to snake-case string - nested object is supported ```javascript objKeyToSnake({ thisIsKey: 'someVal' }) //=> { this_is_key: 'someVal' } ``` - parseCookie :: string -> obj - parse a cookie string to an object ```javascript parseCookie('foo=bar ; equation=E%3Dmc%5E2; asd='); //=> { foo: 'bar', equation: 'E=mc^2', asd: '' } ``` - serializeCookie :: obj -> string - serialize an object to cookie string ```javascript serializeCookie({ foo: 'bar', equation: 'E=mc^2', asd: '' }); //=> 'foo=bar;equation=E%3Dmc%5E2;asd=' ``` ### MoonUse - useRetry - useRetryAsync ```javascript useRetryAsync({ operation: async () => someAsyncOperation(), maxRetries: 3, backoffStrategy: (attempt) => 500 * attempt, shouldRetry: (error) => error.message === 'some error', }); ``` - useLock - useWait - To make an action execution wait for a given time before execution ```javascript useWait(1000, action); //=> wait for 1000ms, and then run action - ``` - useRedisCache - To get value from redis cache, otherwise get the value and cache it ```javascript const foo = await useCache('someCacheKey', getter, {keyLife:100}); //=> keyLife: key有效時間 (in second) - ``` ### Model - basicTypes ``` YES_NO_TYPE, NULLABLE_YES_NO_TYPE, STRING_TYPE, NON_EMPTY_STRING_TYPE, NUMBER_OR_STRING_TYPE, NULLABLE_STRING_TYPE, INTEGER_TYPE, UNSIGNED_INTEGER_TYPE, NULLABLE_INTEGER_TYPE, POSITIVE_INTEGER_TYPE, NULLABLE_UNSIGNED_INTEGER_TYPE, BIG_INTEGER_TYPE, NULLABLE_BIG_INTEGER_TYPE, UNSIGNED_TINY_INTEGER_TYPE, NUMBER_TYPE, ARRAY_TYPE, ARRAY_OF_INT_TYPE, NULLABLE_ARRAY_TYPE, OBJECT_TYPE, NULLABLE_OBJECT_TYPE, FUNCTION_TYPE, NULLABLE_FUNCTION_TYPE, ``` - example ``` Model.basicTypes.STRING_TYPE; ``` - datetimeTypes ``` DATE_TYPE, NULLABLE_DATE_TYPE, DATETIME_TYPE, NULLABLE_DATETIME_TYPE, ISO_DATETIME_TYPE, NULLABLE_ISO_DATETIME_TYPE, ``` - appTypes ``` EMAIL_TYPE, NULLABLE_EMAIL_TYPE, EMPTY_STRING_OR_EMAIL_TYPE, LINE_ID_TYPE, EMPTY_STRING_OR_LINE_ID_TYPE, CITY_TYPE, CITY_AREA_TYPE, MEDIA_TYPE, TW_TAX_ID_TYPE, NULLABLE_TW_TAX_ID_TYPE, TW_MOBILE_NO_TYPE, HOSTNAME_TYPE, NULLABLE_HOSTNAME_TYPE, EMPTY_STRING_OR_HOSTNAME_TYPE, ``` - appTypes.CITY_TYPE (台灣城市) - 結構: 整數 (城市編號) - properties: - validator - cityList (台灣城市清單) - 會檢查縣市是否為合法值 - appTypes.CITY_AREA_TYPE (台灣城市與區域) - 結構: ``` {cityId: 1, areaId: 1} ``` - properties: - validator - cityList (台灣城市清單) - areaList (台灣區域清單,含城市編號與區域號碼) - 會檢查縣市與區域的對應,是否為合法值 - 城市與區域未定: {cityId:0, areaId:0} - 使用範例 ``` const someModelDef = { location: { type: CITY_AREA_TYPE, } } ``` - cityList內容 ``` const cityList = [ { id: 0, name: '未定義' }, { id: 1, name: '台北市' }, ... ]; ``` - areaList內容 ``` const areaList = [ { id: 0, cityId: 0, name: '未定義', zip: 0 }, { id: 1, cityId: 1, name: '中正區', zip: 100 }, ... ]; ```