diff --git a/.editorconfig b/.editorconfig index 6edf2517f..c155d8e84 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ indent_style = space indent_size = 2 trim_trailing_whitespace = true insert_final_newline = true +quote_type = single [*.{js,jsx,ts,tsx,html,css,styl,ss,ess}] indent_style = tab diff --git a/build/build-prelude-paths.js b/build/build-prelude-paths.js new file mode 100644 index 000000000..85a45c9fb --- /dev/null +++ b/build/build-prelude-paths.js @@ -0,0 +1,70 @@ +'use strict'; + +const + ts = require('typescript'), + fs = require('fs'), + glob = require('glob'); + +const primitiveTypes = ['Number', 'Array', 'Date', 'Object', 'String', 'RegExp', 'Function']; +const formatPath = (fullPath) => { + const path = fullPath.replace(/.*\/src\//, ''); + + if (path.endsWith('/index.ts')) { + return path.replace('/index.ts', ''); + } + + return path.replace('.ts', ''); +}; + +function extractPreludeInfo() { + const + preludeFiles = glob.sync('src/core/prelude/**/*.ts'), + preludeProgram = ts.createProgram(preludeFiles, require('../tsconfig.json')), + source = preludeProgram.getSourceFiles(); + + const result = {}; + + function transformer(ctx) { + return (sourceFile) => { + function visitor(node) { + if (ts.isVariableDeclaration(node) && node.initializer) { + const + {initializer, name} = node, + invokedExpression = ts.getInvokedExpression(initializer), + exportedSymbol = name && name.escapedText; + + if (invokedExpression && invokedExpression.escapedText === 'extend') { + const + [{expression, escapedText}, {text: methodName}] = initializer.arguments, + parentType = expression && expression.escapedText || escapedText; + + if (!result[parentType]) { + result[parentType] = {}; + } + + if (primitiveTypes.includes(parentType)) { + result[parentType][methodName] = { + path: formatPath(sourceFile.path), + name: exportedSymbol + }; + } + } + } + + return ts.visitEachChild(node, visitor, ctx); + } + + return ts.visitEachChild(sourceFile, visitor, ctx); + }; + } + + ts.transform(source, [transformer]); + + return result; +} + +function savePreludeInformation(preludeInfo) { + fs.writeFileSync('./lib/prelude-paths.json', JSON.stringify(preludeInfo, null, 2)); +} + +savePreludeInformation(extractPreludeInfo()); diff --git a/lib/prelude-paths.json b/lib/prelude-paths.json new file mode 100644 index 000000000..b11048431 --- /dev/null +++ b/lib/prelude-paths.json @@ -0,0 +1,584 @@ +{ + "Array": { + "union": { + "path": "core/prelude/array", + "name": "union" + }, + "concat": { + "path": "core/prelude/array", + "name": "concat" + } + }, + "Date": { + "is": { + "path": "core/prelude/date/compare", + "name": "is" + }, + "isPast": { + "path": "core/prelude/date/compare", + "name": "isPast" + }, + "isFuture": { + "path": "core/prelude/date/compare", + "name": "isFuture" + }, + "isAfter": { + "path": "core/prelude/date/compare", + "name": "isAfter" + }, + "isBefore": { + "path": "core/prelude/date/compare", + "name": "isBefore" + }, + "isBetween": { + "path": "core/prelude/date/compare", + "name": "isBetween" + }, + "clone": { + "path": "core/prelude/date/create", + "name": "clone" + }, + "create": { + "path": "core/prelude/date/create", + "name": "create" + }, + "beginningOfDay": { + "path": "core/prelude/date/create", + "name": "beginningOfDay" + }, + "endOfDay": { + "path": "core/prelude/date/create", + "name": "endOfDay" + }, + "beginningOfWeek": { + "path": "core/prelude/date/create", + "name": "beginningOfWeek" + }, + "endOfWeek": { + "path": "core/prelude/date/create", + "name": "endOfWeek" + }, + "beginningOfMonth": { + "path": "core/prelude/date/create", + "name": "beginningOfMonth" + }, + "endOfMonth": { + "path": "core/prelude/date/create", + "name": "endOfMonth" + }, + "daysInMonth": { + "path": "core/prelude/date/create", + "name": "daysInMonth" + }, + "beginningOfYear": { + "path": "core/prelude/date/create", + "name": "beginningOfYear" + }, + "endOfYear": { + "path": "core/prelude/date/create", + "name": "endOfYear" + }, + "format": { + "path": "core/prelude/date/format", + "name": "format" + }, + "short": { + "path": "core/prelude/date/format", + "name": "short" + }, + "medium": { + "path": "core/prelude/date/format", + "name": "medium" + }, + "long": { + "path": "core/prelude/date/format", + "name": "long" + }, + "toHTMLTimeString": { + "path": "core/prelude/date/format", + "name": "toHTMLTimeString" + }, + "toHTMLDateString": { + "path": "core/prelude/date/format", + "name": "toHTMLDateString" + }, + "toHTMLString": { + "path": "core/prelude/date/format", + "name": "toHTMLString" + }, + "add": { + "path": "core/prelude/date/modify", + "name": "add" + }, + "set": { + "path": "core/prelude/date/modify", + "name": "set" + }, + "rewind": { + "path": "core/prelude/date/modify", + "name": "rewind" + }, + "relative": { + "path": "core/prelude/date/relative", + "name": "relative" + }, + "relativeTo": { + "path": "core/prelude/date/relative", + "name": "relativeTo" + } + }, + "Function": { + "compose": { + "path": "core/prelude/function/compose", + "name": "compose" + }, + "curry": { + "path": "core/prelude/function/curry", + "name": "curry" + }, + "addToPrototype": { + "path": "core/prelude/function/extend", + "name": "addToPrototype" + }, + "debounce": { + "path": "core/prelude/function/lazy", + "name": "debounce" + }, + "throttle": { + "path": "core/prelude/function/lazy", + "name": "throttle" + }, + "once": { + "path": "core/prelude/function/memoize", + "name": "once" + }, + "option": { + "path": "core/prelude/function/monad", + "name": "option" + }, + "result": { + "path": "core/prelude/function/monad", + "name": "result" + } + }, + "Object": { + "Option": { + "path": "core/prelude/function/monad", + "name": "Option" + }, + "Result": { + "path": "core/prelude/function/monad", + "name": "Result" + }, + "fastClone": { + "path": "core/prelude/object/clone", + "name": "fastClone" + }, + "fastCompare": { + "path": "core/prelude/object/compare", + "name": "fastCompare" + }, + "trySerialize": { + "path": "core/prelude/object/convert", + "name": "trySerialize" + }, + "parse": { + "path": "core/prelude/object/convert", + "name": "parse" + }, + "createDict": { + "path": "core/prelude/object/create", + "name": "createDict" + }, + "convertEnumToDict": { + "path": "core/prelude/object/create", + "name": "convertEnumToDict" + }, + "createEnumLike": { + "path": "core/prelude/object/create", + "name": "createEnumLike" + }, + "fromArray": { + "path": "core/prelude/object/create", + "name": "fromArray" + }, + "select": { + "path": "core/prelude/object/create", + "name": "select" + }, + "reject": { + "path": "core/prelude/object/create", + "name": "reject" + }, + "forEach": { + "path": "core/prelude/object/iterators", + "name": "forEach" + }, + "size": { + "path": "core/prelude/object/metrics", + "name": "size" + }, + "mixin": { + "path": "core/prelude/object/mixin", + "name": "mixin" + }, + "get": { + "path": "core/prelude/object/property", + "name": "get" + }, + "has": { + "path": "core/prelude/object/property", + "name": "has" + }, + "hasOwnProperty": { + "path": "core/prelude/object/property", + "name": "hasOwnProperty" + }, + "defineSymbol": { + "path": "core/prelude/object/property", + "name": "defineSymbol" + }, + "set": { + "path": "core/prelude/object/property", + "name": "set" + }, + "delete": { + "path": "core/prelude/object/property", + "name": "deleteObj" + }, + "cast": { + "path": "core/prelude/types", + "name": "cast" + }, + "isTruly": { + "path": "core/prelude/types", + "name": "isTruly" + }, + "isPrimitive": { + "path": "core/prelude/types", + "name": "isPrimitive" + }, + "isUndef": { + "path": "core/prelude/types", + "name": "isUndef" + }, + "isNull": { + "path": "core/prelude/types", + "name": "isNull" + }, + "isNullable": { + "path": "core/prelude/types", + "name": "isNullable" + }, + "isString": { + "path": "core/prelude/types", + "name": "isString" + }, + "throw": { + "path": "core/prelude/types", + "name": "objThrow" + }, + "isNumber": { + "path": "core/prelude/types", + "name": "isNumber" + }, + "isBoolean": { + "path": "core/prelude/types", + "name": "isBoolean" + }, + "isSymbol": { + "path": "core/prelude/types", + "name": "isSymbol" + }, + "isRegExp": { + "path": "core/prelude/types", + "name": "isRegExp" + }, + "isDate": { + "path": "core/prelude/types", + "name": "isDate" + }, + "isArray": { + "path": "core/prelude/types", + "name": "isArray" + }, + "isArrayLike": { + "path": "core/prelude/types", + "name": "isArrayLike" + }, + "isMap": { + "path": "core/prelude/types", + "name": "isMap" + }, + "isWeakMap": { + "path": "core/prelude/types", + "name": "isWeakMap" + }, + "isSet": { + "path": "core/prelude/types", + "name": "isSet" + }, + "isWeakSet": { + "path": "core/prelude/types", + "name": "isWeakSet" + }, + "isDictionary": { + "path": "core/prelude/types", + "name": "isDictionary" + }, + "isPlainObject": { + "path": "core/prelude/types", + "name": "isPlainObject" + }, + "unwrapProxy": { + "path": "core/prelude/types", + "name": "unwrapProxy" + }, + "isCustomObject": { + "path": "core/prelude/types", + "name": "isCustomObject" + }, + "isSimpleObject": { + "path": "core/prelude/types", + "name": "isSimpleObject" + }, + "isFunction": { + "path": "core/prelude/types", + "name": "isFunction" + }, + "isSimpleFunction": { + "path": "core/prelude/types", + "name": "isSimpleFunction" + }, + "isGenerator": { + "path": "core/prelude/types", + "name": "isGenerator" + }, + "isAsyncGenerator": { + "path": "core/prelude/types", + "name": "isAsyncGenerator" + }, + "isIterator": { + "path": "core/prelude/types", + "name": "isIterator" + }, + "isIterable": { + "path": "core/prelude/types", + "name": "isIterable" + }, + "isAsyncIterable": { + "path": "core/prelude/types", + "name": "isAsyncIterable" + }, + "isIterableIterator": { + "path": "core/prelude/types", + "name": "isIterableIterator" + }, + "isAsyncIterator": { + "path": "core/prelude/types", + "name": "isAsyncIterator" + }, + "isAnyIterator": { + "path": "core/prelude/types", + "name": "isAnyIterator" + }, + "isAnyIterable": { + "path": "core/prelude/types", + "name": "isAnyIterable" + }, + "isPromise": { + "path": "core/prelude/types", + "name": "isPromise" + }, + "isPromiseLike": { + "path": "core/prelude/types", + "name": "isPromiseLike" + }, + "isProxy": { + "path": "core/prelude/types", + "name": "isProxy" + } + }, + "Number": { + "second": { + "path": "core/prelude/number/converters", + "name": "second" + }, + "seconds": { + "path": "core/prelude/number/converters", + "name": "seconds" + }, + "minute": { + "path": "core/prelude/number/converters", + "name": "minute" + }, + "minutes": { + "path": "core/prelude/number/converters", + "name": "minutes" + }, + "hour": { + "path": "core/prelude/number/converters", + "name": "hour" + }, + "hours": { + "path": "core/prelude/number/converters", + "name": "hours" + }, + "day": { + "path": "core/prelude/number/converters", + "name": "day" + }, + "days": { + "path": "core/prelude/number/converters", + "name": "days" + }, + "week": { + "path": "core/prelude/number/converters", + "name": "week" + }, + "weeks": { + "path": "core/prelude/number/converters", + "name": "weeks" + }, + "em": { + "path": "core/prelude/number/converters", + "name": "em" + }, + "rem": { + "path": "core/prelude/number/converters", + "name": "rem" + }, + "px": { + "path": "core/prelude/number/converters", + "name": "px" + }, + "per": { + "path": "core/prelude/number/converters", + "name": "per" + }, + "vh": { + "path": "core/prelude/number/converters", + "name": "vh" + }, + "vw": { + "path": "core/prelude/number/converters", + "name": "vw" + }, + "vmin": { + "path": "core/prelude/number/converters", + "name": "vmin" + }, + "vmax": { + "path": "core/prelude/number/converters", + "name": "vmax" + }, + "pad": { + "path": "core/prelude/number/format", + "name": "pad" + }, + "format": { + "path": "core/prelude/number/format", + "name": "format" + }, + "isSafe": { + "path": "core/prelude/number/metrics", + "name": "isSafe" + }, + "isInteger": { + "path": "core/prelude/number/metrics", + "name": "isInteger" + }, + "isFloat": { + "path": "core/prelude/number/metrics", + "name": "isFloat" + }, + "isEven": { + "path": "core/prelude/number/metrics", + "name": "isEven" + }, + "isOdd": { + "path": "core/prelude/number/metrics", + "name": "isOdd" + }, + "isNatural": { + "path": "core/prelude/number/metrics", + "name": "isNatural" + }, + "isPositive": { + "path": "core/prelude/number/metrics", + "name": "isPositive" + }, + "isNegative": { + "path": "core/prelude/number/metrics", + "name": "isNegative" + }, + "isNonNegative": { + "path": "core/prelude/number/metrics", + "name": "isNonNegative" + }, + "isBetweenZeroAndOne": { + "path": "core/prelude/number/metrics", + "name": "isBetweenZeroAndOne" + }, + "isPositiveBetweenZeroAndOne": { + "path": "core/prelude/number/metrics", + "name": "isPositiveBetweenZeroAndOne" + }, + "floor": { + "path": "core/prelude/number/rounding", + "name": "floor" + }, + "round": { + "path": "core/prelude/number/rounding", + "name": "round" + }, + "ceil": { + "path": "core/prelude/number/rounding", + "name": "ceil" + } + }, + "RegExp": { + "escape": { + "path": "core/prelude/regexp", + "name": "escape" + }, + "addFlags": { + "path": "core/prelude/regexp", + "name": "addFlags" + }, + "removeFlags": { + "path": "core/prelude/regexp", + "name": "removeFlags" + }, + "test": { + "path": "core/prelude/regexp", + "name": "test" + }, + "setFlags": { + "path": "core/prelude/regexp", + "name": "setFlags" + } + }, + "String": { + "letters": { + "path": "core/prelude/string/iterators", + "name": "letters" + }, + "capitalize": { + "path": "core/prelude/string/transformers", + "name": "capitalize" + }, + "camelize": { + "path": "core/prelude/string/transformers", + "name": "camelize" + }, + "dasherize": { + "path": "core/prelude/string/transformers", + "name": "dasherize" + }, + "underscore": { + "path": "core/prelude/string/transformers", + "name": "underscore" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index b96b1e482..115c73f9b 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "scripts": { "dev": "SOURCEMAPS=true gulp watch:server", "build": "gulp build:server", + "build:prelude": "node build/build-prelude-paths", "build:tsconfig": "node build/build-tsconfig", "build:standalone": "gulp build:standalone", "watch:standalone": "gulp watch:standalone", diff --git a/src/core/prelude/array/index.ts b/src/core/prelude/array/index.ts index 5a92f127f..1c25a0651 100644 --- a/src/core/prelude/array/index.ts +++ b/src/core/prelude/array/index.ts @@ -9,8 +9,16 @@ import extend from 'core/prelude/extend'; import { emptyArray } from 'core/prelude/array/const'; +import { + + isIterable, + isPrimitive, + cast + +} from 'core/prelude/types'; + /** @see [[Array.union]] */ -extend(Array.prototype, 'union', function union( +export const union = extend(Array.prototype, 'union', function union( this: unknown[], ...args: Array | unknown> ): unknown[] { @@ -28,8 +36,8 @@ extend(Array.prototype, 'union', function union( continue; } - if (Object.isIterable(val) && !Object.isPrimitive(val)) { - yield* Object.cast(val[Symbol.iterator]()); + if (isIterable(val) && !isPrimitive(val)) { + yield* cast(val[Symbol.iterator]()); } else { yield val; @@ -40,17 +48,8 @@ extend(Array.prototype, 'union', function union( return [...new Set(makeIterator())]; }); -/** @see [[ArrayConstructor.union]] */ -extend(Array, 'union', (arr: unknown[], ...args: Array | unknown>) => { - if (args.length === 0) { - return (...args) => Array.union(arr, ...args); - } - - return arr.union(...args); -}); - /** @see [[ArrayConstructor.concat]] */ -extend(Array, 'concat', (arr: unknown[], ...args: Array>) => { +export const concat = extend(Array, 'concat', (arr: unknown[], ...args: Array>) => { if (args.length === 0) { return (...args) => Array.concat(arr, ...args); } @@ -58,23 +57,26 @@ extend(Array, 'concat', (arr: unknown[], ...args: Array>) => { // Optimization for simple cases switch (args.length) { case 1: - return arr.concat(args[0] != null ? args[0] : emptyArray); + return concat.call(arr, args[0] != null ? args[0] : emptyArray); case 2: - return arr.concat( + return concat.call( + arr, args[0] != null ? args[0] : emptyArray, args[1] != null ? args[1] : emptyArray ); case 3: - return arr.concat( + return concat.call( + arr, args[0] != null ? args[0] : emptyArray, args[1] != null ? args[1] : emptyArray, args[2] != null ? args[2] : emptyArray ); case 4: - return arr.concat( + return concat.call( + arr, args[0] != null ? args[0] : emptyArray, args[1] != null ? args[1] : emptyArray, args[2] != null ? args[2] : emptyArray, @@ -94,7 +96,18 @@ extend(Array, 'concat', (arr: unknown[], ...args: Array>) => { } } - return arr.concat(...filteredArgs); + return concat.call(arr, ...filteredArgs); } } }); + +// #if prelude/standalone +/** @see [[ArrayConstructor.union]] */ +extend(Array, 'union', (arr: unknown[], ...args: Array | unknown>) => { + if (args.length === 0) { + return (...args) => arr.union(arr, ...args); + } + + return arr.union(...args); +}); +// #endif diff --git a/src/core/prelude/date/compare/index.ts b/src/core/prelude/date/compare/index.ts index b106589df..f4b4faa85 100644 --- a/src/core/prelude/date/compare/index.ts +++ b/src/core/prelude/date/compare/index.ts @@ -9,65 +9,53 @@ import extend from 'core/prelude/extend'; import { createStaticDateComparator } from 'core/prelude/date/helpers'; +import { create } from 'core/prelude/date/create'; + /** @see [[Date.is]] */ -extend(Date.prototype, 'is', function is(this: Date, date: DateCreateValue, margin: number = 0): boolean { - return Math.abs(this.valueOf() - Date.create(date).valueOf()) <= margin; +export const is = extend(Date.prototype, 'is', function is(this: Date, date: DateCreateValue, margin: number = 0): boolean { + return Math.abs(this.valueOf() - create(date).valueOf()) <= margin; }); -/** @see [[DateConstructor.is]] */ -extend(Date, 'is', createStaticDateComparator('is')); - /** @see [[Date.isPast]] */ -extend(Date.prototype, 'isPast', function isPast(this: Date): boolean { +export const isPast = extend(Date.prototype, 'isPast', function isPast(this: Date): boolean { return this.valueOf() < Date.now(); }); -/** @see [[DateConstructor.isPast]] */ -extend(Date, 'isPast', (date: Date) => date.isPast()); - /** @see [[Date.isFuture]] */ -extend(Date.prototype, 'isFuture', function isFuture(this: Date): boolean { +export const isFuture = extend(Date.prototype, 'isFuture', function isFuture(this: Date): boolean { return this.valueOf() > Date.now(); }); -/** @see [[DateConstructor.isFuture]] */ -extend(Date, 'isFuture', (date: Date) => date.isFuture()); - /** @see [[Date.isAfter]] */ -extend(Date.prototype, 'isAfter', function isAfter( +export const isAfter = extend(Date.prototype, 'isAfter', function isAfter( this: Date, date: DateCreateValue, margin: number = 0 ): boolean { - return this.valueOf() > Date.create(date).valueOf() - margin; + return this.valueOf() > create(date).valueOf() - margin; }); -/** @see [[DateConstructor.isAfter]] */ -extend(Date, 'isAfter', createStaticDateComparator('isAfter')); - /** @see [[Date.isBefore]] */ -extend(Date.prototype, 'isBefore', function isBefore( +export const isBefore = extend(Date.prototype, 'isBefore', function isBefore( this: Date, date: DateCreateValue, margin: number = 0 ): boolean { - return this.valueOf() < Date.create(date).valueOf() + margin; + return this.valueOf() < create(date).valueOf() + margin; }); -/** @see [[DateConstructor.isBefore]] */ -extend(Date, 'isBefore', createStaticDateComparator('isBefore')); - /** @see [[Date.isBetween]] */ -extend(Date.prototype, 'isBetween', function isBetween( +export const isBetween = extend(Date.prototype, 'isBetween', function isBetween( this: Date, left: DateCreateValue, right: DateCreateValue, margin: number = 0 ): boolean { const v = this.valueOf(); - return v >= Date.create(left).valueOf() - margin && v <= Date.create(right).valueOf() + margin; + return v >= create(left).valueOf() - margin && v <= create(right).valueOf() + margin; }); +//#if prelude/standalone /** @see [[DateConstructor.isBetween]] */ extend(Date, 'isBetween', function isBetween( date: DateCreateValue, @@ -89,3 +77,19 @@ extend(Date, 'isBetween', function isBetween( return Date.create(date).isBetween(left!, right!, margin ?? 0); }); + +/** @see [[DateConstructor.isBefore]] */ +extend(Date, 'isBefore', createStaticDateComparator('isBefore')); + +/** @see [[DateConstructor.isAfter]] */ +extend(Date, 'isAfter', createStaticDateComparator('isAfter')); + +/** @see [[DateConstructor.isFuture]] */ +extend(Date, 'isFuture', (date: Date) => date.isFuture()); + +/** @see [[DateConstructor.isPast]] */ +extend(Date, 'isPast', (date: Date) => date.isPast()); + +/** @see [[DateConstructor.is]] */ +extend(Date, 'is', createStaticDateComparator('is')); +//#endif diff --git a/src/core/prelude/date/const.ts b/src/core/prelude/date/const.ts index 408848035..4b5dfbd90 100644 --- a/src/core/prelude/date/const.ts +++ b/src/core/prelude/date/const.ts @@ -6,8 +6,14 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { createDict } from 'core/prelude/object/create'; +import { forEach } from 'core/prelude/object/iterators'; + +import { format } from 'core/prelude/date/format'; +import { beginningOfDay } from 'core/prelude/date/create'; + export const - formatCache = Object.createDict(); + formatCache = createDict(); export const dateChunkRgxp = /(\d{1,4}[-./]\d{1,2}[-./]\d{1,4})/, @@ -22,24 +28,24 @@ export const isDateStr = new RegExp(`^${dateChunkRgxp.source}${timeChunkRgxp.source}${zoneChunkRgxp.source}$`), isFloatStr = /^\d+\.\d+$/; -export const createAliases = Object.createDict({ +export const createAliases = createDict({ now: () => new Date(), - today: () => new Date().beginningOfDay(), + today: () => beginningOfDay.call(new Date()), yesterday: () => { const v = new Date(); v.setDate(v.getDate() - 1); - return v.beginningOfDay(); + return beginningOfDay.call(v); }, tomorrow: () => { const v = new Date(); v.setDate(v.getDate() + 1); - return v.beginningOfDay(); + return beginningOfDay.call(v); } }); -export const formatAliases = Object.createDict({ +export const formatAliases = createDict({ e: 'era', Y: 'year', M: 'month', @@ -51,30 +57,30 @@ export const formatAliases = Object.createDict({ z: 'timeZoneName' }); -Object.forEach(formatAliases, (val) => { +forEach(formatAliases, (val) => { formatAliases[val] = val; }); ['Y', 'M', 'w', 'd', 'h', 'm', 's'].forEach((key) => { - const format = (date) => { + const formatFunc = (date) => { const now = new Date(); - if (date.format(key) !== now.format(key)) { + if (format.call(date, key) !== format.call(now, key)) { return formatAliases[key]; } }; - formatAliases[`${key}?`] = format; - formatAliases[`${formatAliases[key]}?`] = format; + formatAliases[`${key}?`] = formatFunc; + formatAliases[`${formatAliases[key]}?`] = formatFunc; }); -export const boolAliases = Object.createDict({ +export const boolAliases = createDict({ '+': true, '-': false }); -export const defaultFormats = Object.createDict({ +export const defaultFormats = createDict({ era: 'short', year: 'numeric', month: 'short', diff --git a/src/core/prelude/date/create/index.ts b/src/core/prelude/date/create/index.ts index 9d440e1c3..fd52e69fa 100644 --- a/src/core/prelude/date/create/index.ts +++ b/src/core/prelude/date/create/index.ts @@ -20,13 +20,18 @@ import { } from 'core/prelude/date/const'; +import { isTruly, isString, isNumber } from 'core/prelude/types'; +import { parse } from 'core/prelude/object/convert'; + +import { test } from 'core/prelude/regexp'; + /** @see [[Date.clone]] */ -extend(Date.prototype, 'clone', function clone(this: Date): Date { +export const clone = extend(Date.prototype, 'clone', function clone(this: Date): Date { return new Date(this); }); /** @see [[DateConstructor.create]] */ -extend(Date, 'create', (pattern?: DateCreateValue) => { +export const create = extend(Date, 'create', (pattern?: DateCreateValue) => { if (pattern == null || pattern === '') { return new Date(); } @@ -35,7 +40,7 @@ extend(Date, 'create', (pattern?: DateCreateValue) => { return new Date(pattern); } - if (Object.isString(pattern)) { + if (isString(pattern)) { if (pattern in createAliases) { return createAliases[pattern](); } @@ -54,7 +59,7 @@ extend(Date, 'create', (pattern?: DateCreateValue) => { }; const normalizeZone = (zone) => { - if (RegExp.test(normalizeZoneRgxp, zone)) { + if (test(normalizeZoneRgxp, zone)) { return `${zone.substr(0, 3)}:${zone.substr(3)}`; } @@ -80,20 +85,20 @@ extend(Date, 'create', (pattern?: DateCreateValue) => { const normalizedDate = normalizeDate(date); - time = Object.isTruly(time) ? time : '00:00:00'; - zone = Object.isTruly(zone) ? zone : getZone(normalizedDate); + time = isTruly(time) ? time : '00:00:00'; + zone = isTruly(zone) ? zone : getZone(normalizedDate); return `${normalizedDate}T${time}${normalizeZone(zone)}`; }; - return new Date(Date.parse(pattern.replace(isDateStr, replacer))); + return new Date(parse(pattern.replace(isDateStr, replacer))); } - if (Object.isString(pattern) && isFloatStr.test(pattern)) { + if (isString(pattern) && isFloatStr.test(pattern)) { const float = parseFloat(pattern); pattern = float > 0 ? float * 1e3 : pattern; - } else if (Object.isNumber(pattern) && !pattern.isInteger()) { + } else if (isNumber(pattern) && !pattern.isInteger()) { pattern *= 1e3; } @@ -101,89 +106,91 @@ extend(Date, 'create', (pattern?: DateCreateValue) => { }); /** @see [[Date.beginningOfDay]] */ -extend(Date.prototype, 'beginningOfDay', function beginningOfDay(this: Date): Date { - const date = this.clone(); +export const beginningOfDay = extend(Date.prototype, 'beginningOfDay', function beginningOfDay(this: Date): Date { + const date = clone.call(this); date.setHours(0, 0, 0, 0); return date; }); -/** @see [[DateConstructor.beginningOfDay]] */ -extend(Date, 'beginningOfDay', (date: Date) => date.beginningOfDay()); - /** @see [[Date.endOfDay]] */ -extend(Date.prototype, 'endOfDay', function endOfDay(this: Date): Date { - const date = this.clone(); +export const endOfDay = extend(Date.prototype, 'endOfDay', function endOfDay(this: Date): Date { + const date = clone.call(this); date.setHours(23, 59, 59, 999); return date; }); -/** @see [[DateConstructor.endOfDay]] */ -extend(Date, 'endOfDay', (date: Date) => date.endOfDay()); - /** @see [[Date.beginningOfWeek]] */ -extend(Date.prototype, 'beginningOfWeek', function beginningOfWeek(this: Date): Date { - const date = this.clone(); +export const beginningOfWeek = extend(Date.prototype, 'beginningOfWeek', function beginningOfWeek(this: Date): Date { + const date = clone.call(this); date.setDate(this.getDate() - this.getDay()); return date.beginningOfDay(); }); -/** @see [[DateConstructor.beginningOfWeek]] */ -extend(Date, 'beginningOfWeek', (date: Date) => date.beginningOfWeek()); - /** @see [[Date.endOfWeek]] */ -extend(Date.prototype, 'endOfWeek', function endOfWeek(this: Date): Date { - const date = this.clone(); +export const endOfWeek = extend(Date.prototype, 'endOfWeek', function endOfWeek(this: Date): Date { + const date = clone.call(this); date.setDate(this.getDate() + 6 - this.getDay()); return date.endOfDay(); }); -/** @see [[DateConstructor.endOfWeek]] */ -extend(Date, 'endOfWeek', (date: Date) => date.endOfWeek()); - /** @see [[Date.beginningOfMonth]] */ -extend(Date.prototype, 'beginningOfMonth', function beginningOfMonth(this: Date): Date { - const date = this.clone(); +export const beginningOfMonth = extend(Date.prototype, 'beginningOfMonth', function beginningOfMonth(this: Date): Date { + const date = clone.call(this); date.setDate(1); - return date.beginningOfDay(); + return beginningOfDay.call(date); }); -/** @see [[DateConstructor.beginningOfMonth]] */ -extend(Date, 'beginningOfMonth', (date: Date) => date.beginningOfMonth()); - /** @see [[Date.endOfMonth]] */ -extend(Date.prototype, 'endOfMonth', function endOfMonth(this: Date): Date { - const date = this.clone(); +export const endOfMonth = extend(Date.prototype, 'endOfMonth', function endOfMonth(this: Date): Date { + const date = clone.call(this); date.setMonth(this.getMonth() + 1, 0); - return date.endOfDay(); + return endOfDay.call(date); }); -/** @see [[DateConstructor.endOfMonth]] */ -extend(Date, 'endOfMonth', (date: Date) => date.endOfMonth()); - /** @see [[Date.daysInMonth]] */ -extend(Date.prototype, 'daysInMonth', function daysInMonth(this: Date): number { - return this.clone().endOfMonth().getDate(); +export const daysInMonth = extend(Date.prototype, 'daysInMonth', function daysInMonth(this: Date): number { + return endOfMonth.call(clone.call(this)).getDate(); }); -/** @see [[DateConstructor.daysInMonth]] */ -extend(Date, 'daysInMonth', (date: Date) => date.daysInMonth()); - /** @see [[Date.beginningOfYear]] */ -extend(Date.prototype, 'beginningOfYear', function beginningOfYear(this: Date): Date { - const date = this.clone(); +export const beginningOfYear = extend(Date.prototype, 'beginningOfYear', function beginningOfYear(this: Date): Date { + const date = clone.call(this); date.setMonth(0, 1); - return date.beginningOfDay(); + return beginningOfDay.call(date); }); -/** @see [[DateConstructor.beginningOfYear]] */ -extend(Date, 'beginningOfYear', (date: Date) => date.beginningOfYear()); - /** @see [[Date.endOfYear]] */ -extend(Date.prototype, 'endOfYear', function endOfYear(this: Date): Date { - const date = this.clone(); +export const endOfYear = extend(Date.prototype, 'endOfYear', function endOfYear(this: Date): Date { + const date = clone.call(this); date.setMonth(12, 0); - return date.endOfDay(); + return endOfDay.call(date); }); +//#if prelude/standalone /** @see [[DateConstructor.endOfYear]] */ extend(Date, 'endOfYear', (date: Date) => date.endOfYear()); + +/** @see [[DateConstructor.beginningOfYear]] */ +extend(Date, 'beginningOfYear', (date: Date) => date.beginningOfYear()); + +/** @see [[DateConstructor.daysInMonth]] */ +extend(Date, 'daysInMonth', (date: Date) => date.daysInMonth()); + +/** @see [[DateConstructor.endOfMonth]] */ +extend(Date, 'endOfMonth', (date: Date) => date.endOfMonth()); + +/** @see [[DateConstructor.beginningOfMonth]] */ +extend(Date, 'beginningOfMonth', (date: Date) => date.beginningOfMonth()); + +/** @see [[DateConstructor.endOfWeek]] */ +extend(Date, 'endOfWeek', (date: Date) => date.endOfWeek()); + +/** @see [[DateConstructor.beginningOfWeek]] */ +extend(Date, 'beginningOfWeek', (date: Date) => date.beginningOfWeek()); + +/** @see [[DateConstructor.endOfDay]] */ +extend(Date, 'endOfDay', (date: Date) => date.endOfDay()); + +/** @see [[DateConstructor.beginningOfDay]] */ +extend(Date, 'beginningOfDay', (date: Date) => date.beginningOfDay()); +//#endif diff --git a/src/core/prelude/date/format/index.ts b/src/core/prelude/date/format/index.ts index 8154ca66b..5c77e0595 100644 --- a/src/core/prelude/date/format/index.ts +++ b/src/core/prelude/date/format/index.ts @@ -11,46 +11,15 @@ import { locale as defaultLocale } from 'core/prelude/i18n'; import { formatCache, formatAliases, boolAliases, defaultFormats } from 'core/prelude/date/const'; import { createStaticDateFormatter } from 'core/prelude/date/helpers'; -/** @see [[Date.short]] */ -extend(Date.prototype, 'short', function short( - this: Date, - locale: CanUndef> = defaultLocale.value -): string { - return this.format('d:numeric;M:numeric;Y:numeric', locale); -}); - -/** @see [[DateConstructor.short]] */ -extend(Date, 'short', createStaticDateFormatter('short')); - -/** @see [[Date.medium]] */ -extend(Date.prototype, 'medium', function medium( - this: Date, - locale: CanUndef> = defaultLocale.value -): string { - return this.format('d:numeric;M:long;Y:numeric', locale); -}); - -/** @see [[DateConstructor.medium]] */ -extend(Date, 'medium', createStaticDateFormatter('medium')); - -/** @see [[Date.long]] */ -extend(Date.prototype, 'long', function long( - this: Date, - locale: CanUndef> = defaultLocale.value -): string { - return this.format('d:numeric;M:long;Y:numeric;h:2-digit;m:2-digit;s:2-digit', locale); -}); - -/** @see [[DateConstructor.long]] */ -extend(Date, 'long', createStaticDateFormatter('long')); +import { isPlainObject, isFunction } from 'core/prelude/types'; /** @see [[Date.format]] */ -extend(Date.prototype, 'format', function format( +export const format = extend(Date.prototype, 'format', function format( this: Date, patternOrOpts: string | Intl.DateTimeFormatOptions, locale: CanUndef> = defaultLocale.value ): string { - if (Object.isPlainObject(patternOrOpts)) { + if (isPlainObject(patternOrOpts)) { return this.toLocaleString(locale, patternOrOpts); } @@ -86,7 +55,7 @@ extend(Date.prototype, 'format', function format( if (formatKeyAlias != null) { formatKey = formatKeyAlias; - if (Object.isFunction(formatKey)) { + if (isFunction(formatKey)) { formatKey = formatKey(this); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition @@ -113,42 +82,32 @@ extend(Date.prototype, 'format', function format( return formatter.format(this); }); -/** @see [[DateConstructor.format]] */ -extend(Date, 'format', ( - date: Date | string | Intl.NumberFormatOptions, - patternOrOpts?: string | Intl.NumberFormatOptions, - locale?: CanArray -) => { - if (Object.isString(date) || Object.isPlainObject(date)) { - locale = Object.cast(patternOrOpts); - patternOrOpts = date; - return (date) => Date.format(date, Object.cast(patternOrOpts), locale); - } - - return date.format(Object.cast(patternOrOpts), locale); +/** @see [[Date.short]] */ +export const short = extend(Date.prototype, 'short', function short( + this: Date, + locale: CanUndef> = defaultLocale.value +): string { + return format.call(this, 'd:numeric;M:numeric;Y:numeric', locale); }); -/** @see [[Date.toHTMLDateString]] */ -extend(Date.prototype, 'toHTMLDateString', function toHTMLDateString( +/** @see [[Date.medium]] */ +export const medium = extend(Date.prototype, 'medium', function medium( this: Date, - opts: DateHTMLDateStringOptions = {} + locale: CanUndef> = defaultLocale.value ): string { - const - s = (v) => String(v).padStart(2, '0'), - needMonth = opts.month !== false; - - return [ - this.getFullYear(), - needMonth ? s(this.getMonth() + 1) : '01', - needMonth && opts.date !== false ? s(this.getDate()) : '01' - ].join('-'); + return format.call(this, 'd:numeric;M:long;Y:numeric', locale); }); -/** @see [[DateConstructor.toHTMLDateString]] */ -extend(Date, 'toHTMLDateString', createStaticDateFormatter('toHTMLDateString')); +/** @see [[Date.long]] */ +export const long = extend(Date.prototype, 'long', function long( + this: Date, + locale: CanUndef> = defaultLocale.value +): string { + return format.call(this, 'd:numeric;M:long;Y:numeric;h:2-digit;m:2-digit;s:2-digit', locale); +}); /** @see [[Date.toHTMLTimeString]] */ -extend(Date.prototype, 'toHTMLTimeString', function toHTMLTimeString( +export const toHTMLTimeString = extend(Date.prototype, 'toHTMLTimeString', function toHTMLTimeString( this: Date, opts: DateHTMLTimeStringOptions = {} ): string { @@ -176,13 +135,58 @@ extend(Date.prototype, 'toHTMLTimeString', function toHTMLTimeString( return res.join(':'); }); -/** @see [[DateConstructor.toHTMLTimeString]] */ -extend(Date, 'toHTMLTimeString', createStaticDateFormatter('toHTMLTimeString')); +/** @see [[Date.toHTMLDateString]] */ +export const toHTMLDateString = extend(Date.prototype, 'toHTMLDateString', function toHTMLDateString( + this: Date, + opts: DateHTMLDateStringOptions = {} +): string { + const + s = (v) => String(v).padStart(2, '0'), + needMonth = opts.month !== false; + + return [ + this.getFullYear(), + needMonth ? s(this.getMonth() + 1) : '01', + needMonth && opts.date !== false ? s(this.getDate()) : '01' + ].join('-'); +}); /** @see [[Date.toHTMLString]] */ -extend(Date.prototype, 'toHTMLString', function toHTMLString(this: Date, opts: DateHTMLStringOptions): string { - return `${this.toHTMLDateString(opts)}T${this.toHTMLTimeString(opts)}`; +export const toHTMLString = extend(Date.prototype, 'toHTMLString', function toHTMLString(this: Date, opts: DateHTMLStringOptions): string { + return `${toHTMLDateString(this, opts)}T${toHTMLTimeString(this, opts)}`; }); +//#if prelude/standalone +/** @see [[DateConstructor.format]] */ +extend(Date, 'format', ( + date: Date | string | Intl.NumberFormatOptions, + patternOrOpts?: string | Intl.NumberFormatOptions, + locale?: CanArray +) => { + if (Object.isString(date) || Object.isPlainObject(date)) { + locale = Object.cast(patternOrOpts); + patternOrOpts = date; + return (date) => format.call(date, Object.cast(patternOrOpts), locale); + } + + return date.format(Object.cast(patternOrOpts), locale); +}); + +/** @see [[DateConstructor.toHTMLDateString]] */ +extend(Date, 'toHTMLDateString', createStaticDateFormatter('toHTMLDateString')); + +/** @see [[DateConstructor.long]] */ +extend(Date, 'long', createStaticDateFormatter('long')); + +/** @see [[DateConstructor.medium]] */ +extend(Date, 'medium', createStaticDateFormatter('medium')); + +/** @see [[DateConstructor.short]] */ +extend(Date, 'short', createStaticDateFormatter('short')); + /** @see [[DateConstructor.toHTMLString]] */ extend(Date, 'toHTMLString', createStaticDateFormatter('toHTMLString')); + +/** @see [[DateConstructor.toHTMLTimeString]] */ +extend(Date, 'toHTMLTimeString', createStaticDateFormatter('toHTMLTimeString')); +//#endif diff --git a/src/core/prelude/date/helpers.ts b/src/core/prelude/date/helpers.ts index b540aca30..bc52c7a3c 100644 --- a/src/core/prelude/date/helpers.ts +++ b/src/core/prelude/date/helpers.ts @@ -6,6 +6,16 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { + + isPlainObject, + isString, + isNumber, + isBoolean + +} from 'core/prelude/types'; +import { create } from 'core/prelude/date/create'; + /** * Factory to create functions to modify date values * @param mod @@ -112,7 +122,7 @@ export function createDateModifier(mod: (val: number, base: number) => number = */ export function createStaticDateModifier(method: string): AnyFunction { return (date: Date | DateSetParams, units: DateSetParams | boolean, reset?: boolean) => { - if (Object.isPlainObject(date) || Object.isBoolean(units)) { + if (isPlainObject(date) || isBoolean(units)) { reset = Boolean(units); units = date; return (date) => Date[Symbol.for('[[V4_EXTEND_API]]')][method](date, units, reset); @@ -132,8 +142,8 @@ export function createStaticDateComparator(method: string): AnyFunction { date2: DateCreateValue, margin?: number ): boolean | AnyFunction { - if (arguments.length < 2 || arguments.length < 3 && Object.isNumber(date1)) { - if (Object.isNumber(date1)) { + if (arguments.length < 2 || arguments.length < 3 && isNumber(date1)) { + if (isNumber(date1)) { margin = date1; date1 = date2; } @@ -141,7 +151,7 @@ export function createStaticDateComparator(method: string): AnyFunction { return (date2, m) => Date[Symbol.for('[[V4_EXTEND_API]]')][method](date1, date2, margin ?? m); } - return Date.create(date1)[method](date2, margin); + return create(date1)[method](date2, margin); }; } @@ -151,7 +161,7 @@ export function createStaticDateComparator(method: string): AnyFunction { */ export function createStaticDateFormatter(method: string): AnyFunction { return (date: Date | string | DateHTMLTimeStringOptions, opts?: string | DateHTMLTimeStringOptions) => { - if (Object.isString(date) || Object.isPlainObject(date)) { + if (isString(date) || isPlainObject(date)) { opts = date; return (date) => Date[Symbol.for('[[V4_EXTEND_API]]')][method](date, opts); } diff --git a/src/core/prelude/date/modify/index.ts b/src/core/prelude/date/modify/index.ts index db3adc078..48d3633dc 100644 --- a/src/core/prelude/date/modify/index.ts +++ b/src/core/prelude/date/modify/index.ts @@ -10,19 +10,21 @@ import extend from 'core/prelude/extend'; import { createDateModifier, createStaticDateModifier } from 'core/prelude/date/helpers'; /** @see [[Date.add]] */ -extend(Date.prototype, 'add', createDateModifier((v, b) => b + v)); - -/** @see [[DateConstructor.add]] */ -extend(Date, 'add', createStaticDateModifier('add')); +export const add = extend(Date.prototype, 'add', createDateModifier((v, b) => b + v)); /** @see [[Date.set]] */ -extend(Date.prototype, 'set', createDateModifier()); - -/** @see [[DateConstructor.set]] */ -extend(Date, 'set', createStaticDateModifier('set')); +export const set = extend(Date.prototype, 'set', createDateModifier()); /** @see [[Date.rewind]] */ -extend(Date.prototype, 'rewind', createDateModifier((v, b) => b - v)); +export const rewind = extend(Date.prototype, 'rewind', createDateModifier((v, b) => b - v)); +//#if prelude/standalone /** @see [[DateConstructor.rewind]] */ extend(Date, 'rewind', createStaticDateModifier('rewind')); + +/** @see [[DateConstructor.set]] */ +extend(Date, 'set', createStaticDateModifier('set')); + +/** @see [[DateConstructor.add]] */ +extend(Date, 'add', createStaticDateModifier('add')); +//#endif diff --git a/src/core/prelude/date/relative/index.ts b/src/core/prelude/date/relative/index.ts index 339ae6e0f..13aee821e 100644 --- a/src/core/prelude/date/relative/index.ts +++ b/src/core/prelude/date/relative/index.ts @@ -8,29 +8,18 @@ import extend from 'core/prelude/extend'; +import { create } from 'core/prelude/date/create'; + /** @see [[Date.relative]] */ -extend(Date.prototype, 'relative', function relative(this: Date): DateRelative { +export const relative = extend(Date.prototype, 'relative', function relative(this: Date): DateRelative { return getRelative(this, new Date()); }); -/** @see [[DateConstructor.relative]] */ -extend(Date, 'relative', (date: DateCreateValue) => Date.create(date).relative()); - /** @see [[Date.relativeTo]] */ -extend(Date.prototype, 'relativeTo', function relativeTo(this: Date, date: DateCreateValue): DateRelative { +export const relativeTo = extend(Date.prototype, 'relativeTo', function relativeTo(this: Date, date: DateCreateValue): DateRelative { return getRelative(this, date); }); -/** @see [[DateConstructor.relativeTo]] */ -extend(Date, 'relativeTo', function relativeTo(from: DateCreateValue, to: DateCreateValue): DateRelative | AnyFunction { - if (arguments.length === 1) { - const d = Date.create(from); - return (date2) => d.relativeTo(date2); - } - - return Date.create(from).relativeTo(to); -}); - /** * Returns a relative value of the date for another date * @@ -39,7 +28,7 @@ extend(Date, 'relativeTo', function relativeTo(from: DateCreateValue, to: DateCr */ export function getRelative(from: DateCreateValue, to: DateCreateValue): DateRelative { const - diff = Date.create(to).valueOf() - Date.create(from).valueOf(); + diff = create(to).valueOf() - create(from).valueOf(); const intervals = [ {type: 'milliseconds', bound: 1e3}, @@ -74,3 +63,18 @@ export function getRelative(from: DateCreateValue, to: DateCreateValue): DateRel diff }; } + +//#if prelude/standalone +/** @see [[DateConstructor.relativeTo]] */ +extend(Date, 'relativeTo', function relativeTo(from: DateCreateValue, to: DateCreateValue): DateRelative | AnyFunction { + if (arguments.length === 1) { + const d = Date.create(from); + return (date2) => d.relativeTo(date2); + } + + return Date.create(from).relativeTo(to); +}); + +/** @see [[DateConstructor.relative]] */ +extend(Date, 'relative', (date: DateCreateValue) => Date.create(date).relative()); +//#endif diff --git a/src/core/prelude/env/index.ts b/src/core/prelude/env/index.ts index 25a405f41..27cd97195 100644 --- a/src/core/prelude/env/index.ts +++ b/src/core/prelude/env/index.ts @@ -11,10 +11,13 @@ import type { AsyncStorageNamespace } from 'core/kv-storage'; import { emitter } from 'core/prelude/env/const'; +import { createDict } from 'core/prelude/object/create'; +import { isPromise } from 'core/prelude/types'; + export * from 'core/prelude/env/const'; const - memoryStorage = Object.createDict(); + memoryStorage = createDict(); let storage: CanUndef>; @@ -29,7 +32,7 @@ storage = import('core/kv-storage').then(({asyncLocal}) => asyncLocal.namespace( * @param key */ export async function get(key: string): Promise> { - if (Object.isPromise(storage)) { + if (isPromise(storage)) { return (await storage).get(key); } @@ -43,7 +46,7 @@ export async function get(key: string): Promise> { * @param value */ export function set(key: string, value: Dictionary): void { - if (Object.isPromise(storage)) { + if (isPromise(storage)) { storage.then((storage) => storage.set(key, value)).catch(stderr); } else { @@ -58,7 +61,7 @@ export function set(key: string, value: Dictionary): void { * @param key */ export function remove(key: string): void { - if (Object.isPromise(storage)) { + if (isPromise(storage)) { storage.then((storage) => storage.remove(key)).catch(stderr); } else { @@ -69,7 +72,7 @@ export function remove(key: string): void { } extend(globalThis, 'envs', () => { - if (Object.isPromise(storage)) { + if (isPromise(storage)) { return storage; } diff --git a/src/core/prelude/extend/index.ts b/src/core/prelude/extend/index.ts index 583403598..53344eea9 100644 --- a/src/core/prelude/extend/index.ts +++ b/src/core/prelude/extend/index.ts @@ -13,53 +13,14 @@ * @param name - method name * @param method */ -export default function extend(obj: Function | object, name: string, method: Function | PropertyDescriptor): void { - const descriptor: PropertyDescriptor = { - configurable: true - }; - - if (typeof method === 'function') { - descriptor.writable = true; - descriptor.value = method; - - } else { - Object.assign(descriptor, method); - } - - const - dictKey = Symbol.for('[[V4_EXTEND_API]]'); - - if (!(dictKey in obj)) { - Object.defineProperty(obj, dictKey, { - value: Object.create(null) - }); - } - - Object.defineProperty(obj[dictKey], name, descriptor); - - //#if runtime has noGlobals - - const key = Symbol.for(`[[V4_PROP_TRAP:${name}]]`); - Object.defineProperty(obj, key, descriptor); - - if (obj === Function.prototype || typeof obj !== 'function' && obj !== Object.prototype) { - Object.defineProperty(Object.prototype, key, { - configurable: true, - - set(val: unknown): void { - this[name] = val; - }, - - get(): unknown { - return this[name]; - } - }); +export default function extend< + T + >(obj: Function | object, + name: string, + method: AnyFunction | PropertyDescriptor): T { + if (obj === globalThis) { + obj[name] = method; } - //#endif - //#unless runtime has noGlobals - - Object.defineProperty(obj, name, descriptor); - - //#endunless + return method; } diff --git a/src/core/prelude/function/compose/index.ts b/src/core/prelude/function/compose/index.ts index a2cd34670..b2e8f989f 100644 --- a/src/core/prelude/function/compose/index.ts +++ b/src/core/prelude/function/compose/index.ts @@ -8,6 +8,39 @@ import extend from 'core/prelude/extend'; +import { isPromise } from 'core/prelude/types'; + +/** @see [[Function.compose]] */ +export const compose = extend(Function.prototype, 'compose', function compose( + this: AnyFunction, + ...fns: Array> +): AnyFunction { + const + that = this; + + return function wrapper(this: unknown, ...args: unknown[]): unknown { + let + res = that.apply(this, args); + + for (let i = 0; i < fns.length; i++) { + const + fn = fns[i]; + + if (fn != null) { + if (isPromise(res)) { + res = res.then((res) => fn.call(this, res)); + + } else { + res = fn.call(this, res); + } + } + } + + return res; + }; +}); + +//#if prelude/standalone /** @see [[FunctionConstructor.compose]] */ extend(Function, 'compose', (...fns: Array>) => function wrapper(this: unknown, ...args: unknown[]): unknown { if (fns.length === 0) { @@ -44,33 +77,4 @@ extend(Function, 'compose', (...fns: Array>) => function w return res; }); - -/** @see [[Function.compose]] */ -extend(Function.prototype, 'compose', function compose( - this: AnyFunction, - ...fns: Array> -): AnyFunction { - const - that = this; - - return function wrapper(this: unknown, ...args: unknown[]): unknown { - let - res = that.apply(this, args); - - for (let i = 0; i < fns.length; i++) { - const - fn = fns[i]; - - if (fn != null) { - if (Object.isPromise(res)) { - res = res.then((res) => fn.call(this, res)); - - } else { - res = fn.call(this, res); - } - } - } - - return res; - }; -}); +//#endif diff --git a/src/core/prelude/function/curry/index.ts b/src/core/prelude/function/curry/index.ts index 5512af799..cfee8d90d 100644 --- a/src/core/prelude/function/curry/index.ts +++ b/src/core/prelude/function/curry/index.ts @@ -9,15 +9,8 @@ import extend from 'core/prelude/extend'; import { __ } from 'core/prelude/function/const'; -/** @see [[FunctionConstructor.__]] */ -extend(Function, '__', { - get(): typeof __ { - return __; - } -}); - /** @see [[Function.curry]] */ -extend(Function.prototype, 'curry', function curry(this: AnyFunction): AnyFunction { +export const curry = extend(Function.prototype, 'curry', function curry(this: AnyFunction): AnyFunction { const // eslint-disable-next-line @typescript-eslint/no-this-alias fn = this; @@ -78,5 +71,14 @@ extend(Function.prototype, 'curry', function curry(this: AnyFunction): AnyFuncti } }); +//#if prelude/standalone /** @see [[FunctionConstructor.curry]] */ extend(Function, 'curry', (fn: AnyFunction) => fn.curry()); + +/** @see [[FunctionConstructor.__]] */ +extend(Function, '__', { + get(): typeof __ { + return __; + } +}); +//#endif diff --git a/src/core/prelude/function/extend.ts b/src/core/prelude/function/extend.ts index 270fb8459..25254985e 100644 --- a/src/core/prelude/function/extend.ts +++ b/src/core/prelude/function/extend.ts @@ -8,8 +8,10 @@ import extend from 'core/prelude/extend'; +import { isDictionary } from 'core/prelude/types'; + /** @see [[Function.addToPrototype]] */ -extend(Function.prototype, 'addToPrototype', function addToPrototype( +export const addToPrototype = extend(Function.prototype, 'addToPrototype', function addToPrototype( this: AnyFunction, ...args: Array | Function> ): AnyFunction { @@ -20,7 +22,7 @@ extend(Function.prototype, 'addToPrototype', function addToPrototype( const arg = args[i]; - if (Object.isDictionary(arg)) { + if (isDictionary(arg)) { Object.assign(prototype, arg); } else { diff --git a/src/core/prelude/function/lazy/index.ts b/src/core/prelude/function/lazy/index.ts index c2ea34a82..f3e7f1f68 100644 --- a/src/core/prelude/function/lazy/index.ts +++ b/src/core/prelude/function/lazy/index.ts @@ -8,8 +8,10 @@ import extend from 'core/prelude/extend'; +import { isNumber } from 'core/prelude/types'; + /** @see [[Function.debounce]] */ -extend(Function.prototype, 'debounce', function debounce(this: AnyFunction, delay: number = 250): AnyFunction { +export const debounce = extend(Function.prototype, 'debounce', function debounce(this: AnyFunction, delay: number = 250): AnyFunction { const // eslint-disable-next-line @typescript-eslint/no-this-alias fn = this; @@ -32,25 +34,15 @@ extend(Function.prototype, 'debounce', function debounce(this: AnyFunction, dela }; }); -/** @see [[FunctionConstructor.debounce]] */ -extend(Function, 'debounce', (fn: AnyFunction | number, delay?: number) => { - if (Object.isNumber(fn)) { - delay = fn; - return (fn) => Function.debounce(fn, delay); - } - - return fn.debounce(delay); -}); - /** @see [[Function.throttle]] */ -extend(Function.prototype, 'throttle', function throttle( +export const throttle = extend(Function.prototype, 'throttle', function throttle( this: AnyFunction, delayOrOpts?: number | ThrottleOptions ): AnyFunction { let opts: ThrottleOptions = {}; - if (Object.isNumber(delayOrOpts)) { + if (isNumber(delayOrOpts)) { opts.delay = delayOrOpts; } else { @@ -91,6 +83,7 @@ extend(Function.prototype, 'throttle', function throttle( }; }); +//#if prelude/standalone /** @see [[FunctionConstructor.throttle]] */ extend(Function, 'throttle', (fn: AnyFunction | number, delayOrOpts?: number | ThrottleOptions) => { if (!Object.isFunction(fn)) { @@ -100,3 +93,14 @@ extend(Function, 'throttle', (fn: AnyFunction | number, delayOrOpts?: number | T return fn.throttle(Object.cast(delayOrOpts)); }); + +/** @see [[FunctionConstructor.debounce]] */ +extend(Function, 'debounce', (fn: AnyFunction | number, delay?: number) => { + if (Object.isNumber(fn)) { + delay = fn; + return (fn) => Function.debounce(fn, delay); + } + + return fn.debounce(delay); +}); +//#endif diff --git a/src/core/prelude/function/memoize/index.ts b/src/core/prelude/function/memoize/index.ts index bbc02e560..c8d6ef304 100644 --- a/src/core/prelude/function/memoize/index.ts +++ b/src/core/prelude/function/memoize/index.ts @@ -9,7 +9,7 @@ import extend from 'core/prelude/extend'; /** @see [[Function.once]] */ -extend(Function.prototype, 'once', function once(this: AnyFunction): AnyFunction { +export const once = extend(Function.prototype, 'once', function once(this: AnyFunction): AnyFunction { const // eslint-disable-next-line @typescript-eslint/no-this-alias fn = this; @@ -29,5 +29,7 @@ extend(Function.prototype, 'once', function once(this: AnyFunction): AnyFunction }; }); +//#if prelude/standalone /** @see [[FunctionConstructor.once]] */ extend(Function, 'once', (fn: AnyFunction) => fn.once()); +//#endif diff --git a/src/core/prelude/function/monad/index.ts b/src/core/prelude/function/monad/index.ts index edcba2493..a20539c0e 100644 --- a/src/core/prelude/function/monad/index.ts +++ b/src/core/prelude/function/monad/index.ts @@ -7,27 +7,29 @@ */ import extend from 'core/prelude/extend'; -import { Option, Result } from 'core/prelude/structures'; +import { Option as OptionStructure, Result as OptionResult } from 'core/prelude/structures'; + +import { isFunction } from 'core/prelude/types'; /** @see [[Function.option]] */ -extend(Function.prototype, 'option', function option(this: AnyFunction): AnyFunction { +export const option = extend(Function.prototype, 'option', function option(this: AnyFunction): AnyFunction { const wrapper = (...args) => { const fst = args[0]; if (fst == null) { - return Option.reject(null); + return OptionStructure.reject(null); } - if (fst instanceof Option || fst instanceof Result) { + if (fst instanceof OptionStructure || fst instanceof OptionResult) { return fst.then((value) => wrapper(value, ...args.slice(1))); } try { - return Option.resolve(this(...args)); + return OptionStructure.resolve(this(...args)); } catch (err) { - return Option.reject(err); + return OptionStructure.reject(err); } }; @@ -35,33 +37,33 @@ extend(Function.prototype, 'option', function option(this: AnyFunction): AnyFunc }); /** @see [[ObjectConstructor.Option]] */ -extend(Object, 'Option', (value: unknown) => { +export const Option = extend(Object, 'Option', (value: unknown) => { if (value == null) { - return Option.reject(null); + return OptionStructure.reject(null); } - if (Object.isFunction(value)) { + if (isFunction(value)) { return value.option(); } - return Option.resolve(value); + return OptionStructure.resolve(value); }); /** @see [[Function.result]] */ -extend(Function.prototype, 'result', function result(this: AnyFunction): AnyFunction { +export const result = extend(Function.prototype, 'result', function result(this: AnyFunction): AnyFunction { const wrapper = (...args) => { const fst = args[0]; - if (fst instanceof Option || fst instanceof Result) { + if (fst instanceof OptionStructure || fst instanceof OptionResult) { return fst.then((value) => wrapper(value, ...args.slice(1))); } try { - return Result.resolve(this(...args)); + return OptionResult.resolve(this(...args)); } catch (err) { - return Result.reject(err); + return OptionResult.reject(err); } }; @@ -69,14 +71,14 @@ extend(Function.prototype, 'result', function result(this: AnyFunction): AnyFunc }); /** @see [[ObjectConstructor.Result]] */ -extend(Object, 'Result', (value: unknown) => { +export const Result = extend(Object, 'Result', (value: unknown) => { if (value instanceof Error) { - return Result.reject(value); + return OptionResult.reject(value); } - if (Object.isFunction(value)) { + if (isFunction(value)) { return value.result(); } - return Result.resolve(value); + return OptionResult.resolve(value); }); diff --git a/src/core/prelude/global/const.ts b/src/core/prelude/global/const.ts index 3856fa79f..bc9cf0350 100644 --- a/src/core/prelude/global/const.ts +++ b/src/core/prelude/global/const.ts @@ -6,7 +6,9 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ -export const errorsToIgnore = Object.createDict({ +import { createDict } from 'core/prelude/object/create'; + +export const errorsToIgnore = createDict({ clearAsync: true, abort: true }); diff --git a/src/core/prelude/global/index.ts b/src/core/prelude/global/index.ts index cdb899564..4aee036a5 100644 --- a/src/core/prelude/global/index.ts +++ b/src/core/prelude/global/index.ts @@ -24,3 +24,14 @@ extend(globalThis, 'stderr', (err) => { log.error('stderr', err); } }); + +export const stderr = (err: any): void => { + if (err instanceof Object) { + if (errorsToIgnore[err.type] === true) { + log.info('stderr', err); + return; + } + + log.error('stderr', err); + } +}; diff --git a/src/core/prelude/i18n/const.ts b/src/core/prelude/i18n/const.ts index b7c7acb01..e35abc78c 100644 --- a/src/core/prelude/i18n/const.ts +++ b/src/core/prelude/i18n/const.ts @@ -9,6 +9,8 @@ import { EventEmitter2 as EventEmitter } from 'eventemitter2'; import type { Locale } from 'core/prelude/i18n/interface'; +import { createDict } from 'core/prelude/object/create'; + /** * The event emitter to broadcast localization events */ @@ -33,7 +35,7 @@ export const locale: Locale = { /** * A dictionary to map literal pluralization forms to numbers */ -export const pluralizeMap = Object.createDict({ +export const pluralizeMap = createDict({ none: 0, one: 1, some: 2, diff --git a/src/core/prelude/i18n/helpers.ts b/src/core/prelude/i18n/helpers.ts index 5cf6a1dd4..eebc7f5db 100644 --- a/src/core/prelude/i18n/helpers.ts +++ b/src/core/prelude/i18n/helpers.ts @@ -14,6 +14,8 @@ import langPacs, { Translation, PluralTranslation } from 'lang'; import { locale, pluralizeMap } from 'core/prelude/i18n/const'; import type { PluralizationCount } from 'core/prelude/i18n/interface'; +import { isArray, isString, isNumber } from 'core/prelude/types'; + /** @see [[i18n]] */ extend(globalThis, 'i18n', i18nFactory); @@ -38,19 +40,19 @@ export function i18nFactory( ): (key: string, params?: I18nParams) => string { const resolvedLocale = customLocale ?? locale.value, - keysetNames = Object.isArray(keysetNameOrNames) ? keysetNameOrNames : [keysetNameOrNames]; + keysetNames = isArray(keysetNameOrNames) ? keysetNameOrNames : [keysetNameOrNames]; if (resolvedLocale == null) { throw new ReferenceError('The locale for internationalization is not defined'); } return function i18n(value: string | TemplateStringsArray, params?: I18nParams) { - if (Object.isArray(value) && value.length !== 1) { + if (isArray(value) && value.length !== 1) { throw new SyntaxError('Using i18n with template literals is allowed only without variables'); } const - key = Object.isString(value) ? value : value[0], + key = isString(value) ? value : value[0], correctKeyset = keysetNames.find((keysetName) => langPacs[resolvedLocale]?.[keysetName]?.[key]), translateValue = langPacs[resolvedLocale]?.[correctKeyset ?? '']?.[key]; @@ -87,7 +89,7 @@ export function i18nFactory( */ export function resolveTemplate(value: Translation, params?: I18nParams): string { const - template = Object.isArray(value) ? pluralizeText(value, params?.count) : value; + template = isArray(value) ? pluralizeText(value, params?.count) : value; return template.replace(/{([^}]+)}/g, (_, key) => { if (params?.[key] == null) { @@ -120,10 +122,10 @@ export function resolveTemplate(value: Translation, params?: I18nParams): string export function pluralizeText(pluralTranslation: PluralTranslation, count: CanUndef): string { let normalizedCount; - if (Object.isNumber(count)) { + if (isNumber(count)) { normalizedCount = count; - } else if (Object.isString(count)) { + } else if (isString(count)) { if (count in pluralizeMap) { normalizedCount = pluralizeMap[count]; } diff --git a/src/core/prelude/number/const.ts b/src/core/prelude/number/const.ts index 4d54e786d..5f45126f0 100644 --- a/src/core/prelude/number/const.ts +++ b/src/core/prelude/number/const.ts @@ -6,31 +6,33 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { createDict } from 'core/prelude/object/create'; + export const - formatCache = Object.createDict(); + formatCache = createDict(); export const decPartRgxp = /\.\d+/; -export const globalFormatOpts = Object.createDict({ +export const globalFormatOpts = createDict({ init: false, decimal: '.', thousands: ',' }); -export const formatAliases = Object.createDict({ +export const formatAliases = createDict({ $: 'currency', $d: 'currencyDisplay', '%': 'percent', '.': 'decimal' }); -export const boolAliases = Object.createDict({ +export const boolAliases = createDict({ '+': true, '-': false }); -export const defaultFormats = Object.createDict({ +export const defaultFormats = createDict({ style: 'decimal', currency: 'USD', currencyDisplay: 'symbol' diff --git a/src/core/prelude/number/converters/index.ts b/src/core/prelude/number/converters/index.ts index 35399b5c0..e4d8831dc 100644 --- a/src/core/prelude/number/converters/index.ts +++ b/src/core/prelude/number/converters/index.ts @@ -12,77 +12,79 @@ import extend from 'core/prelude/extend'; import { createMsFunction, createStaticMsFunction, createStringTypeGetter } from 'core/prelude/number/helpers'; const - second = 1e3, - minute = 60 * second, - hour = 60 * minute, - day = 24 * hour, - week = 7 * day; + secondInMs = 1e3, + minuteInMs = 60 * secondInMs, + hourInMs = 60 * minuteInMs, + dayInMs = 24 * hourInMs, + weekInMs = 7 * dayInMs; /** @see [[Number.second]] */ -extend(Number.prototype, 'second', createMsFunction(second)); +export const second: PropertyDescriptor = extend(Number.prototype, 'second', createMsFunction(secondInMs)); /** @see [[Number.seconds]] */ -extend(Number.prototype, 'seconds', Number.prototype.second); - -/** @see [[NumberConstructor.second]] */ -extend(Number, 'seconds', createStaticMsFunction(second)); +export const seconds = extend(Number.prototype, 'seconds', second); /** @see [[Number.minute]] */ -extend(Number.prototype, 'minute', createMsFunction(minute)); +export const minute: PropertyDescriptor = extend(Number.prototype, 'minute', createMsFunction(minuteInMs)); /** @see [[Number.minutes]] */ -extend(Number.prototype, 'minutes', Number.prototype.minute); - -/** @see [[NumberConstructor.minutes]] */ -extend(Number, 'minutes', createStaticMsFunction(minute)); +export const minutes = extend(Number.prototype, 'minutes', minute); /** @see [[Number.hour]] */ -extend(Number.prototype, 'hour', createMsFunction(hour)); +export const hour: PropertyDescriptor = extend(Number.prototype, 'hour', createMsFunction(hourInMs)); /** @see [[Number.hours]] */ -extend(Number.prototype, 'hours', Number.prototype.hour); - -/** @see [[NumberConstructor.hours]] */ -extend(Number, 'hours', createStaticMsFunction(hour)); +export const hours = extend(Number.prototype, 'hours', hour); /** @see [[Number.day]] */ -extend(Number.prototype, 'day', createMsFunction(day)); +export const day: PropertyDescriptor = extend(Number.prototype, 'day', createMsFunction(dayInMs)); /** @see [[Number.days]] */ -extend(Number.prototype, 'days', Number.prototype.day); - -/** @see [[NumberConstructor.days]] */ -extend(Number, 'days', createStaticMsFunction(day)); +export const days = extend(Number.prototype, 'days', day); /** @see [[Number.week]] */ -extend(Number.prototype, 'week', createMsFunction(week)); +export const week: PropertyDescriptor = extend(Number.prototype, 'week', createMsFunction(weekInMs)); /** @see [[Number.weeks]] */ -extend(Number.prototype, 'weeks', Number.prototype.week); - -/** @see [[NumberConstructor.weeks]] */ -extend(Number, 'weeks', createStaticMsFunction(week)); +export const weeks = extend(Number.prototype, 'weeks', week); /** @see [[Number.em]] */ -extend(Number.prototype, 'em', createStringTypeGetter('em')); +export const em = extend(Number.prototype, 'em', createStringTypeGetter('em')); /** @see [[Number.rem]] */ -extend(Number.prototype, 'rem', createStringTypeGetter('rem')); +export const rem = extend(Number.prototype, 'rem', createStringTypeGetter('rem')); /** @see [[Number.px]] */ -extend(Number.prototype, 'px', createStringTypeGetter('px')); +export const px = extend(Number.prototype, 'px', createStringTypeGetter('px')); /** @see [[Number.per]] */ -extend(Number.prototype, 'per', createStringTypeGetter('per')); +export const per = extend(Number.prototype, 'per', createStringTypeGetter('per')); /** @see [[Number.vh]] */ -extend(Number.prototype, 'vh', createStringTypeGetter('vh')); +export const vh = extend(Number.prototype, 'vh', createStringTypeGetter('vh')); /** @see [[Number.vw]] */ -extend(Number.prototype, 'vw', createStringTypeGetter('vw')); +export const vw = extend(Number.prototype, 'vw', createStringTypeGetter('vw')); /** @see [[Number.vmin]] */ -extend(Number.prototype, 'vmin', createStringTypeGetter('vmin')); +export const vmin = extend(Number.prototype, 'vmin', createStringTypeGetter('vmin')); /** @see [[Number.vmax]] */ -extend(Number.prototype, 'vmax', createStringTypeGetter('vmax')); +export const vmax = extend(Number.prototype, 'vmax', createStringTypeGetter('vmax')); + +//#if prelude/standalone +/** @see [[NumberConstructor.weeks]] */ +extend(Number, 'weeks', createStaticMsFunction(weekInMs)); + +/** @see [[NumberConstructor.days]] */ +extend(Number, 'days', createStaticMsFunction(dayInMs)); + +/** @see [[NumberConstructor.hours]] */ +extend(Number, 'hours', createStaticMsFunction(hourInMs)); + +/** @see [[NumberConstructor.second]] */ +extend(Number, 'seconds', createStaticMsFunction(secondInMs)); + +/** @see [[NumberConstructor.minutes]] */ +extend(Number, 'minutes', createStaticMsFunction(minuteInMs)); +//#endif diff --git a/src/core/prelude/number/format/index.ts b/src/core/prelude/number/format/index.ts index f6857b778..ea4900ffd 100644 --- a/src/core/prelude/number/format/index.ts +++ b/src/core/prelude/number/format/index.ts @@ -11,6 +11,15 @@ import extend from 'core/prelude/extend'; import { deprecate } from 'core/functools'; import { locale as defaultLocale } from 'core/prelude/i18n'; +import { + + isPlainObject, + isNumber, + isString, + cast + +} from 'core/prelude/types'; + import { globalFormatOpts, @@ -27,15 +36,15 @@ import { import { repeatString } from 'core/prelude/number/helpers'; /** @see [[Number.pad]] */ -extend(Number.prototype, 'pad', function pad( +export const pad = extend(Number.prototype, 'pad', function pad( this: number, lengthOrOpts: number | NumberPadOptions = 0, opts?: NumberPadOptions ): string { - opts = {...Object.isPlainObject(lengthOrOpts) ? lengthOrOpts : opts}; + opts = {...isPlainObject(lengthOrOpts) ? lengthOrOpts : opts}; if (opts.length == null) { - opts.length = Object.isNumber(lengthOrOpts) ? lengthOrOpts : 0; + opts.length = isNumber(lengthOrOpts) ? lengthOrOpts : 0; } const @@ -51,18 +60,8 @@ extend(Number.prototype, 'pad', function pad( return str; }); -/** @see [[NumberConstructor.pad]] */ -extend(Number, 'pad', (value: number | NumberPadOptions, lengthOrOpts: number | NumberPadOptions) => { - if (Object.isPlainObject(value)) { - const opts = value; - return (value) => Number.pad(value, opts); - } - - return value.pad(Object.cast(lengthOrOpts)); -}); - /** @see [[Number.format]] */ -extend(Number.prototype, 'format', function format( +export const format = extend(Number.prototype, 'format', function format( this: number, patternOrOpts?: number | string | Intl.NumberFormatOptions, locale: CanUndef> = defaultLocale.value @@ -71,11 +70,11 @@ extend(Number.prototype, 'format', function format( return this.toLocaleString(locale); } - if (Object.isPlainObject(patternOrOpts)) { + if (isPlainObject(patternOrOpts)) { return this.toLocaleString(locale, patternOrOpts); } - if (Object.isString(patternOrOpts)) { + if (isString(patternOrOpts)) { const pattern = patternOrOpts, cacheKey = [locale, pattern].join(); @@ -175,19 +174,20 @@ extend(Number.prototype, 'format', function format( return res; }); +//#if prelude/standalone /** @see [[NumberConstructor.format]] */ extend(Number, 'format', ( value: number | string | Intl.NumberFormatOptions, patternOrOpts?: string | Intl.NumberFormatOptions, locale?: CanArray ) => { - if (Object.isString(value) || Object.isPlainObject(value)) { - locale = Object.cast(patternOrOpts); + if (isString(value) || isPlainObject(value)) { + locale = cast(patternOrOpts); patternOrOpts = value; - return (value) => Number.format(value, Object.cast(patternOrOpts), locale); + return (value) => Number.format(value, cast(patternOrOpts), locale); } - return value.format(Object.cast(patternOrOpts), locale); + return value.format(cast(patternOrOpts), locale); }); /** @see [[NumberConstructor.getOption]] */ @@ -200,3 +200,14 @@ extend(Number, 'setOption', deprecate(function setOption(key: string, value: str globalFormatOpts.init = true; globalFormatOpts[key] = value; })); + +/** @see [[NumberConstructor.pad]] */ +extend(Number, 'pad', (value: number | NumberPadOptions, lengthOrOpts: number | NumberPadOptions) => { + if (isPlainObject(value)) { + const opts = value; + return (value) => Number.pad(value, opts); + } + + return value.pad(cast(lengthOrOpts)); +}); +//#endif diff --git a/src/core/prelude/number/metrics/index.ts b/src/core/prelude/number/metrics/index.ts index b118077dd..5a62b7913 100644 --- a/src/core/prelude/number/metrics/index.ts +++ b/src/core/prelude/number/metrics/index.ts @@ -9,89 +9,91 @@ import extend from 'core/prelude/extend'; /** @see [[Number.isSafe]] */ -extend(Number.prototype, 'isSafe', function isSafe(this: number): boolean { +export const isSafe = extend(Number.prototype, 'isSafe', function isSafe(this: number): boolean { return this >= Number.MIN_SAFE_INTEGER && this <= Number.MAX_SAFE_INTEGER; }); -/** @see [[NumberConstructor.isSafe]] */ -extend(Number, 'isSafe', (value) => Object.isNumber(value) && value.isSafe()); - /** @see [[Number.isInteger]] */ -extend(Number.prototype, 'isInteger', function isInteger(this: number): boolean { +export const isInteger = extend(Number.prototype, 'isInteger', function isInteger(this: number): boolean { return this % 1 === 0; }); -/** @see [[NumberConstructor.isInteger]] */ -extend(Number, 'isInteger', (value) => Object.isNumber(value) && value.isInteger()); - /** @see [[Number.isFloat]] */ -extend(Number.prototype, 'isFloat', function isFloat(this: number): boolean { +export const isFloat = extend(Number.prototype, 'isFloat', function isFloat(this: number): boolean { return Number.isFinite(this) && this % 1 !== 0; }); -/** @see [[NumberConstructor.isFloat]] */ -extend(Number, 'isFloat', (value) => Object.isNumber(value) && value.isFloat()); - /** @see [[Number.isEven]] */ -extend(Number.prototype, 'isEven', function isEven(this: number): boolean { +export const isEven = extend(Number.prototype, 'isEven', function isEven(this: number): boolean { return this % 2 === 0; }); -/** @see [[NumberConstructor.isEven]] */ -extend(Number, 'isEven', (value) => Object.isNumber(value) && value.isEven()); - /** @see [[Number.isOdd]] */ -extend(Number.prototype, 'isOdd', function isOdd(this: number): boolean { +export const isOdd = extend(Number.prototype, 'isOdd', function isOdd(this: number): boolean { return Number.isFinite(this) && this % 2 !== 0; }); -/** @see [[NumberConstructor.isOdd]] */ -extend(Number, 'isOdd', (value) => Object.isNumber(value) && value.isOdd()); - /** @see [[Number.isNatural]] */ -extend(Number.prototype, 'isNatural', function isNatural(this: number): boolean { +export const isNatural = extend(Number.prototype, 'isNatural', function isNatural(this: number): boolean { return this > 0 && this % 1 === 0; }); -/** @see [[NumberConstructor.isNatural]] */ -extend(Number, 'isNatural', (value) => Object.isNumber(value) && value.isNatural()); - /** @see [[Number.isPositive]] */ -extend(Number.prototype, 'isPositive', function isPositive(this: number): boolean { +export const isPositive = extend(Number.prototype, 'isPositive', function isPositive(this: number): boolean { return this > 0; }); -/** @see [[NumberConstructor.isPositive]] */ -extend(Number, 'isPositive', (value) => Object.isNumber(value) && value.isPositive()); - /** @see [[Number.isNegative]] */ -extend(Number.prototype, 'isNegative', function isNegative(this: number): boolean { +export const isNegative = extend(Number.prototype, 'isNegative', function isNegative(this: number): boolean { return this < 0; }); -/** @see [[NumberConstructor.isNegative]] */ -extend(Number, 'isNegative', (value) => Object.isNumber(value) && value.isNegative()); - /** @see [[Number.isNonNegative]] */ -extend(Number.prototype, 'isNonNegative', function isNonNegative(this: number): boolean { +export const isNonNegative = extend(Number.prototype, 'isNonNegative', function isNonNegative(this: number): boolean { return this >= 0; }); -/** @see [[NumberConstructor.isNonNegative]] */ -extend(Number, 'isNonNegative', (value) => Object.isNumber(value) && value.isNonNegative()); - /** @see [[Number.isBetweenZeroAndOne]] */ -extend(Number.prototype, 'isBetweenZeroAndOne', function isBetweenZeroAndOne(this: number): boolean { +export const isBetweenZeroAndOne = extend(Number.prototype, 'isBetweenZeroAndOne', function isBetweenZeroAndOne(this: number): boolean { return this >= 0 && this <= 1; }); -/** @see [[NumberConstructor.isBetweenZeroAndOne]] */ -extend(Number, 'isBetweenZeroAndOne', (value) => Object.isNumber(value) && value.isBetweenZeroAndOne()); - /** @see [[Number.isPositiveBetweenZeroAndOne]] */ -extend(Number.prototype, 'isPositiveBetweenZeroAndOne', function isPositiveBetweenZeroAndOne(this: number): boolean { +export const isPositiveBetweenZeroAndOne = extend(Number.prototype, 'isPositiveBetweenZeroAndOne', function isPositiveBetweenZeroAndOne(this: number): boolean { return this > 0 && this <= 1; }); +//#if prelude/standalone /** @see [[NumberConstructor.isPositiveBetweenZeroAndOne]] */ extend(Number, 'isPositiveBetweenZeroAndOne', (value) => Object.isNumber(value) && value.isPositiveBetweenZeroAndOne()); + +/** @see [[NumberConstructor.isBetweenZeroAndOne]] */ +extend(Number, 'isBetweenZeroAndOne', (value) => Object.isNumber(value) && value.isBetweenZeroAndOne()); + +/** @see [[NumberConstructor.isNonNegative]] */ +extend(Number, 'isNonNegative', (value) => Object.isNumber(value) && value.isNonNegative()); + +/** @see [[NumberConstructor.isNegative]] */ +extend(Number, 'isNegative', (value) => Object.isNumber(value) && value.isNegative()); + +/** @see [[NumberConstructor.isPositive]] */ +extend(Number, 'isPositive', (value) => Object.isNumber(value) && value.isPositive()); + +/** @see [[NumberConstructor.isNatural]] */ +extend(Number, 'isNatural', (value) => Object.isNumber(value) && value.isNatural()); + +/** @see [[NumberConstructor.isOdd]] */ +extend(Number, 'isOdd', (value) => Object.isNumber(value) && value.isOdd()); + +/** @see [[NumberConstructor.isEven]] */ +extend(Number, 'isEven', (value) => Object.isNumber(value) && value.isEven()); + +/** @see [[NumberConstructor.isFloat]] */ +extend(Number, 'isFloat', (value) => Object.isNumber(value) && value.isFloat()); + +/** @see [[NumberConstructor.isInteger]] */ +extend(Number, 'isInteger', (value) => Object.isNumber(value) && value.isInteger()); + +/** @see [[NumberConstructor.isSafe]] */ +extend(Number, 'isSafe', (value) => Object.isNumber(value) && value.isSafe()); +//#endif diff --git a/src/core/prelude/number/rounding/index.ts b/src/core/prelude/number/rounding/index.ts index 7c5db63dc..32003e049 100644 --- a/src/core/prelude/number/rounding/index.ts +++ b/src/core/prelude/number/rounding/index.ts @@ -10,19 +10,21 @@ import extend from 'core/prelude/extend'; import { createRoundingFunction, createStaticRoundingFunction } from 'core/prelude/number/helpers'; /** @see [[Number.floor]] */ -extend(Number.prototype, 'floor', createRoundingFunction(Math.floor)); - -/** @see [[NumberConstructor.floor]] */ -extend(Number, 'floor', createStaticRoundingFunction('floor')); +export const floor = extend(Number.prototype, 'floor', createRoundingFunction(Math.floor)); /** @see [[Number.round]] */ -extend(Number.prototype, 'round', createRoundingFunction(Math.round)); +export const round = extend(Number.prototype, 'round', createRoundingFunction(Math.round)); + +/** @see [[Number.ceil]] */ +export const ceil = extend(Number.prototype, 'ceil', createRoundingFunction(Math.ceil)); +//#if prelude/standalone /** @see [[NumberConstructor.round]] */ extend(Number, 'round', createStaticRoundingFunction('round')); -/** @see [[Number.ceil]] */ -extend(Number.prototype, 'ceil', createRoundingFunction(Math.ceil)); - /** @see [[NumberConstructor.round]] */ extend(Number, 'ceil', createStaticRoundingFunction('ceil')); + +/** @see [[NumberConstructor.floor]] */ +extend(Number, 'floor', createStaticRoundingFunction('floor')); +//#endif diff --git a/src/core/prelude/object/clone/index.ts b/src/core/prelude/object/clone/index.ts index 8c2551a7e..d9e226edf 100644 --- a/src/core/prelude/object/clone/index.ts +++ b/src/core/prelude/object/clone/index.ts @@ -9,15 +9,26 @@ import extend from 'core/prelude/extend'; import type { ValMap } from 'core/prelude/object/clone/interface'; +import { + + isTruly, + isFunction, + isFrozen, + isExtensible, + unwrapProxy, + isSealed + +} from 'core/prelude/types'; + const objRef = '[[OBJ_REF:base]]', valRef = '[[VAL_REF:'; /** @see [[ObjectConstructor.fastClone]] */ -extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { - if (!Object.isTruly(obj)) { +export const fastClone = extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { + if (!isTruly(obj)) { if (opts !== undefined) { - return (obj) => Object.fastClone(obj, opts); + return (obj) => fastClone(obj, opts); } return obj; @@ -31,14 +42,14 @@ extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { const p = opts ?? {}; - if (Object.isFrozen(obj) && p.freezable !== false) { + if (isFrozen(obj) && p.freezable !== false) { return obj; } let clone; - if (Object.isFunction(p.reviver) || Object.isFunction(p.replacer)) { + if (isFunction(p.reviver) || isFunction(p.replacer)) { clone = jsonBasedClone(obj, opts); } else { @@ -51,15 +62,15 @@ extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { } if (p.freezable !== false) { - if (!Object.isExtensible(obj)) { + if (!isExtensible(obj)) { Object.preventExtensions(clone); } - if (Object.isSealed(obj)) { + if (isSealed(obj)) { Object.seal(clone); } - if (Object.isFrozen(obj)) { + if (isFrozen(obj)) { Object.freeze(clone); } } @@ -76,7 +87,7 @@ extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { for (let o = obj.entries(), el = o.next(); !el.done; el = o.next()) { const val = el.value; - map.set(val[0], Object.fastClone(val[1], opts)); + map.set(val[0], fastClone(val[1], opts)); } return map; @@ -87,7 +98,7 @@ extend(Object, 'fastClone', (obj, opts?: FastCloneOptions) => { set = new Set(); for (let o = obj.values(), el = o.next(); !el.done; el = o.next()) { - set.add(Object.fastClone(el.value, opts)); + set.add(fastClone(el.value, opts)); } return set; @@ -197,7 +208,7 @@ export function createSerializer( } } - return Object.unwrapProxy(value); + return unwrapProxy(value); }; } @@ -227,7 +238,7 @@ export function createParser( } } - if (Object.isFunction(reviver)) { + if (isFunction(reviver)) { return reviver(key, value); } diff --git a/src/core/prelude/object/compare/index.ts b/src/core/prelude/object/compare/index.ts index 77f95054c..4c852e2e3 100644 --- a/src/core/prelude/object/compare/index.ts +++ b/src/core/prelude/object/compare/index.ts @@ -9,14 +9,29 @@ import extend from 'core/prelude/extend'; import { funcCache } from 'core/prelude/object/const'; +import { + + unwrapProxy, + cast, + isMap, + isSet, + isArray, + isRegExp, + isDictionary, + isDate, + isTruly, + isFunction + +} from 'core/prelude/types'; + /** @see [[ObjectConstructor.fastCompare]] */ -extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): boolean | AnyFunction { +export const fastCompare = extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): boolean | AnyFunction { if (arguments.length < 2) { - return (b) => Object.fastCompare(a, b); + return (b) => fastCompare(a, b); } - a = Object.unwrapProxy(a); - b = Object.unwrapProxy(b); + a = unwrapProxy(a); + b = unwrapProxy(b); const isEqual = a === b; @@ -38,36 +53,36 @@ extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): bool } const - objA = Object.cast(a), - objB = Object.cast(b); + objA = cast(a), + objB = cast(b); if (objA.constructor !== objB.constructor) { return false; } - if (Object.isRegExp(a)) { + if (isRegExp(a)) { return a.toString() === objB.toString(); } - if (Object.isDate(a)) { + if (isDate(a)) { return a.valueOf() === objB.valueOf(); } const - isArr = Object.isArray(a), - isMap = !isArr && Object.isMap(a), - isSet = !isMap && Object.isSet(a); + isValArr = isArray(a), + isValMap = !isValArr && isMap(a), + isValSet = !isValMap && isSet(a); - const cantJSONCompare = !isArr && !Object.isDictionary(a) && ( - !Object.isFunction(objA['toJSON']) || - !Object.isFunction(objB['toJSON']) + const cantJSONCompare = !isValArr && !isDictionary(a) && ( + !isFunction(objA['toJSON']) || + !isFunction(objB['toJSON']) ); if (cantJSONCompare) { - if ((isMap || isSet)) { + if ((isValMap || isValSet)) { const - setA = Object.cast>(a), - setB = Object.cast>(b); + setA = cast>(a), + setB = cast>(b); if (setA.size !== setB.size) { return false; @@ -86,7 +101,8 @@ extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): bool aVal = aEl.value, bVal = bEl.value; - if (!Object.fastCompare(aVal[0], bVal[0]) || !Object.fastCompare(aVal[1], bVal[1])) { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (!fastCompare(aVal[0], bVal[0]) || !fastCompare(aVal[1], bVal[1])) { return false; } } @@ -101,11 +117,11 @@ extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): bool length1, length2; - if (isArr) { + if (isValArr) { length1 = objA['length']; length2 = objB['length']; - } else if (isMap || isSet) { + } else if (isValMap || isValSet) { length1 = objA['size']; length2 = objB['size']; @@ -129,7 +145,7 @@ extend(Object, 'fastCompare', function fastCompare(a: unknown, b: unknown): bool /** @see [[ObjectConstructor.fastHash]] */ extend(Object, 'fastHash', (obj) => { const res = JSON.stringify(obj, createSerializer(obj, undefined, funcCache)); - return cyrb53(Object.isTruly(res) ? res : 'null'); + return cyrb53(isTruly(res) ? res : 'null'); /* eslint-disable no-bitwise */ @@ -171,7 +187,7 @@ export function createSerializer( return (key, value) => { if (value == null) { init = true; - return Object.unwrapProxy(value); + return unwrapProxy(value); } const @@ -198,9 +214,9 @@ export function createSerializer( } if (isObj && (value instanceof Map || value instanceof Set)) { - return [...Object.unwrapProxy(value).entries()]; + return [...unwrapProxy(value).entries()]; } - return Object.unwrapProxy(value); + return unwrapProxy(value); }; } diff --git a/src/core/prelude/object/convert/index.ts b/src/core/prelude/object/convert/index.ts index 9ad69c368..1e90e3179 100644 --- a/src/core/prelude/object/convert/index.ts +++ b/src/core/prelude/object/convert/index.ts @@ -9,21 +9,35 @@ import extend from 'core/prelude/extend'; import { canParse, isInvalidKey } from 'core/prelude/object/const'; +import { + + isString, + isArray, + isDictionary, + isFunction, + isNumber + +} from 'core/prelude/types'; + +import { test } from 'core/prelude/regexp'; + +import { get } from 'core/prelude/object/property'; + /** @see [[ObjectConstructor.trySerialize]] */ -extend(Object, 'trySerialize', (value, replacer?: JSONCb) => { - if (Object.isFunction(value)) { +export const trySerialize = extend(Object, 'trySerialize', (value, replacer?: JSONCb) => { + if (isFunction(value)) { replacer = value; - return (value) => Object.trySerialize(value, replacer); + return (value) => trySerialize(value, replacer); } let encodedValue; const canSerializeToJSON = - Object.isString(value) || - Object.isArray(value) || - Object.isDictionary(value) || - Object.isFunction(Object.get(value, 'toJSON')); + isString(value) || + isArray(value) || + isDictionary(value) || + isFunction(get(value, 'toJSON')); if (canSerializeToJSON) { try { @@ -37,8 +51,8 @@ extend(Object, 'trySerialize', (value, replacer?: JSONCb) => { encodedValue = value; try { - if (Object.isFunction(replacer)) { - return Object.trySerialize(replacer('', encodedValue), replacer); + if (isFunction(replacer)) { + return trySerialize(replacer('', encodedValue), replacer); } } catch {} } @@ -47,23 +61,23 @@ extend(Object, 'trySerialize', (value, replacer?: JSONCb) => { }); /** @see [[ObjectConstructor.parse]] */ -extend(Object, 'parse', (value, reviver?: JSONCb) => { - if (Object.isFunction(value)) { +export const parse = extend(Object, 'parse', (value, reviver?: JSONCb) => { + if (isFunction(value)) { reviver = value; - return (value) => Object.parse(value, wrapReviver(reviver)); + return (value) => parse(value, wrapReviver(reviver)); } - if (Object.isString(value)) { + if (isString(value)) { if (value === 'undefined') { return; } - if (canParse.test(value)) { + if (test(canParse, value)) { try { const parsedVal = JSON.parse(value, wrapReviver(reviver)); - if (Object.isNumber(parsedVal)) { + if (isNumber(parsedVal)) { return parsedVal.isSafe() ? parsedVal : value; } @@ -71,7 +85,7 @@ extend(Object, 'parse', (value, reviver?: JSONCb) => { } catch {} } - if (Object.isFunction(reviver)) { + if (isFunction(reviver)) { return reviver('', value); } } @@ -80,11 +94,11 @@ extend(Object, 'parse', (value, reviver?: JSONCb) => { function wrapReviver(fn: Nullable) { return (key, value) => { - if (isInvalidKey.test(key)) { + if (test(isInvalidKey, key)) { return; } - if (Object.isFunction(fn)) { + if (isFunction(fn)) { value = fn(key, value); } diff --git a/src/core/prelude/object/create/index.ts b/src/core/prelude/object/create/index.ts index f7b6c54cb..c6361145b 100644 --- a/src/core/prelude/object/create/index.ts +++ b/src/core/prelude/object/create/index.ts @@ -11,8 +11,25 @@ import extend from 'core/prelude/extend'; import { deprecate } from 'core/functools'; import { getSameAs } from 'core/prelude/object/helpers'; +import { + + isArray, + isWeakSet, + isTruly, + isFunction, + isRegExp, + cast, + isSet, + isIterable, + isPrimitive + +} from 'core/prelude/types'; + +import { set } from 'core/prelude/object/property'; +import { forEach } from 'core/prelude/object/iterators'; + /** @see [[ObjectConstructor.createDict]] */ -extend(Object, 'createDict', (...objects) => { +export const createDict = extend(Object, 'createDict', (...objects) => { if (objects.length > 0) { return Object.assign(Object.create(null), ...objects); } @@ -21,9 +38,9 @@ extend(Object, 'createDict', (...objects) => { }); /** @see [[ObjectConstructor.convertEnumToDict]] */ -extend(Object, 'convertEnumToDict', (obj) => { +export const convertEnumToDict = extend(Object, 'convertEnumToDict', (obj) => { const - res = Object.createDict(); + res = createDict(); if (obj == null) { return res; @@ -45,24 +62,24 @@ extend(Object, 'convertEnumToDict', (obj) => { }); /** @see [[ObjectConstructor.createEnumLike]] */ -extend(Object, 'createEnumLike', createEnumLike); +export const createEnumLike = extend(Object, 'createEnumLike', createEnumLikeFunc); /** * @deprecated * @see [[ObjectConstructor.createEnumLike]] */ -extend(Object, 'createMap', deprecate({renamedTo: 'createEnum'}, createEnumLike)); +extend(Object, 'createMap', deprecate({renamedTo: 'createEnum'}, createEnumLikeFunc)); /** @see [[ObjectConstructor.createEnumLike]] */ -export function createEnumLike(obj: Nullable): Dictionary { +export function createEnumLikeFunc(obj: Nullable): Dictionary { const - map = Object.createDict(); + map = createDict(); if (obj == null) { return map; } - if (Object.isArray(obj)) { + if (isArray(obj)) { for (let i = 0; i < obj.length; i++) { const el = obj[i]; map[i] = el; @@ -87,12 +104,12 @@ export function createEnumLike(obj: Nullable): Dictionary { } /** @see [[ObjectConstructor.fromArray]] */ -extend(Object, 'fromArray', ( +export const fromArray = extend(Object, 'fromArray', ( arr: Nullable, opts?: ObjectFromArrayOptions ) => { const - map = Object.createDict(); + map = createDict(); if (arr == null) { return map; @@ -126,13 +143,13 @@ extend(Object, 'fromArray', ( }); /** @see [[ObjectConstructor.select]] */ -extend(Object, 'select', selectReject(true)); +export const select = extend(Object, 'select', selectReject(true)); /** @see [[ObjectConstructor.reject]] */ -extend(Object, 'reject', selectReject(false)); +export const reject = extend(Object, 'reject', selectReject(false)); /** - * Factory to create Object.select/reject functions + * Factory to create select/reject functions * @param select */ export function selectReject(select: boolean): AnyFunction { @@ -141,7 +158,7 @@ export function selectReject(select: boolean): AnyFunction { condition: Iterable | Dictionary | RegExp | Function ): unknown { if (arguments.length === 1) { - condition = Object.cast(obj); + condition = cast(obj); return (obj) => wrapper(obj, condition); } @@ -155,32 +172,32 @@ export function selectReject(select: boolean): AnyFunction { const filter = new Set(); - if (!Object.isRegExp(condition) && !Object.isFunction(condition)) { - if (Object.isPrimitive(condition)) { + if (!isRegExp(condition) && !isFunction(condition)) { + if (isPrimitive(condition)) { filter.add(condition); - } else if (Object.isIterable(condition)) { - Object.forEach(condition, (el) => { + } else if (isIterable(condition)) { + forEach(condition, (el) => { filter.add(el); }); } else { - Object.forEach(condition, (el, key) => { - if (Object.isTruly(el)) { + forEach(condition, (el, key) => { + if (isTruly(el)) { filter.add(key); } }); } } - Object.forEach(obj, (el, key) => { + forEach(obj, (el, key) => { let test: boolean; - if (Object.isFunction(condition)) { - test = Object.isTruly(condition(key, el)); + if (isFunction(condition)) { + test = isTruly(condition(key, el)); - } else if (Object.isRegExp(condition)) { + } else if (isRegExp(condition)) { test = condition.test(String(key)); } else { @@ -188,14 +205,14 @@ export function selectReject(select: boolean): AnyFunction { } if (select ? test : !test) { - if (Object.isArray(res)) { + if (isArray(res)) { res.push(el); - } else if (Object.isSet(res) || Object.isWeakSet(res)) { + } else if (isSet(res) || isWeakSet(res)) { res.add(key); } else { - Object.set(res, [key], el); + set(res, [key], el); } } }); diff --git a/src/core/prelude/object/helpers.ts b/src/core/prelude/object/helpers.ts index a3f58215e..ed8fe3614 100644 --- a/src/core/prelude/object/helpers.ts +++ b/src/core/prelude/object/helpers.ts @@ -6,6 +6,21 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { + + isTruly, + isDictionary, + isSet, + isMap, + isArray, + isCustomObject, + isWeakMap, + isWeakSet, + cast, + isArrayLike + +} from 'core/prelude/types'; + import type { GetTypeType } from 'core/prelude/object/interface'; /** @@ -13,15 +28,15 @@ import type { GetTypeType } from 'core/prelude/object/interface'; * @param value */ export function isContainer(value: unknown): boolean { - if (!Object.isTruly(value) || typeof value !== 'object') { + if (!isTruly(value) || typeof value !== 'object') { return false; } - if (Object.isArray(value) || Object.isDictionary(value) || Object.isMap(value) || Object.isSet(value)) { + if (isArray(value) || isDictionary(value) || isMap(value) || isSet(value)) { return true; } - return Object.isCustomObject(value!.constructor); + return isCustomObject(value!.constructor); } /** @@ -29,15 +44,15 @@ export function isContainer(value: unknown): boolean { * @param value */ export function canExtendProto(value: unknown): boolean { - if (!Object.isTruly(value) || typeof value !== 'object') { + if (!isTruly(value) || typeof value !== 'object') { return false; } - if (Object.isArray(value) || Object.isDictionary(value)) { + if (isArray(value) || isDictionary(value)) { return true; } - return Object.isCustomObject(value!.constructor); + return isCustomObject(value!.constructor); } /** @@ -49,27 +64,27 @@ export function getType(value: unknown): GetTypeType { return ''; } - if (Object.isArray(value)) { + if (isArray(value)) { return 'array'; } - if (Object.isArrayLike(value)) { + if (isArrayLike(value)) { return 'arrayLike'; } - if (Object.isMap(value)) { + if (isMap(value)) { return 'map'; } - if (Object.isWeakMap(value)) { + if (isWeakMap(value)) { return 'weakMap'; } - if (Object.isSet(value)) { + if (isSet(value)) { return 'set'; } - if (Object.isWeakSet(value)) { + if (isWeakSet(value)) { return 'weakSet'; } @@ -85,22 +100,22 @@ export function getSameAs(value: T): Nullable { res: unknown = null; if (value != null && typeof value === 'object') { - if (Object.isArray(value)) { + if (isArray(value)) { res = []; - } else if (Object.isDictionary(value)) { + } else if (isDictionary(value)) { res = Object.getPrototypeOf(value) == null ? Object.create(null) : {}; - } else if (Object.isMap(value)) { + } else if (isMap(value)) { res = new Map(); - } else if (Object.isSet(value)) { + } else if (isSet(value)) { res = new Set(); - } else if (Object.isCustomObject(Object.cast(value).constructor)) { + } else if (isCustomObject(cast(value).constructor)) { res = {}; } } - return Object.cast(res); + return cast(res); } diff --git a/src/core/prelude/object/iterators/index.ts b/src/core/prelude/object/iterators/index.ts index c41c7273e..ed979df7b 100644 --- a/src/core/prelude/object/iterators/index.ts +++ b/src/core/prelude/object/iterators/index.ts @@ -8,8 +8,22 @@ import extend from 'core/prelude/extend'; +import { + + isFunction, + isPlainObject, + isString, + isIterable, + isMap, + isSet, + isArray, + isArrayLike, + isTruly + +} from 'core/prelude/types'; + /** @see [[ObjectConstructor.forEach]] */ -extend(Object, 'forEach', ( +export const forEach = extend< typeof Object.forEach>(Object, 'forEach', ( obj: unknown, optsOrCb: ObjectForEachOptions | AnyFunction, cbOrOpts?: AnyFunction | ObjectForEachOptions @@ -22,19 +36,19 @@ extend(Object, 'forEach', ( p: ObjectForEachOptions, cb: AnyFunction; - if (Object.isFunction(cbOrOpts)) { + if (isFunction(cbOrOpts)) { cb = cbOrOpts; - p = Object.isPlainObject(optsOrCb) ? optsOrCb : {}; + p = isPlainObject(optsOrCb) ? optsOrCb : {}; } else { - if (Object.isFunction(optsOrCb)) { + if (isFunction(optsOrCb)) { cb = optsOrCb; } else { throw new ReferenceError('A callback to iterate is not specified'); } - p = Object.isPlainObject(cbOrOpts) ? cbOrOpts : {}; + p = isPlainObject(cbOrOpts) ? cbOrOpts : {}; } const @@ -60,7 +74,7 @@ extend(Object, 'forEach', ( notOwn = p.notOwn; } - if (Object.isString(obj)) { + if (isString(obj)) { let i = 0; @@ -88,7 +102,7 @@ extend(Object, 'forEach', ( } if (!passDescriptor && notOwn == null) { - if (Object.isArrayLike(obj)) { + if (isArrayLike(obj)) { for (let i = 0; i < obj.length; i++) { cb(obj[i], i, obj); } @@ -96,7 +110,7 @@ extend(Object, 'forEach', ( return; } - if (Object.isMap(obj) || Object.isSet(obj)) { + if (isMap(obj) || isSet(obj)) { for (let o = obj.entries(), i = o.next(); !i.done; i = o.next()) { const [key, el] = i.value; cb(el, key, obj); @@ -105,12 +119,12 @@ extend(Object, 'forEach', ( return; } - if (Object.isIterable(obj)) { + if (isIterable(obj)) { let i = 0; for (const el of obj) { - if (Object.isArray(el) && el.length === 2) { + if (isArray(el) && el.length === 2) { cb(el[1], el[0], obj); } else { @@ -122,7 +136,7 @@ extend(Object, 'forEach', ( } } - if (Object.isTruly(notOwn)) { + if (isTruly(notOwn)) { if (notOwn === -1) { for (const key in obj) { if (Object.hasOwnProperty(obj, key)) { @@ -136,8 +150,8 @@ extend(Object, 'forEach', ( } if (p.withNonEnumerables) { - Object.forEach(obj, cb, {withNonEnumerables: true, passDescriptor}); - Object.forEach(Object.getPrototypeOf(obj), cb, {propsToIterate: 'all', passDescriptor}); + forEach(obj, cb, {withNonEnumerables: true, passDescriptor}); + forEach(Object.getPrototypeOf(obj), cb, {propsToIterate: 'all', passDescriptor}); return; } diff --git a/src/core/prelude/object/metrics/index.ts b/src/core/prelude/object/metrics/index.ts index 9e6ba11dd..6714f526b 100644 --- a/src/core/prelude/object/metrics/index.ts +++ b/src/core/prelude/object/metrics/index.ts @@ -8,17 +8,31 @@ import extend from 'core/prelude/extend'; +import { + + isTruly, + isArray, + isString, + isFunction, + isNumber, + isMap, + isSet, + isIterable, + isDictionary + +} from 'core/prelude/types'; + /** @see [[ObjectConstructor.size]] */ -extend(Object, 'size', (obj: unknown) => { - if (!Object.isTruly(obj)) { +export const size: typeof Object.size = extend(Object, 'size', (obj: unknown) => { + if (!isTruly(obj)) { return 0; } - if (Object.isArray(obj) || Object.isString(obj) || Object.isFunction(obj)) { + if (isArray(obj) || isString(obj) || isFunction(obj)) { return obj.length; } - if (Object.isNumber(obj)) { + if (isNumber(obj)) { return isNaN(obj) ? 0 : obj; } @@ -26,14 +40,14 @@ extend(Object, 'size', (obj: unknown) => { return 0; } - if (Object.isMap(obj) || Object.isSet(obj)) { + if (isMap(obj) || isSet(obj)) { return obj.size; } let length = 0; - if (Object.isIterable(obj)) { + if (isIterable(obj)) { for (const _ of obj) { length++; } @@ -41,7 +55,7 @@ extend(Object, 'size', (obj: unknown) => { return length; } - if (Object.isDictionary(obj)) { + if (isDictionary(obj)) { return Object.keys(obj).length; } diff --git a/src/core/prelude/object/mixin/index.ts b/src/core/prelude/object/mixin/index.ts index 6debf731b..80e12754b 100644 --- a/src/core/prelude/object/mixin/index.ts +++ b/src/core/prelude/object/mixin/index.ts @@ -9,24 +9,36 @@ import extend from 'core/prelude/extend'; import { isContainer, canExtendProto, getType, getSameAs } from 'core/prelude/object/helpers'; +import { + + isArray, + isTruly, + isFunction, + cast, + isBoolean + +} from 'core/prelude/types'; +import { get, set, hasOwnProperty } from 'core/prelude/object/property'; +import { forEach } from 'core/prelude/object/iterators'; + /** @see [[ObjectConstructor.mixin]] */ -extend(Object, 'mixin', function mixin( +export const mixin = extend(Object, 'mixin', function mixin( opts: ObjectMixinOptions | boolean, target: unknown, ...objects: unknown[] ): unknown | AnyFunction { if (arguments.length < 3) { if (arguments.length === 2) { - return (...args) => Object.mixin(opts, target, ...args); + return (...args) => mixin(opts, target, ...args); } - return (base, ...args) => Object.mixin(opts, base, ...args); + return (base, ...args) => mixin(opts, base, ...args); } const p: ObjectMixinOptions = {}; - if (Object.isBoolean(opts)) { + if (isBoolean(opts)) { p.deep = opts; } else { @@ -35,10 +47,10 @@ extend(Object, 'mixin', function mixin( const skipUndefs = 'withUndef' in p ? !p.withUndef : p.skipUndefs !== false, - concatArrays = Object.isTruly(p.concatArrays) || p.concatArray === true, + concatArrays = isTruly(p.concatArrays) || p.concatArray === true, // eslint-disable-next-line @typescript-eslint/unbound-method - concatFn = Object.isFunction(p.concatArrays) ? p.concatArrays : p.concatFn; + concatFn = isFunction(p.concatArrays) ? p.concatArrays : p.concatFn; const onlyAccessors = p.withDescriptors === 'onlyAccessors' || p.withAccessors === true, @@ -103,7 +115,7 @@ extend(Object, 'mixin', function mixin( } } else { - resolvedTarget = Object.cast(target); + resolvedTarget = cast(target); } const @@ -118,7 +130,7 @@ extend(Object, 'mixin', function mixin( !concatArrays && !onlyAccessors && !withDescriptors && - !Object.isTruly(onlyNew) && + !isTruly(onlyNew) && !p.withProto && !p.withNonEnumerables && @@ -136,7 +148,7 @@ extend(Object, 'mixin', function mixin( case 'weakMap': case 'map': setter = (data, key, val) => { - if (Object.isTruly(onlyNew) && data.has(key) !== (onlyNew === -1)) { + if (isTruly(onlyNew) && data.has(key) !== (onlyNew === -1)) { return; } @@ -148,7 +160,7 @@ extend(Object, 'mixin', function mixin( case 'weakSet': case 'set': setter = (data, key, val) => { - if (Object.isTruly(onlyNew) && data.has(val) !== (onlyNew === -1)) { + if (isTruly(onlyNew) && data.has(val) !== (onlyNew === -1)) { return; } @@ -159,7 +171,7 @@ extend(Object, 'mixin', function mixin( default: setter = (data, key, val) => { - if (Object.isTruly(onlyNew) && key in data !== (onlyNew === -1)) { + if (isTruly(onlyNew) && key in data !== (onlyNew === -1)) { return; } @@ -171,7 +183,7 @@ extend(Object, 'mixin', function mixin( for (let i = 0; i < objects.length; i++) { const - extender = Object.cast>(objects[i]); + extender = cast>(objects[i]); if (extender == null) { continue; @@ -191,17 +203,17 @@ extend(Object, 'mixin', function mixin( } else { forEachParams.passDescriptor = withDescriptors || onlyAccessors; forEachParams.withNonEnumerables = p.withNonEnumerables; - forEachParams.propsToIterate = Object.isTruly(p.deep) ? 'all' : 'own'; + forEachParams.propsToIterate = isTruly(p.deep) ? 'all' : 'own'; } } - Object.forEach(extender, forEachParams, (el, key: PropertyKey) => { - if (p.filter && !Object.isTruly(p.filter(el, key, extender))) { + forEach(extender, forEachParams, (el, key: PropertyKey) => { + if (p.filter && !isTruly(p.filter(el, key, extender))) { return; } const propDesc = withDescriptors || onlyAccessors ? - Object.cast(el) : + cast(el) : null; const needExtendDescriptor = targetIsSimpleObj && extenderIsSimpleObj && ( @@ -210,7 +222,7 @@ extend(Object, 'mixin', function mixin( ); if (needExtendDescriptor && propDesc != null) { - if (Object.isTruly(onlyNew) && key in resolvedTarget !== (onlyNew === -1)) { + if (isTruly(onlyNew) && key in resolvedTarget !== (onlyNew === -1)) { return; } @@ -236,7 +248,7 @@ extend(Object, 'mixin', function mixin( } let - oldVal = Object.get(resolvedTarget, [key]); + oldVal = get(resolvedTarget, [key]); const newVal = extenderIsSimpleObj ? extender[key] : el; @@ -246,10 +258,10 @@ extend(Object, 'mixin', function mixin( } let - canDeepExtend = Object.isTruly(newVal); + canDeepExtend = isTruly(newVal); if (canDeepExtend && p.extendFilter != null) { - canDeepExtend = Object.isTruly(p.extendFilter(newVal, key, resolvedTarget)); + canDeepExtend = isTruly(p.extendFilter(newVal, key, resolvedTarget)); } let @@ -257,7 +269,7 @@ extend(Object, 'mixin', function mixin( struct; if (canDeepExtend) { - newValIsArray = Object.isArray(newVal); + newValIsArray = isArray(newVal); struct = newValIsArray ? [] : getSameAs(newVal); canDeepExtend = struct != null; } @@ -269,17 +281,17 @@ extend(Object, 'mixin', function mixin( canExtendProto(oldVal); let - oldValIsArray = Object.isArray(oldVal); + oldValIsArray = isArray(oldVal); - if (canExtendOldValProto && !Object.hasOwnProperty(resolvedTarget, key)) { + if (canExtendOldValProto && !hasOwnProperty(resolvedTarget, key)) { if (oldValIsArray) { - oldVal = Array.from(Object.cast(oldVal)); + oldVal = Array.from(cast(oldVal)); } else { - oldVal = Object.create(Object.cast(oldVal)); + oldVal = Object.create(cast(oldVal)); } - Object.set(resolvedTarget, [key], oldVal); + set(resolvedTarget, [key], oldVal); } let @@ -292,7 +304,7 @@ extend(Object, 'mixin', function mixin( if (!oldValIsArray && canExtendOldValProto && concatArrays) { construct = Object.getPrototypeOf(oldVal); - oldValIsArray = construct != null && Object.isArray(construct); + oldValIsArray = construct != null && isArray(construct); isProto = oldValIsArray; } @@ -301,7 +313,7 @@ extend(Object, 'mixin', function mixin( const old = isProto ? construct : oldVal; - const mergedArr = Object.isFunction(concatFn) ? + const mergedArr = isFunction(concatFn) ? concatFn(old, newVal, key) : old.concat(newVal); @@ -329,7 +341,7 @@ extend(Object, 'mixin', function mixin( } const - mergedVal = Object.mixin(p, clone, newVal); + mergedVal = mixin(p, clone, newVal); if (needExtendDescriptor && propDesc != null) { Object.defineProperty(resolvedTarget, key, { @@ -338,7 +350,7 @@ extend(Object, 'mixin', function mixin( }); } else { - Object.set(resolvedTarget, [key], mergedVal); + set(resolvedTarget, [key], mergedVal); } } else { diff --git a/src/core/prelude/object/property/index.ts b/src/core/prelude/object/property/index.ts index c67a1325e..94cb94834 100644 --- a/src/core/prelude/object/property/index.ts +++ b/src/core/prelude/object/property/index.ts @@ -8,8 +8,24 @@ import extend from 'core/prelude/extend'; +import { + + isPlainObject, + isString, + isPromiseLike, + isArray, + isDictionary, + isMap, + isWeakMap, + isSet, + isWeakSet, + cast, + isSymbol + +} from 'core/prelude/types'; + /** @see [[ObjectConstructor.get]] */ -extend(Object, 'get', ( +export const get = extend(Object, 'get', ( obj: unknown, path: ObjectPropertyPath | ObjectGetOptions, opts?: ObjectGetOptions @@ -19,15 +35,15 @@ extend(Object, 'get', ( curriedPath = obj, curriedOpts = path; - return (obj) => Object.get(obj, Object.cast(curriedPath), Object.cast(curriedOpts)); + return (obj) => get(obj, cast(curriedPath), cast(curriedOpts)); } const - p = {separator: '.', ...Object.isPlainObject(path) ? path : opts}; + p = {separator: '.', ...isPlainObject(path) ? path : opts}; - const get = (path) => { + const getFunc = (path) => { const - chunks = Object.isString(path) ? path.split(p.separator) : path; + chunks = isString(path) ? path.split(p.separator) : path; let res = obj; @@ -40,39 +56,39 @@ extend(Object, 'get', ( const key = chunks[i]; - if (Object.isPromiseLike(res) && !(key in res)) { + if (isPromiseLike(res) && !(key in res)) { res = res.then((val) => { if (val == null) { return; } - if (Object.isMap(val) || Object.isWeakMap(val)) { + if (isMap(val) || isWeakMap(val)) { return val.get(key); } - return (Object.cast(val))[key]; + return (cast(val))[key]; }); - } else if (Object.isMap(res) || Object.isWeakMap(res)) { + } else if (isMap(res) || isWeakMap(res)) { res = res.get(key); } else { - res = Object.cast(res)[key]; + res = cast(res)[key]; } } return res; }; - if (Object.isArray(path) || Object.isString(path)) { - return get(path); + if (isArray(path) || isString(path)) { + return getFunc(path); } - return get; + return getFunc; }); /** @see [[ObjectConstructor.has]] */ -extend(Object, 'has', ( +export const has = extend(Object, 'has', ( obj: unknown, path: ObjectPropertyPath | ObjectGetOptions, opts?: ObjectGetOptions @@ -82,15 +98,15 @@ extend(Object, 'has', ( curriedPath = obj, curriedOpts = path; - return (obj) => Object.has(obj, Object.cast(curriedPath), Object.cast(curriedOpts)); + return (obj) => has(obj, cast(curriedPath), cast(curriedOpts)); } const - p = {separator: '.', ...Object.isPlainObject(path) ? path : opts}; + p = {separator: '.', ...isPlainObject(path) ? path : opts}; - const has = (path) => { + const hasFunc = (path) => { const - chunks = Object.isString(path) ? path.split(p.separator) : path; + chunks = isString(path) ? path.split(p.separator) : path; let res = obj, @@ -104,11 +120,11 @@ extend(Object, 'has', ( const key = chunks[i]; - if (Object.isMap(res) || Object.isWeakMap(res)) { + if (isMap(res) || isWeakMap(res)) { res = res.get(key); } else { - res = Object.cast(res)[key]; + res = cast(res)[key]; } } @@ -119,7 +135,7 @@ extend(Object, 'has', ( return false; } - if (Object.isMap(res) || Object.isSet(res) || Object.isWeakMap(res) || Object.isWeakSet(res)) { + if (isMap(res) || isSet(res) || isWeakMap(res) || isWeakSet(res)) { return res.has(key); } @@ -127,11 +143,11 @@ extend(Object, 'has', ( return key in res; } - return Object.cast(res)[key] !== undefined; + return cast(res)[key] !== undefined; }; - if (Object.isArray(path) || Object.isString(path)) { - return has(path); + if (isArray(path) || isString(path)) { + return hasFunc(path); } return has; @@ -142,7 +158,7 @@ const {hasOwnProperty: nativeHasOwnProperty} = Object.prototype; /** @see [[ObjectConstructor.hasOwnProperty]] */ -extend(Object, 'hasOwnProperty', function hasOwnProperty( +export const hasOwnProperty = extend(Object, 'hasOwnProperty', function hasOwnProperty( this: unknown, obj: unknown, key?: string | symbol @@ -159,21 +175,21 @@ extend(Object, 'hasOwnProperty', function hasOwnProperty( return nativeHasOwnProperty.call(obj, key); } - if (Object.isString(obj) || Object.isSymbol(obj)) { + if (isString(obj) || isSymbol(obj)) { key = obj; - return (obj) => Object.hasOwnProperty(obj, key!); + return (obj) => hasOwnProperty(obj, key); } - return (key) => Object.hasOwnProperty(obj, key); + return (key) => hasOwnProperty(obj, key); }); /** @see [[ObjectConstructor.defineSymbol]] */ -extend(Object, 'defineSymbol', function defineSymbol(obj: T, symbol: symbol, value: unknown): T { +export const defineSymbol = extend(Object, 'defineSymbol', function defineSymbol(obj: T, symbol: symbol, value: unknown): T { return Object.defineProperty(obj, symbol, {value, configurable: true, enumerable: false, writable: true}); }); /** @see [[ObjectConstructor.set]] */ -extend(Object, 'set', function set( +export const set = extend(Object, 'set', function set( obj: unknown, path: ObjectPropertyPath | ObjectGetOptions, value: unknown, @@ -186,7 +202,7 @@ extend(Object, 'set', function set( return function wrapper(obj: unknown, newValue: unknown): unknown { const val = arguments.length > 1 ? newValue : value; - Object.set(obj, Object.cast(curriedPath), val, Object.cast(curriedOpts)); + set(obj, cast(curriedPath), val, cast(curriedOpts)); return obj; }; } @@ -194,29 +210,29 @@ extend(Object, 'set', function set( const p: ObjectSetOptions = { separator: '.', concat: false, - ...Object.isPlainObject(path) ? path : opts + ...isPlainObject(path) ? path : opts }; - if (Object.isArray(path) || Object.isString(path)) { + if (isArray(path) || isString(path)) { if (arguments.length < 2) { return (value) => { - set(path, value); + setFunc(path, value); return obj; }; } - return set(path, value); + return setFunc(path, value); } return (path, ...args) => { - set(path, ...args); + setFunc(path, ...args); return obj; }; - function set(path: ObjectPropertyPath, newValue?: unknown): unknown { + function setFunc(path: ObjectPropertyPath, newValue?: unknown): unknown { const finalValue = arguments.length > 1 ? newValue : value, - chunks = Object.isString(path) ? path.split(p.separator!) : path; + chunks = isString(path) ? path.split(p.separator!) : path; let ref = obj, @@ -235,14 +251,14 @@ extend(Object, 'set', function set( nextChunkIsObj = isNaN(Number(chunks[i + 1])); let - isWeakMap; + isRefWeakMap; - if (Object.isMap(ref) || (isWeakMap = Object.isWeakMap(ref))) { + if (isMap(ref) || (isRefWeakMap = isWeakMap(ref))) { let val = ref.get(key); if (val == null || typeof val !== 'object') { - if (isWeakMap === true && (key == null || typeof key !== 'object')) { + if (isRefWeakMap === true && (key == null || typeof key !== 'object')) { return undefined; } @@ -260,7 +276,7 @@ extend(Object, 'set', function set( } else { const - box = Object.cast(ref); + box = cast(ref); let val = box[key]; @@ -281,10 +297,10 @@ extend(Object, 'set', function set( } let - isWeakMap; + isRefWeakMap; - if (Object.isMap(ref) || (isWeakMap = Object.isWeakMap(ref))) { - if (isWeakMap === true && (cursor == null || typeof cursor !== 'object')) { + if (isMap(ref) || (isRefWeakMap = isWeakMap(ref))) { + if (isRefWeakMap === true && (cursor == null || typeof cursor !== 'object')) { return undefined; } @@ -302,7 +318,7 @@ extend(Object, 'set', function set( } const - box = Object.cast(ref), + box = cast(ref), val = cursor in box && p.concat ? Array.concat([], box[cursor], finalValue) : finalValue; if (p.setter != null) { @@ -316,7 +332,7 @@ extend(Object, 'set', function set( }); /** @see [[ObjectConstructor.delete]] */ -extend(Object, 'delete', ( +export const deleteObj = extend(Object, 'delete', ( obj: unknown, path: ObjectPropertyPath | ObjectGetOptions, opts?: ObjectGetOptions @@ -326,15 +342,15 @@ extend(Object, 'delete', ( curriedPath = obj, curriedOpts = path; - return (obj) => Object.delete(obj, Object.cast(curriedPath), Object.cast(curriedOpts)); + return (obj) => deleteObj(obj, cast(curriedPath), cast(curriedOpts)); } const - p = {separator: '.', ...Object.isPlainObject(path) ? path : opts}; + p = {separator: '.', ...isPlainObject(path) ? path : opts}; const del = (path) => { const - chunks = Object.isString(path) ? path.split(p.separator) : path; + chunks = isString(path) ? path.split(p.separator) : path; let res = obj, @@ -348,11 +364,11 @@ extend(Object, 'delete', ( const key = chunks[i]; - if (Object.isMap(res) || Object.isWeakMap(res)) { + if (isMap(res) || isWeakMap(res)) { res = res.get(key); } else { - res = Object.cast(res)[key]; + res = cast(res)[key]; } } @@ -363,12 +379,12 @@ extend(Object, 'delete', ( return false; } - if (Object.isMap(res) || Object.isSet(res) || Object.isWeakMap(res) || Object.isWeakSet(res)) { + if (isMap(res) || isSet(res) || isWeakMap(res) || isWeakSet(res)) { return res.delete(key); } const - box = Object.cast(res); + box = cast(res); if (typeof res === 'object' ? key in box : box[key] !== undefined) { return delete box[key]; @@ -377,7 +393,7 @@ extend(Object, 'delete', ( return false; }; - if (Object.isArray(path) || Object.isString(path)) { + if (isArray(path) || isString(path)) { return del(path); } @@ -385,5 +401,5 @@ extend(Object, 'delete', ( }); function needCurriedOverload(obj: unknown, path: unknown): boolean { - return (Object.isString(obj) || Object.isArray(obj)) && (path == null || Object.isDictionary(path)); + return (isString(obj) || isArray(obj)) && (path == null || isDictionary(path)); } diff --git a/src/core/prelude/regexp/const.ts b/src/core/prelude/regexp/const.ts index f87f90126..8a10fbd0f 100644 --- a/src/core/prelude/regexp/const.ts +++ b/src/core/prelude/regexp/const.ts @@ -6,9 +6,11 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { createDict } from 'core/prelude/object/create'; + export const isGlobal = /g/, escapeRgxp = /([\\/'*+?|()[\]{}.^$-])/g; export const - testCache = Object.createDict(); + testCache = createDict(); diff --git a/src/core/prelude/regexp/helpers.ts b/src/core/prelude/regexp/helpers.ts index 26295ce67..7dce3a0dd 100644 --- a/src/core/prelude/regexp/helpers.ts +++ b/src/core/prelude/regexp/helpers.ts @@ -6,9 +6,11 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ -export function createFlagsModifier(method: string): Function { +import { isString } from 'core/prelude/types'; + +export function createFlagsModifier(method: string): AnyFunction { return function flagsModifier(rgxp: RegExp | RegExpFlag, ...flags: RegExpFlag[]): Function | RegExp { - if (Object.isString(rgxp)) { + if (isString(rgxp)) { const flag = rgxp; return (rgxp) => rgxp[method](flag); } diff --git a/src/core/prelude/regexp/index.ts b/src/core/prelude/regexp/index.ts index 361d596cd..12d98daea 100644 --- a/src/core/prelude/regexp/index.ts +++ b/src/core/prelude/regexp/index.ts @@ -11,12 +11,26 @@ import extend from 'core/prelude/extend'; import { isGlobal, escapeRgxp, testCache } from 'core/prelude/regexp/const'; import { createFlagsModifier } from 'core/prelude/regexp/helpers'; +import { isString } from 'core/prelude/types'; + /** @see [[RegExpConstructor.escape]] */ -extend(RegExp, 'escape', (value: unknown) => String(value).replace(escapeRgxp, '\\$1')); +export const escape = extend(RegExp, 'escape', (value: unknown) => String(value).replace(escapeRgxp, '\\$1')); + +/** @see [[RegExp.addFlags]] */ +export const addFlags = extend(RegExp.prototype, 'addFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { + const set = new Set([...flags, ...this.flags].flatMap((str) => str.split(''))); + return new RegExp(this.source, [...set].join('')); +}); + +/** @see [[RegExp.removeFlags]] */ +export const removeFlags = extend(RegExp.prototype, 'removeFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { + const set = new Set(flags.flatMap((str) => str.split(''))); + return new RegExp(this.source, this.flags.split('').filter((flag) => !set.has(flag)).join('')); +}); /** @see [[RegExpConstructor.test]] */ -extend(RegExp, 'test', (rgxp: RegExp | string, str?: string) => { - if (Object.isString(rgxp)) { +export const test = extend(RegExp, 'test', (rgxp: RegExp | string, str?: string) => { + if (isString(rgxp)) { str = rgxp; return (rgxp) => RegExp.test(rgxp, str); } @@ -26,7 +40,7 @@ extend(RegExp, 'test', (rgxp: RegExp | string, str?: string) => { } if (isGlobal.test(rgxp.flags)) { - const testRgxp = testCache[rgxp.source] ?? rgxp.removeFlags('g'); + const testRgxp = testCache[rgxp.source] ?? removeFlags(rgxp, 'g'); testCache[rgxp.source] = testRgxp; return testRgxp.test(str); } @@ -34,29 +48,19 @@ extend(RegExp, 'test', (rgxp: RegExp | string, str?: string) => { return rgxp.test(str); }); -/** @see [[RegExp.addFlags]] */ -extend(RegExp.prototype, 'addFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { - const set = new Set([...flags, ...this.flags].flatMap((str) => str.split(''))); +/** @see [[RegExp.setFlags]] */ +export const setFlags = extend(RegExp.prototype, 'setFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { + const set = new Set(flags.flatMap((str) => str.split(''))); return new RegExp(this.source, [...set].join('')); }); +//#if prelude/standalone /** @see [[RegExpConstructor.addFlags]] */ extend(RegExp, 'addFlags', createFlagsModifier('addFlags')); -/** @see [[RegExp.removeFlags]] */ -extend(RegExp.prototype, 'removeFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { - const set = new Set(flags.flatMap((str) => str.split(''))); - return new RegExp(this.source, this.flags.split('').filter((flag) => !set.has(flag)).join('')); -}); - /** @see [[RegExpConstructor.removeFlags]] */ extend(RegExp, 'removeFlags', createFlagsModifier('removeFlags')); -/** @see [[RegExp.setFlags]] */ -extend(RegExp.prototype, 'setFlags', function addFlags(this: RegExp, ...flags: RegExpFlag[]) { - const set = new Set(flags.flatMap((str) => str.split(''))); - return new RegExp(this.source, [...set].join('')); -}); - /** @see [[RegExpConstructor.setFlags]] */ extend(RegExp, 'setFlags', createFlagsModifier('setFlags')); +//#endif diff --git a/src/core/prelude/string/const.ts b/src/core/prelude/string/const.ts index 999250e84..c75b7c39f 100644 --- a/src/core/prelude/string/const.ts +++ b/src/core/prelude/string/const.ts @@ -8,11 +8,13 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { createDict } from 'core/prelude/object/create'; + export const - capitalizeCache = Object.createDict(), - camelizeCache = Object.createDict(), - dasherizeCache = Object.createDict(), - underscoreCache = Object.createDict(); + capitalizeCache = createDict(), + camelizeCache = createDict(), + dasherizeCache = createDict(), + underscoreCache = createDict(); export const isDigital = /\d/, diff --git a/src/core/prelude/string/helpers.ts b/src/core/prelude/string/helpers.ts index ac0bfa2d9..cd24dbedd 100644 --- a/src/core/prelude/string/helpers.ts +++ b/src/core/prelude/string/helpers.ts @@ -6,6 +6,15 @@ * https://github.com/V4Fire/Core/blob/master/LICENSE */ +import { letters } from 'core/prelude/string/index'; +import { + + isTruly, + isBoolean, + isDictionary + +} from 'core/prelude/types'; + /** * Returns true, if the specified character is declared in upper case * @param char @@ -87,7 +96,7 @@ export function toDasherize( */ export function convertToSeparatedStr(str: string, separator: string, stable?: boolean): string { const - symbols = [...str.letters()]; + symbols = [...letters.call(str)]; let res = ''; @@ -112,7 +121,7 @@ export function convertToSeparatedStr(str: string, separator: string, stable?: b if (isCharUpper(el)) { const needSeparator = i > 0 && ( stable || - Object.isTruly(nextChar) && nextChar !== separator && !isCharUpper(nextChar) + isTruly(nextChar) && nextChar !== separator && !isCharUpper(nextChar) ); if (needSeparator) { @@ -124,7 +133,7 @@ export function convertToSeparatedStr(str: string, separator: string, stable?: b } else { res += el; - if (Object.isTruly(nextChar) && isCharUpper(nextChar)) { + if (isTruly(nextChar) && isCharUpper(nextChar)) { res += separator; } } @@ -139,7 +148,7 @@ export function convertToSeparatedStr(str: string, separator: string, stable?: b */ export function createStaticTransformFunction(method: string): AnyFunction { return (value: string | boolean | Dictionary, opts: boolean | Dictionary) => { - if (Object.isBoolean(value) || Object.isDictionary(value)) { + if (isBoolean(value) || isDictionary(value)) { opts = value; return (value) => String[method](value, opts); } diff --git a/src/core/prelude/string/iterators.ts b/src/core/prelude/string/iterators.ts index 1c3d57a45..92c84a014 100644 --- a/src/core/prelude/string/iterators.ts +++ b/src/core/prelude/string/iterators.ts @@ -10,7 +10,7 @@ import extend from 'core/prelude/extend'; import { unicode } from 'core/prelude/string/const'; /** @see [[String.letters]] */ -extend(String.prototype, 'letters', function* letters(this: string): IterableIterator { +export const letters = extend(String.prototype, 'letters', function* letters(this: string): IterableIterator { let baseStr: Nullable = null, prevChar: Nullable = null; @@ -67,5 +67,7 @@ extend(String.prototype, 'letters', function* letters(this: string): IterableIte } }); +//#if prelude/standalone /** @see [[StringConstructor.letters]] */ extend(String, 'letters', (str: string) => str.letters()); +//#endif diff --git a/src/core/prelude/string/transformers.ts b/src/core/prelude/string/transformers.ts index 216a0f330..756a363da 100644 --- a/src/core/prelude/string/transformers.ts +++ b/src/core/prelude/string/transformers.ts @@ -14,7 +14,6 @@ import { camelizeCache, dasherizeCache, underscoreCache, - camelizeRgxp, normalizeRgxp @@ -30,8 +29,10 @@ import { } from 'core/prelude/string/helpers'; +import { isBoolean } from 'core/prelude/types'; + /** @see [[String.capitalize]] */ -extend(String.prototype, 'capitalize', function capitalize( +export const capitalize = extend(String.prototype, 'capitalize', function capitalize( this: string, {lower, all, cache}: StringCapitalizeOptions = {} ): string { @@ -52,7 +53,7 @@ extend(String.prototype, 'capitalize', function capitalize( chunks = str.split(' '); for (let i = 0; i < chunks.length; i++) { - chunks[i] = chunks[i].capitalize({lower}); + chunks[i] = capitalize.call(chunks[i], {lower}); } res = chunks.join(' '); @@ -69,18 +70,15 @@ extend(String.prototype, 'capitalize', function capitalize( return res; }); -/** @see [[StringConstructor.capitalize]] */ -extend(String, 'capitalize', createStaticTransformFunction('capitalize')); - /** @see [[String.camelize]] */ -extend(String.prototype, 'camelize', function camelize( +export const camelize = extend(String.prototype, 'camelize', function camelize( this: string, upperOrOpts: boolean | StringCamelizeOptions ): string { const opts: StringCamelizeOptions = {}; - if (Object.isBoolean(upperOrOpts)) { + if (isBoolean(upperOrOpts)) { opts.upper = upperOrOpts; } else { @@ -112,18 +110,15 @@ extend(String.prototype, 'camelize', function camelize( return res; }); -/** @see [[StringConstructor.camelize]] */ -extend(String, 'camelize', createStaticTransformFunction('camelize')); - /** @see [[String.dasherize]] */ -extend(String.prototype, 'dasherize', function dasherize( +export const dasherize = extend(String.prototype, 'dasherize', function dasherize( this: string, stableOrOpts?: boolean | StringDasherizeOptions ): string { const opts: StringDasherizeOptions = {}; - if (Object.isBoolean(stableOrOpts)) { + if (isBoolean(stableOrOpts)) { opts.stable = stableOrOpts; } else { @@ -154,18 +149,15 @@ extend(String.prototype, 'dasherize', function dasherize( return res; }); -/** @see [[StringConstructor.dasherize]] */ -extend(String, 'dasherize', createStaticTransformFunction('dasherize')); - /** @see [[String.underscore]] */ -extend(String.prototype, 'underscore', function underscore( +export const underscore = extend(String.prototype, 'underscore', function underscore( this: string, stableOrOpts?: boolean | StringUnderscoreOptions ): string { const opts: StringUnderscoreOptions = {}; - if (Object.isBoolean(stableOrOpts)) { + if (isBoolean(stableOrOpts)) { opts.stable = stableOrOpts; } else { @@ -196,5 +188,16 @@ extend(String.prototype, 'underscore', function underscore( return res; }); +//#if prelude/standalone /** @see [[StringConstructor.underscore]] */ extend(String, 'underscore', createStaticTransformFunction('underscore')); + +/** @see [[StringConstructor.capitalize]] */ +extend(String, 'capitalize', createStaticTransformFunction('capitalize')); + +/** @see [[StringConstructor.dasherize]] */ +extend(String, 'dasherize', createStaticTransformFunction('dasherize')); + +/** @see [[StringConstructor.camelize]] */ +extend(String, 'camelize', createStaticTransformFunction('camelize')); +//#endif diff --git a/src/core/prelude/structures/sync-promise/index.ts b/src/core/prelude/structures/sync-promise/index.ts index 5c5178d74..b89722681 100644 --- a/src/core/prelude/structures/sync-promise/index.ts +++ b/src/core/prelude/structures/sync-promise/index.ts @@ -20,6 +20,8 @@ import { } from 'core/prelude/structures/sync-promise/interface'; +import { isTruly, isPromiseLike } from 'core/prelude/types'; + export * from 'core/prelude/structures/sync-promise/interface'; /** @@ -46,7 +48,7 @@ export default class SyncPromise implements Promise { static resolve(): SyncPromise; static resolve(value?: Value): SyncPromise { const - Constr = Object.isTruly(this) ? this : SyncPromise; + Constr = isTruly(this) ? this : SyncPromise; if (value instanceof Constr) { return value; @@ -60,7 +62,7 @@ export default class SyncPromise implements Promise { * @param [reason] */ static reject(reason?: unknown): SyncPromise { - const Constr = Object.isTruly(this) ? this : SyncPromise; + const Constr = isTruly(this) ? this : SyncPromise; return new Constr((_, reject) => reject(reason)); } @@ -322,7 +324,7 @@ export default class SyncPromise implements Promise { this.value = val; - if (Object.isPromiseLike(val)) { + if (isPromiseLike(val)) { // eslint-disable-next-line @typescript-eslint/no-use-before-define val.then(forceResolve, reject); return; @@ -452,7 +454,7 @@ export default class SyncPromise implements Promise { let res = cb?.(); - if (Object.isPromiseLike(res)) { + if (isPromiseLike(res)) { res = res.then(() => this.value); } else { @@ -471,7 +473,7 @@ export default class SyncPromise implements Promise { let res = cb?.(); - if (Object.isPromiseLike(res)) { + if (isPromiseLike(res)) { res = res.then(() => this.value); resolve(res); @@ -515,7 +517,7 @@ export default class SyncPromise implements Promise { const res = fn?.(...args); - if (Object.isPromiseLike(res)) { + if (isPromiseLike(res)) { (>res).then(resolve, reject); } else { diff --git a/src/core/prelude/types/index.ts b/src/core/prelude/types/index.ts index b7cc4884d..b567900e2 100644 --- a/src/core/prelude/types/index.ts +++ b/src/core/prelude/types/index.ts @@ -12,56 +12,56 @@ import extend from 'core/prelude/extend'; import { isNative, toString, nonPrimitiveTypes, READONLY, PROXY } from 'core/prelude/types/const'; /** @see [[ObjectConstructor.cast]] */ -extend(Object, 'cast', (value) => value); - -/** @see [[ObjectConstructor.throw]] */ -extend(Object, 'throw', (err = 'This is a loopback function or method') => { - if (Object.isString(err)) { - throw new Error(err); - } - - throw err; -}); +export const cast = extend(Object, 'cast', (value) => value); /** @see [[ObjectConstructor.isTruly]] */ -extend(Object, 'isTruly', (value) => Boolean(value)); +export const isTruly = extend(Object, 'isTruly', (value) => Boolean(value)); /** @see [[ObjectConstructor.isPrimitive]] */ -extend(Object, 'isPrimitive', (value) => !value || !nonPrimitiveTypes[typeof value]); +export const isPrimitive = extend(Object, 'isPrimitive', (value) => !value || !nonPrimitiveTypes[typeof value]); /** @see [[ObjectConstructor.isUndef]] */ -extend(Object, 'isUndef', (value) => value === undefined); +export const isUndef = extend(Object, 'isUndef', (value) => value === undefined); /** @see [[ObjectConstructor.isNull]] */ // eslint-disable-next-line eqeqeq -extend(Object, 'isNull', (value) => value === null); +export const isNull = extend(Object, 'isNull', (value) => value === null); /** @see [[ObjectConstructor.isNullable]] */ -extend(Object, 'isNullable', (value) => value == null); +export const isNullable = extend(Object, 'isNullable', (value) => value == null); /** @see [[ObjectConstructor.isString]] */ -extend(Object, 'isString', (value) => typeof value === 'string'); +export const isString = extend(Object, 'isString', (value): value is typeof Object.isString => typeof value === 'string'); + +/** @see [[ObjectConstructor.throw]] */ +export const objThrow = extend(Object, 'throw', (err = 'This is a loopback function or method') => { + if (isString(err)) { + throw new Error(err); + } + + throw err; +}); /** @see [[ObjectConstructor.isNumber]] */ -extend(Object, 'isNumber', (value) => typeof value === 'number'); +export const isNumber = extend(Object, 'isNumber', (value) => typeof value === 'number'); /** @see [[ObjectConstructor.isBoolean]] */ -extend(Object, 'isBoolean', (value) => typeof value === 'boolean'); +export const isBoolean = extend(Object, 'isBoolean', (value) => typeof value === 'boolean'); /** @see [[ObjectConstructor.isSymbol]] */ -extend(Object, 'isSymbol', (value) => typeof value === 'symbol'); +export const isSymbol = extend(Object, 'isSymbol', (value) => typeof value === 'symbol'); /** @see [[ObjectConstructor.isRegExp]] */ -extend(Object, 'isRegExp', (value) => value instanceof RegExp); +export const isRegExp = extend(Object, 'isRegExp', (value) => value instanceof RegExp); /** @see [[ObjectConstructor.isDate]] */ -extend(Object, 'isDate', (value) => value instanceof Date); +export const isDate = extend(Object, 'isDate', (value) => value instanceof Date); /** @see [[ObjectConstructor.isArray]] */ -extend(Object, 'isArray', Array.isArray); +export const isArray = extend(Object, 'isArray', Array.isArray); /** @see [[ObjectConstructor.isArrayLike]] */ -extend(Object, 'isArrayLike', (value) => { +export const isArrayLike = extend(Object, 'isArrayLike', (value) => { const t = typeof value; @@ -73,25 +73,34 @@ extend(Object, 'isArrayLike', (value) => { }); /** @see [[ObjectConstructor.isMap]] */ -extend(Object, 'isMap', (value) => value instanceof Map); +export const isMap = extend(Object, 'isMap', (value) => value instanceof Map); /** @see [[ObjectConstructor.isWeakMap]] */ -extend(Object, 'isWeakMap', (value) => value instanceof WeakMap); +export const isWeakMap = extend(Object, 'isWeakMap', (value) => value instanceof WeakMap); /** @see [[ObjectConstructor.isSet]] */ -extend(Object, 'isSet', (value) => value instanceof Set); +export const isSet = extend(Object, 'isSet', (value) => value instanceof Set); /** @see [[ObjectConstructor.isWeakSet]] */ -extend(Object, 'isWeakSet', (value) => value instanceof WeakSet); +export const isWeakSet = extend(Object, 'isWeakSet', (value) => value instanceof WeakSet); /** @see [[ObjectConstructor.isDictionary]] */ -extend(Object, 'isDictionary', isPlainObject); +export const isDictionary = extend(Object, 'isDictionary', isPlainObjectFunc); /** @see [[ObjectConstructor.isPlainObject]] */ -extend(Object, 'isPlainObject', isPlainObject); +export const isPlainObject = extend(Object, 'isPlainObject', isPlainObjectFunc); + +/** @see [[ObjectConstructor.unwrapProxy]] */ +export const unwrapProxy = extend(Object, 'unwrapProxy', (value) => { + while (value?.[PROXY] && value[PROXY] !== value) { + value = value[PROXY]; + } + + return value; +}); -function isPlainObject(value: unknown): boolean { - value = Object.unwrapProxy(value); +function isPlainObjectFunc(value: unknown): boolean { + value = unwrapProxy(value); if (value == null || typeof value !== 'object') { return false; @@ -103,8 +112,8 @@ function isPlainObject(value: unknown): boolean { } /** @see [[ObjectConstructor.isCustomObject]] */ -extend(Object, 'isCustomObject', (value) => { - value = Object.unwrapProxy(value); +export const isCustomObject = extend(Object, 'isCustomObject', (value) => { + value = unwrapProxy(value); let type; @@ -122,7 +131,7 @@ extend(Object, 'isCustomObject', (value) => { }); /** @see [[ObjectConstructor.isSimpleObject]] */ -extend(Object, 'isSimpleObject', (value) => { +export const isSimpleObject = extend(Object, 'isSimpleObject', (value) => { if (!value || typeof value !== 'object') { return false; } @@ -131,19 +140,19 @@ extend(Object, 'isSimpleObject', (value) => { }); /** @see [[ObjectConstructor.isFunction]] */ -extend(Object, 'isFunction', (value) => typeof value === 'function'); +export const isFunction = extend(Object, 'isFunction', (value) => typeof value === 'function'); /** @see [[ObjectConstructor.isSimpleFunction]] */ -extend(Object, 'isSimpleFunction', (value) => typeof value === 'function'); +export const isSimpleFunction = extend(Object, 'isSimpleFunction', (value) => typeof value === 'function'); /** @see [[ObjectConstructor.isGenerator]] */ -extend(Object, 'isGenerator', (value) => typeof value === 'function' && value.constructor.name === 'GeneratorFunction'); +export const isGenerator = extend(Object, 'isGenerator', (value) => typeof value === 'function' && value.constructor.name === 'GeneratorFunction'); /** @see [[ObjectConstructor.isAsyncGenerator]] */ -extend(Object, 'isAsyncGenerator', (value) => typeof value === 'function' && value.constructor.name === 'AsyncGeneratorFunction'); +export const isAsyncGenerator = extend(Object, 'isAsyncGenerator', (value) => typeof value === 'function' && value.constructor.name === 'AsyncGeneratorFunction'); /** @see [[ObjectConstructor.isIterator]] */ -extend(Object, 'isIterator', (value) => { +export const isIterator = extend(Object, 'isIterator', (value) => { if (value == null || typeof value !== 'object' || !('next' in value)) { return false; } @@ -151,20 +160,8 @@ extend(Object, 'isIterator', (value) => { return typeof value.next === 'function'; }); -/** @see [[ObjectConstructor.isIterableIterator]] */ -extend(Object, 'isIterableIterator', (value) => - Object.isIterator(value) && Object.isIterable(value)); - -/** @see [[ObjectConstructor.isAsyncIterator]] */ -extend(Object, 'isAsyncIterator', (value) => - Object.isIterator(value) && Object.isAsyncIterable(value)); - -/** @see [[ObjectConstructor.isAnyIterator]] */ -extend(Object, 'isAnyIterator', (value) => - Object.isIterator(value) || Object.isAsyncIterator(value)); - /** @see [[ObjectConstructor.isIterable]] */ -extend(Object, 'isIterable', (value) => { +export const isIterable = extend(Object, 'isIterable', (value) => { if (value == null) { return false; } @@ -173,7 +170,7 @@ extend(Object, 'isIterable', (value) => { }); /** @see [[ObjectConstructor.isAsyncIterable]] */ -extend(Object, 'isAsyncIterable', (value) => { +export const isAsyncIterable = extend(Object, 'isAsyncIterable', (value) => { if (value == null) { return false; } @@ -181,12 +178,24 @@ extend(Object, 'isAsyncIterable', (value) => { return typeof value[Symbol.asyncIterator] === 'function'; }); +/** @see [[ObjectConstructor.isIterableIterator]] */ +export const isIterableIterator = extend(Object, 'isIterableIterator', (value) => + isIterator(value) && isIterable(value)); + +/** @see [[ObjectConstructor.isAsyncIterator]] */ +export const isAsyncIterator = extend(Object, 'isAsyncIterator', (value) => + isIterator(value) && isAsyncIterable(value)); + +/** @see [[ObjectConstructor.isAnyIterator]] */ +export const isAnyIterator = extend(Object, 'isAnyIterator', (value) => + isIterator(value) || isAsyncIterator(value)); + /** @see [[ObjectConstructor.isAnyIterable]] */ -extend(Object, 'isAnyIterable', (value) => +export const isAnyIterable = extend(Object, 'isAnyIterable', (value) => Object.isIterable(value) || Object.isAsyncIterable(value)); /** @see [[ObjectConstructor.isPromise]] */ -extend(Object, 'isPromise', (value) => { +export const isPromise = extend(Object, 'isPromise', (value) => { if (value == null || typeof value !== 'object' || !('then' in value) || !('catch' in value)) { return false; } @@ -195,7 +204,7 @@ extend(Object, 'isPromise', (value) => { }); /** @see [[ObjectConstructor.isPromiseLike]] */ -extend(Object, 'isPromiseLike', (value) => { +export const isPromiseLike = extend(Object, 'isPromiseLike', (value) => { if (value == null || typeof value !== 'object' || !('then' in value)) { return false; } @@ -204,33 +213,30 @@ extend(Object, 'isPromiseLike', (value) => { }); /** @see [[ObjectConstructor.isProxy]] */ -extend(Object, 'isProxy', (value) => value?.[PROXY] != null); - -/** @see [[ObjectConstructor.unwrapProxy]] */ -extend(Object, 'unwrapProxy', (value) => { - while (value?.[PROXY] && value[PROXY] !== value) { - value = value[PROXY]; - } - - return value; -}); +export const isProxy = extend(Object, 'isProxy', (value) => value?.[PROXY] != null); const { - isExtensible, - isSealed, - isFrozen + isExtensible: originalIsExtensible, + isSealed: originalIsSealed, + isFrozen: originalIsFrozen } = Object; -Object.isExtensible = (value) => { +export const isExtensible = (value: Object | null): boolean => { if (value == null || value[READONLY] === true) { return false; } - return isExtensible(value); + return originalIsExtensible(value); }; -Object.isSealed = (value) => - value == null || isSealed(value) || value[READONLY] === true; +export const isSealed = (value: Object | null): boolean => + value == null || originalIsSealed(value) || value[READONLY] === true; + +export const isFrozen = (value: Object | null): boolean => + value == null || originalIsFrozen(value) || value[READONLY] === true; -Object.isFrozen = (value) => - value == null || isFrozen(value) || value[READONLY] === true; +//#if prelude/standalone +Object.isExtensible = isExtensible; +Object.isSealed = isSealed; +Object.isFrozen = isFrozen; +//#endif