diff --git a/docs/en/v1/api/array/find.md b/docs/en/v1/api/array/find.md index b104825d..ab0d7b38 100644 --- a/docs/en/v1/api/array/find.md +++ b/docs/en/v1/api/array/find.md @@ -5,8 +5,8 @@ prev: text: "isLastIndex" link: "/en/v1/api/array/isLastIndex" next: - text: "findLast" - link: "/en/v1/api/array/findLast" + text: "findDuplicates" + link: "/en/v1/api/array/findDuplicates" --- # find diff --git a/docs/en/v1/api/array/findDuplicates.md b/docs/en/v1/api/array/findDuplicates.md new file mode 100644 index 00000000..9811a721 --- /dev/null +++ b/docs/en/v1/api/array/findDuplicates.md @@ -0,0 +1,48 @@ +--- +outline: [2, 3] +description: "The findDuplicates() function returns duplicated values from an array and keeps a single occurrence for each duplicated value." +prev: + text: "find" + link: "/en/v1/api/array/find" +next: + text: "findLast" + link: "/en/v1/api/array/findLast" +--- + +# findDuplicates + +The **`findDuplicates()`** function returns duplicated values from an array and keeps a single occurrence for each duplicated value. + +## Interactive example + + + +## Syntax + +### Classic signature + +```typescript +function findDuplicates< + GenericInput extends readonly EligibleDuplicateElement[], +>( + array: GenericInput, +): undefined | AnyTuple +``` + +## Parameters + +- `array`: Input array to scan for duplicates. + +## Return value + +Returns `undefined` when no duplicate is found, otherwise returns a tuple containing duplicated values (one occurrence per value). + +## See also + +- [`find`](/en/v1/api/array/find) - Finds a value matching a predicate +- [`group`](/en/v1/api/array/group) - Groups values by key +- [`includes`](/en/v1/api/array/includes) - Checks value presence in an array diff --git a/docs/en/v1/api/array/findLast.md b/docs/en/v1/api/array/findLast.md index 17054e7a..f1c6aa88 100644 --- a/docs/en/v1/api/array/findLast.md +++ b/docs/en/v1/api/array/findLast.md @@ -2,8 +2,8 @@ outline: [2, 3] description: "The findLast() method returns the last element of an array that satisfies a given condition." prev: - text: "find" - link: "/en/v1/api/array/find" + text: "findDuplicates" + link: "/en/v1/api/array/findDuplicates" next: text: "findIndex" link: "/en/v1/api/array/findIndex" diff --git a/docs/en/v1/api/array/index.md b/docs/en/v1/api/array/index.md index be4d8021..fd15b033 100644 --- a/docs/en/v1/api/array/index.md +++ b/docs/en/v1/api/array/index.md @@ -68,6 +68,9 @@ Indicates whether an index corresponds to the last element of the array. ### [find](/en/v1/api/array/find) Finds the first element that satisfies a condition. +### [findDuplicates](/en/v1/api/array/findDuplicates) +Finds duplicated values and keeps one occurrence per duplicate. + ### [findLast](/en/v1/api/array/findLast) Finds the last element that satisfies a condition. diff --git a/docs/examples/v1/api/array/findDuplicates/tryout.doc.ts b/docs/examples/v1/api/array/findDuplicates/tryout.doc.ts new file mode 100644 index 00000000..20482216 --- /dev/null +++ b/docs/examples/v1/api/array/findDuplicates/tryout.doc.ts @@ -0,0 +1,25 @@ +import { A, DDate, pipe, type ExpectType } from "@duplojs/utils"; + +const primitiveResult = A.findDuplicates(["apple", "banana", "apple", "banana", "pear"]); +// ["apple", "banana"] + +const dateValue = DDate.create("2024-01-01"); +const timeValue = DDate.createTime(90, "minute"); +const dateAndTimeResult = A.findDuplicates([ + dateValue, + DDate.create("2024-01-01"), + timeValue, + DDate.createTime(90, "minute"), +]); +// [dateValue, timeValue] + +const pipedResult = pipe( + [true, false, true, false], + A.findDuplicates, +); + +type check = ExpectType< + typeof pipedResult, + undefined | readonly [boolean, ...boolean[]], + "strict" +>; diff --git a/docs/fr/v1/api/array/find.md b/docs/fr/v1/api/array/find.md index 95539186..4e87a387 100644 --- a/docs/fr/v1/api/array/find.md +++ b/docs/fr/v1/api/array/find.md @@ -5,8 +5,8 @@ prev: text: "isLastIndex" link: "/fr/v1/api/array/isLastIndex" next: - text: "findLast" - link: "/fr/v1/api/array/findLast" + text: "findDuplicates" + link: "/fr/v1/api/array/findDuplicates" --- # find diff --git a/docs/fr/v1/api/array/findDuplicates.md b/docs/fr/v1/api/array/findDuplicates.md new file mode 100644 index 00000000..3e5b1b53 --- /dev/null +++ b/docs/fr/v1/api/array/findDuplicates.md @@ -0,0 +1,48 @@ +--- +outline: [2, 3] +description: "La fonction findDuplicates() retourne les valeurs dupliquées d'un tableau et conserve une seule occurrence pour chaque valeur dupliquée." +prev: + text: "find" + link: "/fr/v1/api/array/find" +next: + text: "findLast" + link: "/fr/v1/api/array/findLast" +--- + +# findDuplicates + +La fonction **`findDuplicates()`** retourne les valeurs dupliquées d'un tableau et conserve une seule occurrence pour chaque valeur dupliquée. + +## Exemple interactif + + + +## Syntaxe + +### Signature classique + +```typescript +function findDuplicates< + GenericInput extends readonly EligibleDuplicateElement[], +>( + array: GenericInput, +): undefined | AnyTuple +``` + +## Paramètres + +- `array` : Tableau d'entrée à parcourir pour détecter les doublons. + +## Valeur de retour + +Retourne `undefined` lorsqu'aucun doublon n'est trouvé, sinon retourne un tuple contenant les valeurs dupliquées (une occurrence par valeur). + +## Voir aussi + +- [`find`](/fr/v1/api/array/find) - Trouve une valeur correspondant à un prédicat +- [`group`](/fr/v1/api/array/group) - Regroupe les valeurs par clé +- [`includes`](/fr/v1/api/array/includes) - Vérifie la présence d'une valeur dans un tableau diff --git a/docs/fr/v1/api/array/findLast.md b/docs/fr/v1/api/array/findLast.md index de2d7396..fe7ff66a 100644 --- a/docs/fr/v1/api/array/findLast.md +++ b/docs/fr/v1/api/array/findLast.md @@ -2,8 +2,8 @@ outline: [2, 3] description: "La méthode findLast() retourne le dernier élément d'un tableau qui satisfait une condition donnée." prev: - text: "find" - link: "/fr/v1/api/array/find" + text: "findDuplicates" + link: "/fr/v1/api/array/findDuplicates" next: text: "findIndex" link: "/fr/v1/api/array/findIndex" diff --git a/docs/fr/v1/api/array/index.md b/docs/fr/v1/api/array/index.md index e84f1f55..8d20f5c3 100644 --- a/docs/fr/v1/api/array/index.md +++ b/docs/fr/v1/api/array/index.md @@ -68,6 +68,9 @@ Indique si un index correspond au dernier élément du tableau. ### [find](/fr/v1/api/array/find) Trouve le premier élément qui satisfait une condition. +### [findDuplicates](/fr/v1/api/array/findDuplicates) +Trouve les valeurs dupliquées et conserve une occurrence par doublon. + ### [findLast](/fr/v1/api/array/findLast) Trouve le dernier élément qui satisfait une condition. diff --git a/docs/public/libs/v1/array/findDuplicates.cjs b/docs/public/libs/v1/array/findDuplicates.cjs new file mode 100644 index 00000000..950fd274 --- /dev/null +++ b/docs/public/libs/v1/array/findDuplicates.cjs @@ -0,0 +1,38 @@ +'use strict'; + +var is = require('../date/is.cjs'); +var isTime = require('../date/isTime.cjs'); + +function findDuplicates(array) { + const store = new Map(); + let storeTimeObject = undefined; + let result = undefined; + for (let index$1 = 0; index$1 < array.length; index$1++) { + const element = array[index$1]; + if (is.is(element) || isTime.isTime(element)) { + storeTimeObject ??= new Map(); + const serializedValue = element.toJSON(); + const storedElement = storeTimeObject.get(serializedValue) ?? element; + const storedCount = store.get(storedElement); + if (storedCount === 1) { + result ??= []; + result.push(storedElement); + } + store.set(storedElement, (storedCount ?? 0) + 1); + if (storedElement === element) { + storeTimeObject.set(serializedValue, element); + } + } + else { + const storedCount = store.get(element); + if (storedCount === 1) { + result ??= []; + result.push(element); + } + store.set(element, (storedCount ?? 0) + 1); + } + } + return result; +} + +exports.findDuplicates = findDuplicates; diff --git a/docs/public/libs/v1/array/findDuplicates.d.ts b/docs/public/libs/v1/array/findDuplicates.d.ts new file mode 100644 index 00000000..b41d2ff1 --- /dev/null +++ b/docs/public/libs/v1/array/findDuplicates.d.ts @@ -0,0 +1,4 @@ +import { type AnyTuple } from "../common"; +import * as DDate from "../date"; +export type EligibleDuplicateElement = (string | boolean | null | number | bigint | undefined | DDate.TheDate | DDate.TheTime); +export declare function findDuplicates(array: GenericInput): undefined | AnyTuple; diff --git a/docs/public/libs/v1/array/findDuplicates.mjs b/docs/public/libs/v1/array/findDuplicates.mjs new file mode 100644 index 00000000..19b29fbc --- /dev/null +++ b/docs/public/libs/v1/array/findDuplicates.mjs @@ -0,0 +1,36 @@ +import { is } from '../date/is.mjs'; +import { isTime } from '../date/isTime.mjs'; + +function findDuplicates(array) { + const store = new Map(); + let storeTimeObject = undefined; + let result = undefined; + for (let index$1 = 0; index$1 < array.length; index$1++) { + const element = array[index$1]; + if (is(element) || isTime(element)) { + storeTimeObject ??= new Map(); + const serializedValue = element.toJSON(); + const storedElement = storeTimeObject.get(serializedValue) ?? element; + const storedCount = store.get(storedElement); + if (storedCount === 1) { + result ??= []; + result.push(storedElement); + } + store.set(storedElement, (storedCount ?? 0) + 1); + if (storedElement === element) { + storeTimeObject.set(serializedValue, element); + } + } + else { + const storedCount = store.get(element); + if (storedCount === 1) { + result ??= []; + result.push(element); + } + store.set(element, (storedCount ?? 0) + 1); + } + } + return result; +} + +export { findDuplicates }; diff --git a/docs/public/libs/v1/array/index.cjs b/docs/public/libs/v1/array/index.cjs index 4f61be94..70b267a6 100644 --- a/docs/public/libs/v1/array/index.cjs +++ b/docs/public/libs/v1/array/index.cjs @@ -45,6 +45,7 @@ var isLastIndex = require('./isLastIndex.cjs'); var select = require('./select.cjs'); var lengthEqual = require('./lengthEqual.cjs'); var mapTuple = require('./mapTuple.cjs'); +var findDuplicates = require('./findDuplicates.cjs'); var _delete = require('./splice/delete.cjs'); var insert = require('./splice/insert.cjs'); var replace = require('./splice/replace.cjs'); @@ -110,6 +111,7 @@ exports.select = select.select; exports.selectTools = select.selectTools; exports.lengthEqual = lengthEqual.lengthEqual; exports.mapTuple = mapTuple.mapTuple; +exports.findDuplicates = findDuplicates.findDuplicates; exports.spliceDelete = _delete.spliceDelete; exports.spliceInsert = insert.spliceInsert; exports.spliceReplace = replace.spliceReplace; diff --git a/docs/public/libs/v1/array/index.d.ts b/docs/public/libs/v1/array/index.d.ts index 81f94d52..60b00351 100644 --- a/docs/public/libs/v1/array/index.d.ts +++ b/docs/public/libs/v1/array/index.d.ts @@ -75,3 +75,4 @@ export * from "./isLastIndex"; export * from "./select"; export * from "./lengthEqual"; export * from "./mapTuple"; +export * from "./findDuplicates"; diff --git a/docs/public/libs/v1/array/index.mjs b/docs/public/libs/v1/array/index.mjs index 25efc14c..a0b52463 100644 --- a/docs/public/libs/v1/array/index.mjs +++ b/docs/public/libs/v1/array/index.mjs @@ -43,6 +43,7 @@ export { isLastIndex } from './isLastIndex.mjs'; export { select, selectTools } from './select.mjs'; export { lengthEqual } from './lengthEqual.mjs'; export { mapTuple } from './mapTuple.mjs'; +export { findDuplicates } from './findDuplicates.mjs'; export { spliceDelete } from './splice/delete.mjs'; export { spliceInsert } from './splice/insert.mjs'; export { spliceReplace } from './splice/replace.mjs'; diff --git a/docs/public/libs/v1/clean/constraint/base.d.ts b/docs/public/libs/v1/clean/constraint/base.d.ts index bc8a84eb..fda5c6fc 100644 --- a/docs/public/libs/v1/clean/constraint/base.d.ts +++ b/docs/public/libs/v1/clean/constraint/base.d.ts @@ -101,7 +101,7 @@ export interface ConstraintHandler Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class CreateConstrainedTypeError extends CreateConstrainedTypeError_base { constrainedTypeName: string; data: unknown; diff --git a/docs/public/libs/v1/clean/constraint/set.d.ts b/docs/public/libs/v1/clean/constraint/set.d.ts index 32586358..a924160f 100644 --- a/docs/public/libs/v1/clean/constraint/set.d.ts +++ b/docs/public/libs/v1/clean/constraint/set.d.ts @@ -107,7 +107,7 @@ export interface ConstraintsSetHandler Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class CreateConstraintsSetError extends CreateConstraintsSetError_base { data: unknown; dataParserError: DDataParser.DataParserError; diff --git a/docs/public/libs/v1/clean/entity/index.d.ts b/docs/public/libs/v1/clean/entity/index.d.ts index ba0959d8..072e8673 100644 --- a/docs/public/libs/v1/clean/entity/index.d.ts +++ b/docs/public/libs/v1/clean/entity/index.d.ts @@ -117,7 +117,7 @@ export interface EntityHandler Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class CreateEntityError extends CreateEntityError_base { rawProperties: PropertiesToMapOfEntity; dataParserError: DDataParser.DataParserError; diff --git a/docs/public/libs/v1/clean/flag.d.ts b/docs/public/libs/v1/clean/flag.d.ts index 92a80486..f54b7166 100644 --- a/docs/public/libs/v1/clean/flag.d.ts +++ b/docs/public/libs/v1/clean/flag.d.ts @@ -15,7 +15,7 @@ export interface FlagHandler("majorUser"); * export type MajorFlag = C.GetFlag; * * export function isMajor(entity: Entity) { * if (C.greaterThan(entity.age, 18)) { * return E.success( - * MajorFlag.append(entity, entity.age), + * MajorFlag.append(entity, { age: entity.age }), * ); * } * return E.left("not-major"); @@ -94,7 +94,7 @@ export interface Flag | E.Right<"not-thirsty-anymore", undefined> * - * const flagged = User.MajorFlag.append(user, user.age); + * const flagged = User.MajorFlag.append(user, { age: user.age }); * const value = User.MajorFlag.getValue(flagged); * * ``` diff --git a/docs/public/libs/v1/clean/newType.d.ts b/docs/public/libs/v1/clean/newType.d.ts index 9d4df133..42bff169 100644 --- a/docs/public/libs/v1/clean/newType.d.ts +++ b/docs/public/libs/v1/clean/newType.d.ts @@ -114,7 +114,7 @@ export interface NewTypeHandler Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class CreateNewTypeError extends CreateNewTypeError_base { newTypeName: string; data: unknown; diff --git a/docs/public/libs/v1/clean/primitive/base.d.ts b/docs/public/libs/v1/clean/primitive/base.d.ts index 9dd0c020..d374ce8e 100644 --- a/docs/public/libs/v1/clean/primitive/base.d.ts +++ b/docs/public/libs/v1/clean/primitive/base.d.ts @@ -70,7 +70,7 @@ export interface PrimitiveHandler Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class CreatePrimitiveError extends CreatePrimitiveError_base { data: unknown; dataParserError: DDataParser.DataParserError; diff --git a/docs/public/libs/v1/clean/toMapDataParser.cjs b/docs/public/libs/v1/clean/toMapDataParser.cjs index 20da7ffa..e2b14c50 100644 --- a/docs/public/libs/v1/clean/toMapDataParser.cjs +++ b/docs/public/libs/v1/clean/toMapDataParser.cjs @@ -1,10 +1,11 @@ 'use strict'; var newType = require('./newType.cjs'); +var hasSomeKinds = require('../common/hasSomeKinds.cjs'); +var property = require('./entity/property.cjs'); var base = require('./primitive/base.cjs'); var base$1 = require('./constraint/base.cjs'); var set = require('./constraint/set.cjs'); -var hasSomeKinds = require('../common/hasSomeKinds.cjs'); var index = require('../pattern/match/index.cjs'); var transform = require('../dataParser/parsers/transform.cjs'); var index$1 = require('../dataParser/parsers/string/index.cjs'); @@ -18,6 +19,15 @@ var nil = require('../dataParser/parsers/nil.cjs'); var wrapValue = require('../common/wrapValue.cjs'); function toMapDataParser(input, params) { + if (hasSomeKinds.hasSomeKinds(input, [ + property.entityPropertyNullableKind, + property.entityPropertyArrayKind, + property.entityPropertyStructureKind, + property.entityPropertyIdentifierKind, + property.entityPropertyUnionKind, + ])) { + return property.entityPropertyDefinitionToDataParser(input, (newTypeHandler) => toMapDataParser(newTypeHandler, params)); + } const dataParser = (base.primitiveHandlerKind.has(input) ? input.dataParser.clone() : input.internal.dataParser.clone()); diff --git a/docs/public/libs/v1/clean/toMapDataParser.d.ts b/docs/public/libs/v1/clean/toMapDataParser.d.ts index 8ef67f6a..51d9afa7 100644 --- a/docs/public/libs/v1/clean/toMapDataParser.d.ts +++ b/docs/public/libs/v1/clean/toMapDataParser.d.ts @@ -1,9 +1,9 @@ import * as DDataParser from "../dataParser"; import { type ConstraintHandler, type ConstraintsSetHandler, type GetConstraint, type GetConstraints } from "./constraint"; -import { type GetNewType, type NewTypeHandler } from "./newType"; import { type PrimitiveHandler } from "./primitive"; -type ToMapDataParserInput = NewTypeHandler | ConstraintHandler | ConstraintsSetHandler | PrimitiveHandler; -type OutputDataParser = GenericInput extends NewTypeHandler ? GetNewType : GenericInput extends ConstraintHandler ? GetConstraint : GenericInput extends ConstraintsSetHandler ? GetConstraints : GenericInput extends PrimitiveHandler ? ReturnType : never; +import { type EntityPropertyDefinition, type EntityProperty } from "./entity"; +type ToMapDataParserInput = (ConstraintHandler | ConstraintsSetHandler | PrimitiveHandler | EntityPropertyDefinition); +type OutputDataParser = GenericInput extends ConstraintHandler ? GetConstraint : GenericInput extends ConstraintsSetHandler ? GetConstraints : GenericInput extends PrimitiveHandler ? ReturnType : GenericInput extends EntityPropertyDefinition ? EntityProperty : never; interface ToMapDataParserParams { coerce?: boolean; } @@ -41,7 +41,7 @@ interface ToMapDataParserParams { * ``` * * @remarks - * - Supported inputs: `NewTypeHandler`, `ConstraintHandler`, `ConstraintsSetHandler`, and `PrimitiveHandler`. + * - Supported inputs: `NewTypeHandler`, `ConstraintHandler`, `ConstraintsSetHandler`, `PrimitiveHandler`, and `EntityProperty`. * - Use `coerce: true` to allow conversions (e.g. number to string) on compatible parsers. * * @see https://utils.duplojs.dev/en/v1/api/clean/toMapDataParser @@ -49,5 +49,5 @@ interface ToMapDataParserParams { * @namespace C * */ -export declare function toMapDataParser(input: GenericInput, params?: ToMapDataParserParams): DDataParser.Contract, GenericInputDataParser>; +export declare function toMapDataParser>(input: GenericInput, params?: ToMapDataParserParams): DDataParser.Contract, unknown>; export {}; diff --git a/docs/public/libs/v1/clean/toMapDataParser.mjs b/docs/public/libs/v1/clean/toMapDataParser.mjs index 9e841245..03ba64df 100644 --- a/docs/public/libs/v1/clean/toMapDataParser.mjs +++ b/docs/public/libs/v1/clean/toMapDataParser.mjs @@ -1,8 +1,9 @@ import { newTypeHandlerKind, newTypeKind } from './newType.mjs'; +import { hasSomeKinds } from '../common/hasSomeKinds.mjs'; +import { entityPropertyDefinitionToDataParser, entityPropertyNullableKind, entityPropertyArrayKind, entityPropertyStructureKind, entityPropertyIdentifierKind, entityPropertyUnionKind } from './entity/property.mjs'; import { primitiveHandlerKind } from './primitive/base.mjs'; import { constrainedTypeKind, constraintHandlerKind } from './constraint/base.mjs'; import { constraintsSetHandlerKind } from './constraint/set.mjs'; -import { hasSomeKinds } from '../common/hasSomeKinds.mjs'; import { match } from '../pattern/match/index.mjs'; import { transform } from '../dataParser/parsers/transform.mjs'; import { stringKind } from '../dataParser/parsers/string/index.mjs'; @@ -16,6 +17,15 @@ import { nilKind } from '../dataParser/parsers/nil.mjs'; import { keyWrappedValue } from '../common/wrapValue.mjs'; function toMapDataParser(input, params) { + if (hasSomeKinds(input, [ + entityPropertyNullableKind, + entityPropertyArrayKind, + entityPropertyStructureKind, + entityPropertyIdentifierKind, + entityPropertyUnionKind, + ])) { + return entityPropertyDefinitionToDataParser(input, (newTypeHandler) => toMapDataParser(newTypeHandler, params)); + } const dataParser = (primitiveHandlerKind.has(input) ? input.dataParser.clone() : input.internal.dataParser.clone()); diff --git a/docs/public/libs/v1/common/asserts.d.ts b/docs/public/libs/v1/common/asserts.d.ts index 6018cdc3..60a12610 100644 --- a/docs/public/libs/v1/common/asserts.d.ts +++ b/docs/public/libs/v1/common/asserts.d.ts @@ -1,6 +1,6 @@ declare const AssertsError_base: new (params: { "@DuplojsUtilsError/asserts-error"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("./kind").Kind, unknown> & import("./kind").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("./kind").Kind, unknown> & import("./kind").Kind, unknown>; export declare class AssertsError extends AssertsError_base { value: unknown; constructor(value: unknown); diff --git a/docs/public/libs/v1/common/stringToBytes.d.ts b/docs/public/libs/v1/common/stringToBytes.d.ts index 23f0ee81..11587812 100644 --- a/docs/public/libs/v1/common/stringToBytes.d.ts +++ b/docs/public/libs/v1/common/stringToBytes.d.ts @@ -1,6 +1,6 @@ declare const InvalidBytesInStringError_base: new (params: { "@DuplojsUtilsError/missing-builder-methods-error"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("./kind").Kind, unknown> & import("./kind").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("./kind").Kind, unknown> & import("./kind").Kind, unknown>; export declare class InvalidBytesInStringError extends InvalidBytesInStringError_base { input: string; constructor(input: string); diff --git a/docs/public/libs/v1/common/toRegExp.cjs b/docs/public/libs/v1/common/toRegExp.cjs index d6c24f81..7d5707f7 100644 --- a/docs/public/libs/v1/common/toRegExp.cjs +++ b/docs/public/libs/v1/common/toRegExp.cjs @@ -1,7 +1,6 @@ 'use strict'; var escapeRegExp = require('./escapeRegExp.cjs'); -var is = require('../array/is.cjs'); /** * {@include common/toRegExp/index.md} @@ -10,7 +9,7 @@ function toRegExp(input) { if (typeof input === "string") { return new RegExp(`^${escapeRegExp.escapeRegExp(input)}$`); } - if (is.is(input)) { + if (input instanceof Array) { const result = input.map(escapeRegExp.escapeRegExp).join("|"); return new RegExp(`^(?:${result})$`); } diff --git a/docs/public/libs/v1/common/toRegExp.mjs b/docs/public/libs/v1/common/toRegExp.mjs index 6992cbe8..fbeee25c 100644 --- a/docs/public/libs/v1/common/toRegExp.mjs +++ b/docs/public/libs/v1/common/toRegExp.mjs @@ -1,5 +1,4 @@ import { escapeRegExp } from './escapeRegExp.mjs'; -import { is } from '../array/is.mjs'; /** * {@include common/toRegExp/index.md} @@ -8,7 +7,7 @@ function toRegExp(input) { if (typeof input === "string") { return new RegExp(`^${escapeRegExp(input)}$`); } - if (is(input)) { + if (input instanceof Array) { const result = input.map(escapeRegExp).join("|"); return new RegExp(`^(?:${result})$`); } diff --git a/docs/public/libs/v1/dataParser/base.cjs b/docs/public/libs/v1/dataParser/base.cjs index fa2de3cc..089fe286 100644 --- a/docs/public/libs/v1/dataParser/base.cjs +++ b/docs/public/libs/v1/dataParser/base.cjs @@ -45,7 +45,7 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, error, checker); + const checkerResult = checker.exec(result, error, checker, self); if (checkerResult === SDPE) { return SDPE; } @@ -61,7 +61,7 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, error, checker); + const checkerResult = checker.exec(result, error, checker, self); if (checkerResult === SDPE) { return SDPE; } diff --git a/docs/public/libs/v1/dataParser/base.d.ts b/docs/public/libs/v1/dataParser/base.d.ts index 29133be2..4da9d2ec 100644 --- a/docs/public/libs/v1/dataParser/base.d.ts +++ b/docs/public/libs/v1/dataParser/base.d.ts @@ -8,7 +8,7 @@ export interface DataParserCheckerDefinition { } export interface DataParserChecker extends Kind { readonly definition: GenericDefinition; - exec(data: GenericInput, error: DataParserError, self: this): GenericOutput | SymbolDataParserError; + exec(data: GenericInput, error: DataParserError, self: this, dataParser: DataParser): GenericOutput | SymbolDataParserError; } export type InputChecker = Parameters[0]; export declare function dataParserCheckerInit(kind: Exclude, typeof checkerKind>, params: NoInfer, "exec">>, exec: (...args: Parameters) => InputChecker | SymbolDataParserError): GenericDataParserChecker; @@ -245,7 +245,7 @@ interface DataParserInitExecParams { } declare const DataParserThrowError_base: new (params: { "@DuplojsUtilsError/dataParserThrowError"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & Kind, unknown> & Kind, unknown>; export declare class DataParserThrowError extends DataParserThrowError_base { value: unknown; constructor(value: unknown); diff --git a/docs/public/libs/v1/dataParser/base.mjs b/docs/public/libs/v1/dataParser/base.mjs index 8f56f5aa..3f862bbd 100644 --- a/docs/public/libs/v1/dataParser/base.mjs +++ b/docs/public/libs/v1/dataParser/base.mjs @@ -43,7 +43,7 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, error, checker); + const checkerResult = checker.exec(result, error, checker, self); if (checkerResult === SDPE) { return SDPE; } @@ -59,7 +59,7 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, error, checker); + const checkerResult = checker.exec(result, error, checker, self); if (checkerResult === SDPE) { return SDPE; } diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.cjs index a3b6f807..8b27aba4 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.cjs @@ -11,9 +11,9 @@ function checkerArrayMax(max, definition = {}) { ...definition, max, }, - }, (data, error$1, self) => data.length <= self.definition.max + }, (data, error$1, self, dataParser) => data.length <= self.definition.max ? data - : error.addIssue(error$1, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage)); + : error.addIssue(error$1, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerArrayMax = checkerArrayMax; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs index 3957498a..e5535ca8 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs @@ -9,9 +9,9 @@ function checkerArrayMax(max, definition = {}) { ...definition, max, }, - }, (data, error, self) => data.length <= self.definition.max + }, (data, error, self, dataParser) => data.length <= self.definition.max ? data - : addIssue(error, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage)); + : addIssue(error, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerArrayMax, checkerArrayMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs index be0b35bd..6c3e4d2f 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs @@ -11,9 +11,9 @@ function checkerArrayMin(min, definition = {}) { ...definition, min, }, - }, (data, error$1, self) => data.length >= self.definition.min + }, (data, error$1, self, dataParser) => data.length >= self.definition.min ? data - : error.addIssue(error$1, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage)); + : error.addIssue(error$1, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerArrayMin = checkerArrayMin; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs index fa75795e..ee7520f2 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs @@ -9,9 +9,9 @@ function checkerArrayMin(min, definition = {}) { ...definition, min, }, - }, (data, error, self) => data.length >= self.definition.min + }, (data, error, self, dataParser) => data.length >= self.definition.min ? data - : addIssue(error, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage)); + : addIssue(error, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerArrayMin, checkerArrayMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs index 24d06fc6..3a0c8e43 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs @@ -11,9 +11,9 @@ function checkerBigIntMax(max, definition = {}) { ...definition, max, }, - }, (value, error$1, self) => { + }, (value, error$1, self, dataParser) => { if (value > self.definition.max) { - return error.addIssue(error$1, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage); + return error.addIssue(error$1, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs index 5cadd5a4..525935e2 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs @@ -9,9 +9,9 @@ function checkerBigIntMax(max, definition = {}) { ...definition, max, }, - }, (value, error, self) => { + }, (value, error, self, dataParser) => { if (value > self.definition.max) { - return addIssue(error, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage); + return addIssue(error, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs index f27213b5..f2dddd22 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs @@ -11,9 +11,9 @@ function checkerBigIntMin(min, definition = {}) { ...definition, min, }, - }, (value, error$1, self) => { + }, (value, error$1, self, dataParser) => { if (value < self.definition.min) { - return error.addIssue(error$1, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage); + return error.addIssue(error$1, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs index 51b816d8..3a3a7a44 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs @@ -9,9 +9,9 @@ function checkerBigIntMin(min, definition = {}) { ...definition, min, }, - }, (value, error, self) => { + }, (value, error, self, dataParser) => { if (value < self.definition.min) { - return addIssue(error, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage); + return addIssue(error, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs index 5fa131ca..c832b55c 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs @@ -9,11 +9,11 @@ const checkerIntKind = kind.createDataParserKind("checker-number-int"); function checkerInt(definition = {}) { return base.dataParserCheckerInit(checkerIntKind, { definition, - }, (data, error$1, self) => { + }, (data, error$1, self, dataParser) => { if (Number.isInteger(data)) { return data; } - return error.addIssue(error$1, "integer", data, self.definition.errorMessage); + return error.addIssue(error$1, "integer", data, self.definition.errorMessage ?? dataParser.definition.errorMessage); }); } function int(definition) { diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs index 2c7abaef..08a776a5 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs @@ -7,11 +7,11 @@ const checkerIntKind = createDataParserKind("checker-number-int"); function checkerInt(definition = {}) { return dataParserCheckerInit(checkerIntKind, { definition, - }, (data, error, self) => { + }, (data, error, self, dataParser) => { if (Number.isInteger(data)) { return data; } - return addIssue(error, "integer", data, self.definition.errorMessage); + return addIssue(error, "integer", data, self.definition.errorMessage ?? dataParser.definition.errorMessage); }); } function int(definition) { diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs index 7d2455aa..fef70252 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs @@ -11,9 +11,9 @@ function checkerNumberMax(max, definition = {}) { ...definition, max, }, - }, (value, error$1, self) => value <= self.definition.max + }, (value, error$1, self, dataParser) => value <= self.definition.max ? value - : error.addIssue(error$1, `number <= ${self.definition.max}`, value, self.definition.errorMessage)); + : error.addIssue(error$1, `number <= ${self.definition.max}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerNumberMax = checkerNumberMax; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs index 6e908a90..67ee0bfd 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs @@ -9,9 +9,9 @@ function checkerNumberMax(max, definition = {}) { ...definition, max, }, - }, (value, error, self) => value <= self.definition.max + }, (value, error, self, dataParser) => value <= self.definition.max ? value - : addIssue(error, `number <= ${self.definition.max}`, value, self.definition.errorMessage)); + : addIssue(error, `number <= ${self.definition.max}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerNumberMax, checkerNumberMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs index 59058c68..c160ffa8 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs @@ -11,9 +11,9 @@ function checkerNumberMin(min, definition = {}) { ...definition, min, }, - }, (value, error$1, self) => value >= self.definition.min + }, (value, error$1, self, dataParser) => value >= self.definition.min ? value - : error.addIssue(error$1, `number >= ${self.definition.min}`, value, self.definition.errorMessage)); + : error.addIssue(error$1, `number >= ${self.definition.min}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerNumberMin = checkerNumberMin; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs index 11138be6..330ab008 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs @@ -9,9 +9,9 @@ function checkerNumberMin(min, definition = {}) { ...definition, min, }, - }, (value, error, self) => value >= self.definition.min + }, (value, error, self, dataParser) => value >= self.definition.min ? value - : addIssue(error, `number >= ${self.definition.min}`, value, self.definition.errorMessage)); + : addIssue(error, `number >= ${self.definition.min}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerNumberMin, checkerNumberMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/refine.cjs b/docs/public/libs/v1/dataParser/parsers/refine.cjs index 4bf0161d..4adc336d 100644 --- a/docs/public/libs/v1/dataParser/parsers/refine.cjs +++ b/docs/public/libs/v1/dataParser/parsers/refine.cjs @@ -11,9 +11,9 @@ function checkerRefine(theFunction, definition) { ...definition, theFunction, }, - }, (value, error$1, self) => self.definition.theFunction(value) + }, (value, error$1, self, dataParser) => self.definition.theFunction(value) ? value - : error.addIssue(error$1, "value matching refine predicate", value, self.definition.errorMessage)); + : error.addIssue(error$1, "value matching refine predicate", value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerRefine = checkerRefine; diff --git a/docs/public/libs/v1/dataParser/parsers/refine.mjs b/docs/public/libs/v1/dataParser/parsers/refine.mjs index ecdc64ec..9df26766 100644 --- a/docs/public/libs/v1/dataParser/parsers/refine.mjs +++ b/docs/public/libs/v1/dataParser/parsers/refine.mjs @@ -9,9 +9,9 @@ function checkerRefine(theFunction, definition) { ...definition, theFunction, }, - }, (value, error, self) => self.definition.theFunction(value) + }, (value, error, self, dataParser) => self.definition.theFunction(value) ? value - : addIssue(error, "value matching refine predicate", value, self.definition.errorMessage)); + : addIssue(error, "value matching refine predicate", value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerRefine, dataParserCheckerRefineKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs index abfeec3e..95a1cafc 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs @@ -13,9 +13,9 @@ function checkerEmail(definition = {}) { ...definition, regex: emailRegex, }, - }, (data, error$1, self) => self.definition.regex.test(data) + }, (data, error$1, self, dataParser) => self.definition.regex.test(data) ? data - : error.addIssue(error$1, "email", data, self.definition.errorMessage)); + : error.addIssue(error$1, "email", data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } function email(definition) { return index.string({ diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs index 3b6a3cab..026c2c86 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs @@ -11,9 +11,9 @@ function checkerEmail(definition = {}) { ...definition, regex: emailRegex, }, - }, (data, error, self) => self.definition.regex.test(data) + }, (data, error, self, dataParser) => self.definition.regex.test(data) ? data - : addIssue(error, "email", data, self.definition.errorMessage)); + : addIssue(error, "email", data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } function email(definition) { return string({ diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs index aa59dac1..947e57da 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs @@ -11,9 +11,9 @@ function checkerStringMax(max, definition = {}) { ...definition, max, }, - }, (data, error$1, self) => data.length <= self.definition.max + }, (data, error$1, self, dataParser) => data.length <= self.definition.max ? data - : error.addIssue(error$1, `string.length <= ${self.definition.max}`, data, self.definition.errorMessage)); + : error.addIssue(error$1, `string.length <= ${self.definition.max}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerStringMax = checkerStringMax; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs index c42e8992..80833edc 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs @@ -9,9 +9,9 @@ function checkerStringMax(max, definition = {}) { ...definition, max, }, - }, (data, error, self) => data.length <= self.definition.max + }, (data, error, self, dataParser) => data.length <= self.definition.max ? data - : addIssue(error, `string.length <= ${self.definition.max}`, data, self.definition.errorMessage)); + : addIssue(error, `string.length <= ${self.definition.max}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerStringMax, checkerStringMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs index 46fb6460..0aceb3af 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs @@ -11,9 +11,9 @@ function checkerStringMin(min, definition = {}) { ...definition, min, }, - }, (data, error$1, self) => data.length >= self.definition.min + }, (data, error$1, self, dataParser) => data.length >= self.definition.min ? data - : error.addIssue(error$1, `string.length >= ${self.definition.min}`, data, self.definition.errorMessage)); + : error.addIssue(error$1, `string.length >= ${self.definition.min}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerStringMin = checkerStringMin; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs index 2c31566a..0749d348 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs @@ -9,9 +9,9 @@ function checkerStringMin(min, definition = {}) { ...definition, min, }, - }, (data, error, self) => data.length >= self.definition.min + }, (data, error, self, dataParser) => data.length >= self.definition.min ? data - : addIssue(error, `string.length >= ${self.definition.min}`, data, self.definition.errorMessage)); + : addIssue(error, `string.length >= ${self.definition.min}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerStringMin, checkerStringMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs index 8ca92aef..129282c7 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs @@ -11,9 +11,9 @@ function checkerRegex(regex, definition = {}) { ...definition, regex, }, - }, (data, error$1, self) => self.definition.regex.test(data) + }, (data, error$1, self, dataParser) => self.definition.regex.test(data) ? data - : error.addIssue(error$1, `string with pattern ${self.definition.regex.source.toString()}`, data, self.definition.errorMessage)); + : error.addIssue(error$1, `string with pattern ${self.definition.regex.source.toString()}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerRegex = checkerRegex; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs index e6fb9cfa..eb22bc62 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs @@ -9,9 +9,9 @@ function checkerRegex(regex, definition = {}) { ...definition, regex, }, - }, (data, error, self) => self.definition.regex.test(data) + }, (data, error, self, dataParser) => self.definition.regex.test(data) ? data - : addIssue(error, `string with pattern ${self.definition.regex.source.toString()}`, data, self.definition.errorMessage)); + : addIssue(error, `string with pattern ${self.definition.regex.source.toString()}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerRegex, checkerRegexKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs index b78c361e..1454c3a3 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs @@ -10,19 +10,19 @@ const regexRemoveDote = /:$/; function checkerUrl(definition = {}) { return base.dataParserCheckerInit(checkerUrlKind, { definition: definition, - }, (data, error$1, self) => { + }, (data, error$1, self, dataParser) => { try { const url = new URL(data); if (self.definition.hostname) { self.definition.hostname.lastIndex = 0; if (!self.definition.hostname.test(url.hostname)) { - return error.addIssue(error$1, `URL with hostname matching ${self.definition.hostname.source}`, data, self.definition.errorMessage); + return error.addIssue(error$1, `URL with hostname matching ${self.definition.hostname.source}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } } if (self.definition.protocol) { self.definition.protocol.lastIndex = 0; if (!self.definition.protocol.test(url.protocol.replace(regexRemoveDote, ""))) { - return error.addIssue(error$1, `URL with protocol matching ${self.definition.protocol.source}`, data, self.definition.errorMessage); + return error.addIssue(error$1, `URL with protocol matching ${self.definition.protocol.source}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } } if (self.definition.normalize) { @@ -33,7 +33,7 @@ function checkerUrl(definition = {}) { } } catch { - return error.addIssue(error$1, "valid URL", data, self.definition.errorMessage); + return error.addIssue(error$1, "valid URL", data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } }); } diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs index 4f2d4b73..c0c1b187 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs @@ -8,19 +8,19 @@ const regexRemoveDote = /:$/; function checkerUrl(definition = {}) { return dataParserCheckerInit(checkerUrlKind, { definition: definition, - }, (data, error, self) => { + }, (data, error, self, dataParser) => { try { const url = new URL(data); if (self.definition.hostname) { self.definition.hostname.lastIndex = 0; if (!self.definition.hostname.test(url.hostname)) { - return addIssue(error, `URL with hostname matching ${self.definition.hostname.source}`, data, self.definition.errorMessage); + return addIssue(error, `URL with hostname matching ${self.definition.hostname.source}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } } if (self.definition.protocol) { self.definition.protocol.lastIndex = 0; if (!self.definition.protocol.test(url.protocol.replace(regexRemoveDote, ""))) { - return addIssue(error, `URL with protocol matching ${self.definition.protocol.source}`, data, self.definition.errorMessage); + return addIssue(error, `URL with protocol matching ${self.definition.protocol.source}`, data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } } if (self.definition.normalize) { @@ -31,7 +31,7 @@ function checkerUrl(definition = {}) { } } catch { - return addIssue(error, "valid URL", data, self.definition.errorMessage); + return addIssue(error, "valid URL", data, self.definition.errorMessage ?? dataParser.definition.errorMessage); } }); } diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.cjs index a3d89d03..a7995ec8 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.cjs @@ -13,9 +13,9 @@ function checkerUuid(definition = {}) { ...definition, regex: uuidRegex, }, - }, (data, error$1, self) => uuidRegex.test(data) + }, (data, error$1, self, dataParser) => uuidRegex.test(data) ? data - : error.addIssue(error$1, "uuid", data, self.definition.errorMessage)); + : error.addIssue(error$1, "uuid", data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } /** * {@include dataParser/classic/uuid/index.md} diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.mjs index e2db8be4..363698b7 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/uuid.mjs @@ -11,9 +11,9 @@ function checkerUuid(definition = {}) { ...definition, regex: uuidRegex, }, - }, (data, error, self) => uuidRegex.test(data) + }, (data, error, self, dataParser) => uuidRegex.test(data) ? data - : addIssue(error, "uuid", data, self.definition.errorMessage)); + : addIssue(error, "uuid", data, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } /** * {@include dataParser/classic/uuid/index.md} diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs index 3b97bf6d..cdbc7341 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs @@ -15,9 +15,9 @@ function checkerTimeMax(max, definition = {}) { ...definition, max, }, - }, (value, error$1, self) => lessTime.lessTime(value, self.definition.max) + }, (value, error$1, self, dataParser) => lessTime.lessTime(value, self.definition.max) ? value - : error.addIssue(error$1, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage)); + : error.addIssue(error$1, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerTimeMax = checkerTimeMax; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs index 4b4416b7..e921578e 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs @@ -13,9 +13,9 @@ function checkerTimeMax(max, definition = {}) { ...definition, max, }, - }, (value, error, self) => lessTime(value, self.definition.max) + }, (value, error, self, dataParser) => lessTime(value, self.definition.max) ? value - : addIssue(error, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage)); + : addIssue(error, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerTimeMax, checkerTimeMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs index 3e548c47..883755e0 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs @@ -15,9 +15,9 @@ function checkerTimeMin(min, definition = {}) { ...definition, min, }, - }, (value, error$1, self) => greaterTime.greaterTime(value, self.definition.min) + }, (value, error$1, self, dataParser) => greaterTime.greaterTime(value, self.definition.min) ? value - : error.addIssue(error$1, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage)); + : error.addIssue(error$1, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } exports.checkerTimeMin = checkerTimeMin; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs index 71d0f7d2..a1a60335 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs @@ -13,9 +13,9 @@ function checkerTimeMin(min, definition = {}) { ...definition, min, }, - }, (value, error, self) => greaterTime(value, self.definition.min) + }, (value, error, self, dataParser) => greaterTime(value, self.definition.min) ? value - : addIssue(error, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage)); + : addIssue(error, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage ?? dataParser.definition.errorMessage)); } export { checkerTimeMin, checkerTimeMinKind }; diff --git a/docs/public/libs/v1/date/createOrThrow.cjs b/docs/public/libs/v1/date/createOrThrow.cjs index e53beb9b..8eaea183 100644 --- a/docs/public/libs/v1/date/createOrThrow.cjs +++ b/docs/public/libs/v1/date/createOrThrow.cjs @@ -1,10 +1,10 @@ 'use strict'; -var create = require('./create.cjs'); var kind = require('../common/kind.cjs'); +var unwrap = require('../common/unwrap.cjs'); var errorKindNamespace = require('../common/errorKindNamespace.cjs'); +var create = require('./create.cjs'); var is = require('../either/left/is.cjs'); -var unwrap = require('../common/unwrap.cjs'); class CreateTheDateError extends kind.kindHeritage("create-the-date-error", errorKindNamespace.createErrorKind("create-the-date-error"), Error) { input; diff --git a/docs/public/libs/v1/date/createOrThrow.d.ts b/docs/public/libs/v1/date/createOrThrow.d.ts index 83c45fc5..c701bff0 100644 --- a/docs/public/libs/v1/date/createOrThrow.d.ts +++ b/docs/public/libs/v1/date/createOrThrow.d.ts @@ -2,7 +2,7 @@ import type { SerializedTheDate, SpoolingDate } from "./types"; import type { TheDate } from "./theDate"; declare const CreateTheDateError_base: new (params: { "@DuplojsUtilsError/create-the-date-error"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind, unknown> & import("../common").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => import("../common/kind").Kind, unknown> & import("../common/kind").Kind, unknown> & Error; export declare class CreateTheDateError extends CreateTheDateError_base { input: string | Date | number | SpoolingDate | TheDate; constructor(input: string | Date | number | SpoolingDate | TheDate); diff --git a/docs/public/libs/v1/date/createOrThrow.mjs b/docs/public/libs/v1/date/createOrThrow.mjs index 3047659e..74b54de7 100644 --- a/docs/public/libs/v1/date/createOrThrow.mjs +++ b/docs/public/libs/v1/date/createOrThrow.mjs @@ -1,8 +1,8 @@ -import { create } from './create.mjs'; import { kindHeritage } from '../common/kind.mjs'; +import { unwrap } from '../common/unwrap.mjs'; import { createErrorKind } from '../common/errorKindNamespace.mjs'; +import { create } from './create.mjs'; import { isLeft } from '../either/left/is.mjs'; -import { unwrap } from '../common/unwrap.mjs'; class CreateTheDateError extends kindHeritage("create-the-date-error", createErrorKind("create-the-date-error"), Error) { input; diff --git a/docs/public/libs/v1/date/createTimeOrThrow.cjs b/docs/public/libs/v1/date/createTimeOrThrow.cjs index dce20138..a2f806c4 100644 --- a/docs/public/libs/v1/date/createTimeOrThrow.cjs +++ b/docs/public/libs/v1/date/createTimeOrThrow.cjs @@ -2,9 +2,9 @@ var createTime = require('./createTime.cjs'); var kind = require('../common/kind.cjs'); +var errorKindNamespace = require('../common/errorKindNamespace.cjs'); var is = require('../either/left/is.cjs'); var unwrap = require('../common/unwrap.cjs'); -var errorKindNamespace = require('../common/errorKindNamespace.cjs'); class CreateTheTimeError extends kind.kindHeritage("create-the-time-error", errorKindNamespace.createErrorKind("create-the-time-error"), Error) { input; diff --git a/docs/public/libs/v1/date/createTimeOrThrow.d.ts b/docs/public/libs/v1/date/createTimeOrThrow.d.ts index a424b59a..14b30280 100644 --- a/docs/public/libs/v1/date/createTimeOrThrow.d.ts +++ b/docs/public/libs/v1/date/createTimeOrThrow.d.ts @@ -2,7 +2,7 @@ import type { SerializedTheTime, SpoolingTime } from "./types"; import { type TheTime } from "./theTime"; declare const CreateTheTimeError_base: new (params: { "@DuplojsUtilsError/create-the-time-error"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind, unknown> & import("../common").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind, unknown> & import("../common").Kind, unknown>; export declare class CreateTheTimeError extends CreateTheTimeError_base { input: TheTime | number | SpoolingTime | SerializedTheTime; constructor(input: TheTime | number | SpoolingTime | SerializedTheTime); diff --git a/docs/public/libs/v1/date/createTimeOrThrow.mjs b/docs/public/libs/v1/date/createTimeOrThrow.mjs index 6a7b3901..36a63dca 100644 --- a/docs/public/libs/v1/date/createTimeOrThrow.mjs +++ b/docs/public/libs/v1/date/createTimeOrThrow.mjs @@ -1,8 +1,8 @@ import { createTime } from './createTime.mjs'; import { kindHeritage } from '../common/kind.mjs'; +import { createErrorKind } from '../common/errorKindNamespace.mjs'; import { isLeft } from '../either/left/is.mjs'; import { unwrap } from '../common/unwrap.mjs'; -import { createErrorKind } from '../common/errorKindNamespace.mjs'; class CreateTheTimeError extends kindHeritage("create-the-time-error", createErrorKind("create-the-time-error"), Error) { input; diff --git a/docs/public/libs/v1/date/theDate.d.ts b/docs/public/libs/v1/date/theDate.d.ts index 70e266d0..d4e657d4 100644 --- a/docs/public/libs/v1/date/theDate.d.ts +++ b/docs/public/libs/v1/date/theDate.d.ts @@ -1,7 +1,7 @@ import type { SerializedTheDate } from "./types/serializedTheDate"; declare const TheDate_base: new (params: { "@DuplojsUtilsDate/the-date"?: unknown; -}, parentParams: readonly [value: string | number | Date]) => Date & import("../common/kind").Kind, unknown> & import("../common/kind").Kind, unknown>; +}, parentParams: readonly [value: string | number | Date]) => import("../common/kind").Kind, unknown> & import("../common/kind").Kind, unknown> & Date; /** * Represents an immutable date-time object (`TheDate`) based on UTC. * diff --git a/docs/public/libs/v1/date/theTime.d.ts b/docs/public/libs/v1/date/theTime.d.ts index 2ee349b2..d5d8a403 100644 --- a/docs/public/libs/v1/date/theTime.d.ts +++ b/docs/public/libs/v1/date/theTime.d.ts @@ -1,7 +1,7 @@ import type { SerializedTheTime } from "./types"; declare const TheTime_base: new (params?: { "@DuplojsUtilsDate/the-time"?: unknown; -} | undefined) => import("../common/kind").Kind, unknown> & import("../common/kind").Kind, unknown>; +} | undefined) => import("../common/kind").Kind, unknown> & import("../common/kind").Kind, unknown>; /** * Represents an immutable signed time value object (`TheTime`) stored in milliseconds. * diff --git a/docs/public/libs/v1/flow/run.d.ts b/docs/public/libs/v1/flow/run.d.ts index 84efc95c..5ce299bf 100644 --- a/docs/public/libs/v1/flow/run.d.ts +++ b/docs/public/libs/v1/flow/run.d.ts @@ -24,7 +24,7 @@ export interface FlowDetails = (GenericFlow extends TheFlow ? InferredFunction extends TheFlowFunction ? InferredGenerator extends TheFlowGenerator ? ((InferredEffect extends Exit ? InferredValue : InferredEffect extends Break ? InferredValue : InferredEffect extends Throttling ? InferredValue : InferredEffect extends Debounce ? InferredValue : never) | InferredOutput) extends infer InferredResult ? IsEqual extends true ? FlowDetails ? InferredName : never> : InferredResult : never : never : never : never) extends infer InferredResult ? ExtractFlowGenerator extends AsyncGenerator ? Promise : InferredResult : never; declare const MissingDependenceError_base: new (params: { "@DuplojsUtilsFlow/missing-dependence-error"?: unknown; -}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind, unknown> & import("../common").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind, unknown> & import("../common").Kind, unknown>; export declare class MissingDependenceError extends MissingDependenceError_base { dependenceHandler: DependenceHandler; constructor(dependenceHandler: DependenceHandler); diff --git a/docs/public/libs/v1/metadata.json b/docs/public/libs/v1/metadata.json index dcde8a5f..03d0aef3 100644 --- a/docs/public/libs/v1/metadata.json +++ b/docs/public/libs/v1/metadata.json @@ -251,6 +251,15 @@ { "name": "findAndReplace.mjs" }, + { + "name": "findDuplicates.cjs" + }, + { + "name": "findDuplicates.d.ts" + }, + { + "name": "findDuplicates.mjs" + }, { "name": "findIndex.cjs" }, diff --git a/docs/public/libs/v1/pattern/match/builder.d.ts b/docs/public/libs/v1/pattern/match/builder.d.ts index 9e9a9c76..33d6bce0 100644 --- a/docs/public/libs/v1/pattern/match/builder.d.ts +++ b/docs/public/libs/v1/pattern/match/builder.d.ts @@ -23,7 +23,7 @@ export interface MatchBuilder Error & import("../../common").Kind, unknown> & import("../../common").Kind, unknown>; +}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../../common").Kind, unknown> & import("../../common").Kind, unknown>; export declare class InvalidExhaustivePatternError extends InvalidExhaustivePatternError_base { input: unknown; constructor(input: unknown); diff --git a/jsDoc/array/findDuplicates/example.ts b/jsDoc/array/findDuplicates/example.ts new file mode 100644 index 00000000..e8a8a546 --- /dev/null +++ b/jsDoc/array/findDuplicates/example.ts @@ -0,0 +1,25 @@ +import { A, DDate, pipe, type ExpectType } from "@scripts"; + +const primitiveDuplicates = A.findDuplicates(["apple", "banana", "apple", "banana", "pear"]); +// primitiveDuplicates: ["apple", "banana"] + +const dateValue = DDate.create("2024-01-01"); +const timeValue = DDate.createTime(90, "minute"); +const dateAndTimeDuplicates = A.findDuplicates([ + dateValue, + DDate.create("2024-01-01"), + timeValue, + DDate.createTime(90, "minute"), +]); +// dateAndTimeDuplicates: [dateValue, timeValue] + +const pipedDuplicates = pipe( + [true, false, true, false], + A.findDuplicates, +); + +type check = ExpectType< + typeof pipedDuplicates, + undefined | readonly [boolean, ...boolean[]], + "strict" +>; diff --git a/jsDoc/array/findDuplicates/index.md b/jsDoc/array/findDuplicates/index.md new file mode 100644 index 00000000..ed3a620b --- /dev/null +++ b/jsDoc/array/findDuplicates/index.md @@ -0,0 +1,21 @@ +Finds duplicated values in an array and returns each duplicated value once. + +**Supported call styles:** +- Classic: `findDuplicates(array)` → returns duplicates or `undefined` + +Accepts primitive values plus `TheDate` and `TheTime` values from the date namespace. +For date/time values, duplicates are matched by serialized value. + +```ts +{@include array/findDuplicates/example.ts[3,24]} +``` + +@remarks +- Returns `undefined` when no duplicates are found +- Keeps one occurrence per duplicated value in the result + +@see [`A.includes`](https://utils.duplojs.dev/en/v1/api/array/includes) For checking a single value presence +@see [`A.group`](https://utils.duplojs.dev/en/v1/api/array/group) For grouping values by key +@see https://utils.duplojs.dev/en/v1/api/array/findDuplicates + +@namespace A diff --git a/scripts/array/findDuplicates.ts b/scripts/array/findDuplicates.ts new file mode 100644 index 00000000..736b2dcc --- /dev/null +++ b/scripts/array/findDuplicates.ts @@ -0,0 +1,66 @@ +/* eslint-disable @typescript-eslint/prefer-for-of */ +import { type AnyTuple } from "@scripts/common"; +import * as DDate from "@scripts/date"; + +export type EligibleDuplicateElement = ( + | string + | boolean + | null + | number + | bigint + | undefined + | DDate.TheDate + | DDate.TheTime +); + +export function findDuplicates< + GenericInput extends readonly EligibleDuplicateElement[], +>(array: GenericInput): undefined | AnyTuple; + +export function findDuplicates(array: EligibleDuplicateElement[]): any { + const store = new Map< + EligibleDuplicateElement, + number + >(); + let storeTimeObject: ( + | undefined + | Map< + DDate.SerializedTheDate | DDate.SerializedTheTime, + DDate.TheDate | DDate.TheTime + > + ) = undefined; + let result: undefined | any[] = undefined; + + for (let index = 0; index < array.length; index++) { + const element = array[index]; + + if (DDate.is(element) || DDate.isTime(element)) { + storeTimeObject ??= new Map(); + + const serializedValue = element.toJSON(); + const storedElement = storeTimeObject.get(serializedValue) ?? element; + const storedCount = store.get(storedElement); + + if (storedCount === 1) { + result ??= []; + result.push(storedElement); + } + + store.set(storedElement, (storedCount ?? 0) + 1); + if (storedElement === element) { + storeTimeObject.set(serializedValue, element); + } + } else { + const storedCount = store.get(element); + + if (storedCount === 1) { + result ??= []; + result.push(element); + } + + store.set(element, (storedCount ?? 0) + 1); + } + } + + return result; +} diff --git a/scripts/array/index.ts b/scripts/array/index.ts index ebd80256..dff17cbe 100644 --- a/scripts/array/index.ts +++ b/scripts/array/index.ts @@ -52,3 +52,4 @@ export * from "./isLastIndex"; export * from "./select"; export * from "./lengthEqual"; export * from "./mapTuple"; +export * from "./findDuplicates"; diff --git a/scripts/common/createKindIdentifier.ts b/scripts/common/createKindIdentifier.ts index da24bd27..f65cd370 100644 --- a/scripts/common/createKindIdentifier.ts +++ b/scripts/common/createKindIdentifier.ts @@ -1,6 +1,6 @@ import { type GetKindHandler, type Kind, type KindDefinition, type KindHandler } from "./kind"; import { type UnionContain, type UnionToIntersection } from "./types"; -import * as DArray from "@scripts/array"; +import { coalescing } from "@scripts/array/coalescing"; export function createKindIdentifier< GenericParent extends Kind, @@ -81,7 +81,7 @@ export function createKindIdentifier< const [input, kind] = args; - const formattedKind = DArray.coalescing(kind); + const formattedKind = coalescing(kind); for (const kind of formattedKind) { if (!kind.has(input)) { diff --git a/scripts/common/instanceOf.ts b/scripts/common/instanceOf.ts index 828ec6db..af2b415f 100644 --- a/scripts/common/instanceOf.ts +++ b/scripts/common/instanceOf.ts @@ -1,4 +1,4 @@ -import * as DArray from "@scripts/array"; +import { coalescing } from "@scripts/array/coalescing"; import { type AnyConstructor } from "./types"; /** @@ -37,7 +37,7 @@ export function instanceOf( const [input, constructor] = args; - const formattedConstructor = DArray.coalescing(constructor); + const formattedConstructor = coalescing(constructor); for (const constructor of formattedConstructor) { if (input instanceof constructor) { diff --git a/scripts/common/toRegExp.ts b/scripts/common/toRegExp.ts index 59c347cd..552f7045 100644 --- a/scripts/common/toRegExp.ts +++ b/scripts/common/toRegExp.ts @@ -1,6 +1,5 @@ import type { AnyTuple } from "./types"; import { escapeRegExp } from "./escapeRegExp"; -import * as DArray from "@scripts/array"; /** * {@include common/toRegExp/index.md} @@ -10,7 +9,7 @@ export function toRegExp(input: string | AnyTuple | RegExp): RegExp { return new RegExp(`^${escapeRegExp(input)}$`); } - if (DArray.is(input)) { + if (input instanceof Array) { const result = input.map(escapeRegExp).join("|"); return new RegExp(`^(?:${result})$`); diff --git a/scripts/date/createOrThrow.ts b/scripts/date/createOrThrow.ts index 90b5043e..71343a2f 100644 --- a/scripts/date/createOrThrow.ts +++ b/scripts/date/createOrThrow.ts @@ -1,4 +1,6 @@ -import { createErrorKind, kindHeritage, unwrap } from "@scripts/common"; +import { kindHeritage } from "@scripts/common/kind"; +import { unwrap } from "@scripts/common/unwrap"; +import { createErrorKind } from "@scripts/common/errorKindNamespace"; import { create } from "./create"; import type { SerializedTheDate, SpoolingDate } from "./types"; import * as DEither from "@scripts/either"; diff --git a/tests/array/findDuplicates.test.ts b/tests/array/findDuplicates.test.ts new file mode 100644 index 00000000..a1d59738 --- /dev/null +++ b/tests/array/findDuplicates.test.ts @@ -0,0 +1,70 @@ +import { type AnyTuple, DArray, type ExpectType, pipe, DDate } from "@scripts"; + +describe("findDuplicates", () => { + it("returns undefined when array has no duplicates", () => { + const result = DArray.findDuplicates(["a", 1, true, null, undefined]); + + expect(result).toBeUndefined(); + + type check = ExpectType< + typeof result, + undefined | AnyTuple, + "strict" + >; + }); + + it("returns each duplicated primitive only once", () => { + const result = DArray.findDuplicates(["a", "b", "a", "a", "b", 1, 1, 1]); + + expect(result).toStrictEqual(["a", "b", 1]); + + type check = ExpectType< + typeof result, + undefined | readonly [string | number, ...(string | number)[]], + "strict" + >; + }); + + it("handles nullish and bigint duplicates", () => { + const result = DArray.findDuplicates([undefined, null, 1n, undefined, 1n, null, 1n]); + + expect(result).toStrictEqual([undefined, 1n, null]); + }); + + it("works in pipe", () => { + const result = pipe( + [true, false, true, false, false], + DArray.findDuplicates, + ); + + expect(result).toStrictEqual([true, false]); + + type check = ExpectType< + typeof result, + undefined | readonly [boolean, ...boolean[]], + "strict" + >; + }); + + it("returns only one duplicate for TheDate values sharing same serialized value", () => { + const dateA = DDate.create("2024-01-01"); + const dateB = DDate.create("2024-01-01"); + const dateC = DDate.create("2024-01-01"); + + const result = DArray.findDuplicates([dateA, dateB, dateC]); + + expect(result).toStrictEqual([dateA]); + expect(result?.[0]).toBe(dateA); + }); + + it("returns only one duplicate for TheTime values sharing same serialized value", () => { + const timeA = DDate.createTime(5, "minute"); + const timeB = DDate.createTime(5, "minute"); + const timeC = DDate.createTime(5, "minute"); + + const result = DArray.findDuplicates([timeA, timeB, timeC]); + + expect(result).toStrictEqual([timeA]); + expect(result?.[0]).toBe(timeA); + }); +});