Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add items action #595

Closed
ruiaraujo012 opened this issue May 23, 2024 · 10 comments
Closed

Add items action #595

ruiaraujo012 opened this issue May 23, 2024 · 10 comments
Assignees
Labels
enhancement New feature or request

Comments

@ruiaraujo012
Copy link
Sponsor

ruiaraujo012 commented May 23, 2024

The action should have these arguments (item, index, items) => boolean
#487 (comment)

Here is an example where I have called the action "items":

import {
  _addIssue,
  type BaseIssue,
  type BaseValidation,
  type ErrorMessage,
} from 'valibot';

/**
 * Items issue type.
 */
export interface ItemsIssue<TInput extends unknown[]>
  extends BaseIssue<TInput> {
  /**
   * The issue kind.
   */
  readonly kind: 'validation';
  /**
   * The issue type.
   */
  readonly type: 'items';
  /**
   * The expected input.
   */
  readonly expected: null;
  /**
   * The validation function.
   */
  readonly requirement: (input: TInput[number]) => boolean;
}

/**
 * Items action type.
 */
export interface ItemsAction<
  TInput extends unknown[],
  TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
> extends BaseValidation<TInput, TInput, ItemsIssue<TInput>> {
  /**
   * The action type.
   */
  readonly type: 'items';
  /**
   * The action reference.
   */
  readonly reference: typeof items;
  /**
   * The expected property.
   */
  readonly expects: null;
  /**
   * The validation function.
   */
  readonly requirement: (input: TInput[number]) => boolean;
  /**
   * The error message.
   */
  readonly message: TMessage;
}

/**
 * Creates an items validation action.
 *
 * @param requirement The validation function.
 *
 * @returns An items action.
 */
export function items<TInput extends unknown[]>(
  requirement: (input: TInput[number]) => boolean
): ItemsAction<TInput, undefined>;

/**
 * Creates an items validation action.
 *
 * @param requirement The validation function.
 * @param message The error message.
 *
 * @returns An items action.
 */
export function items<
  TInput extends unknown[],
  const TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
>(
  requirement: (input: TInput[number]) => boolean,
  message: TMessage
): ItemsAction<TInput, TMessage>;

export function items(
  requirement: (input: unknown) => boolean,
  message?: ErrorMessage<ItemsIssue<unknown[]>>
): ItemsAction<unknown[], ErrorMessage<ItemsIssue<unknown[]>> | undefined> {
  return {
    kind: 'validation',
    type: 'items',
    reference: items,
    async: false,
    expects: null,
    requirement,
    message,
    _run(dataset, config) {
      if (dataset.typed) {
        for (let index = 0; index < dataset.value.length; index++) {
          const item = dataset.value[index];
          if (!this.requirement(item)) {
            _addIssue(this, 'item', dataset, config, {
              input: item,
              path: [
                {
                  type: 'array',
                  origin: 'value',
                  input: dataset.value,
                  key: index,
                  value: item,
                },
              ],
            });
          }
        }
      }
      return dataset;
    },
  };
}

Now you can write the following code:

import * as v from 'valibot';
import { items } from './your-path';

const Schema = v.pipe(
  v.array(v.string()),
  items((item) => item.startsWith('foo'), 'Your message')
);

Originally posted by @fabian-hiller in #487 (comment)

@fabian-hiller fabian-hiller self-assigned this May 23, 2024
@fabian-hiller fabian-hiller added the enhancement New feature or request label May 23, 2024
@fabian-hiller
Copy link
Owner

Thank you!

@fabian-hiller
Copy link
Owner

I have started to work in this issue.

@ruiaraujo012
Copy link
Sponsor Author

Nice, thanks for letting me know.

@fabian-hiller
Copy link
Owner

I am still unsure of the correct name. The advantage and difference of this action is that a issue is automatically associated with the item that caused the problem. items and iterate do not reflect this in my eyes. What do you think about checkItem or forEach? The name checkItem is very clear and easy to read. forEach might also work as I plan to add actions for the other iterator methods like sort and filter as well.

@fabian-hiller
Copy link
Owner

I ran into another problem. Since we already have a map schema, I can't add a map action for transforming arrays due to the name collision. One solution to this problem is to call the map action forEach. Another solution might be to add the suffix Item or Items to these functions: everyItem, filterItems, findItem, mapItems, reduceItems, someItem. The last solution would also work well with checkItems.

@ruiaraujo012
Copy link
Sponsor Author

ruiaraujo012 commented Jun 16, 2024

What about checkEach? I think it reflects what it does. checkItems it's a good name as well.
I agree with you when you say that items or iterate doesn't reflect what it does.

@fabian-hiller
Copy link
Owner

checkEach is great, but I really like the Item and Items suffixes for the iterator actions. This makes it even clearer and prevents other naming conflicts in the future. If we go this way, checkItems would make more sense in my eyes.

@ruiaraujo012
Copy link
Sponsor Author

I can see that. I'm OK with checkItems, so go on :D.

@fabian-hiller
Copy link
Owner

Valibot v0.33.1 is now available 🎉

@ruiaraujo012
Copy link
Sponsor Author

Thank you. I saw you have created more Items actions, which is nice :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants