Skip to content

feat: add isoDuration action for RFC 3339 durations#1540

Open
AmadNaseem wants to merge 2 commits into
open-circle:mainfrom
AmadNaseem:feat/iso-duration
Open

feat: add isoDuration action for RFC 3339 durations#1540
AmadNaseem wants to merge 2 commits into
open-circle:mainfrom
AmadNaseem:feat/iso-duration

Conversation

@AmadNaseem

@AmadNaseem AmadNaseem commented Jul 14, 2026

Copy link
Copy Markdown

Closes #1497

Adds an isoDuration validation action for RFC 3339 duration strings (e.g. P1D, PT5H30M, P1Y2M3DT4H5M6S), useful for validating OpenAPI format: duration fields.

It mirrors the existing ISO action family (isoDate, isoTime, isoTimestamp, isoWeek) exactly:

  • library/src/actions/isoDuration/isoDuration.ts, index.ts, isoDuration.test.ts, isoDuration.test-d.ts
  • ISO_DURATION_REGEX in library/src/regex.ts
  • export in library/src/actions/index.ts
  • API-reference pages for isoDuration, IsoDurationAction, IsoDurationIssue, plus the menu and the "Related" lists
  • a CHANGELOG.md entry

Validation

The pattern is a direct transcription of the RFC 3339 Appendix A duration ABNF, so it enforces structure, not just characters:

  • must start with P and contain at least one component (P and PT are rejected)
  • time components require the T designator (PT1S is valid, P1S is not)
  • the week form is standalone (P4W; P1W2D is rejected)
  • components must be in Y M D T H M S order; no fractional values

Note this follows the RFC 3339 grammar rather than the looser colloquial ISO 8601 reading, so e.g. P1Y1D (year + day, skipping month) is rejected — matching the ABNF nesting dur-year = 1*DIGIT "Y" [dur-month]. Happy to relax this if you'd prefer the looser interpretation.

The regex was checked for linear-time behaviour (no catastrophic backtracking), consistent with the existing IPV4_REGEX / DECIMAL_REGEX redos-detector suppressions.

Tests

20 runtime tests and 6 type tests, mirroring isoWeek's test structure, covering the accept/reject matrix and message behaviour. The full actions suite passes and tsc --noEmit is clean.

Deliberately left as follow-ups (happy to do separately if you'd like them in scope)

  • @valibot/i18n: no localized message added (the action falls back to the default English message). Adding it would touch every translation file.
  • @valibot/to-json-schema: no duration → JSON Schema pattern converter yet.

Summary by CodeRabbit

  • New Features

    • Added isoDuration validation for ISO 8601/RFC 3339 duration strings.
    • Supports custom error messages and integration with validation pipelines and composition APIs.
    • Invalid, incomplete, or malformed durations now produce clear validation issues.
  • Documentation

    • Added API reference and guide content for isoDuration, IsoDurationAction, and IsoDurationIssue.
    • Updated related API listings and navigation to include the new validation action.

Copilot AI review requested due to automatic review settings July 14, 2026 07:47
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds the isoDuration validation action for ISO 8601 / RFC 3339 duration strings, including its regex, typed contracts, runtime behavior, exports, and tests. Adds API documentation for the action and related types, updates documentation indexes and related-action lists, and records the feature in the changelog.

Suggested reviewers: copilot, fabian-hiller

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an isoDuration validator for RFC 3339 durations.
Linked Issues check ✅ Passed The PR implements the requested built-in RFC 3339 duration validator and aligns with the issue examples and OpenAPI compatibility goal.
Out of Scope Changes check ✅ Passed The added docs, menu entries, and changelog updates are directly supporting the new isoDuration action and appear in scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new isoDuration validation action to Valibot for validating RFC 3339 duration strings (OpenAPI format: duration use case), and wires it into the library exports and the website API reference.

Changes:

  • Added ISO_DURATION_REGEX and a new isoDuration validation action (with runtime + type tests) in library/src/.
  • Added website API reference pages/types for isoDuration, plus menu and “Related/combined with” list updates.
  • Added an unreleased CHANGELOG.md entry for the new action.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
website/src/routes/guides/(main-concepts)/pipelines/index.mdx Adds isoDuration to the pipelines guide action list.
website/src/routes/api/menu.md Adds isoDuration, IsoDurationAction, and IsoDurationIssue to the API menu.
website/src/routes/api/(types)/IsoDurationIssue/properties.ts Defines API-property metadata for IsoDurationIssue.
website/src/routes/api/(types)/IsoDurationIssue/index.mdx Adds the IsoDurationIssue API reference page.
website/src/routes/api/(types)/IsoDurationAction/properties.ts Defines API-property metadata for IsoDurationAction.
website/src/routes/api/(types)/IsoDurationAction/index.mdx Adds the IsoDurationAction API reference page.
website/src/routes/api/(schemas)/unknown/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/union/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/string/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/lazy/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/intersect/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/custom/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(schemas)/any/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(methods)/pipe/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(methods)/message/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(methods)/fallback/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(methods)/config/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/unionAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/pipeAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/lazyAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/intersectAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/fallbackAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(async)/customAsync/index.mdx Adds isoDuration to “can be combined with” list.
website/src/routes/api/(actions)/isoDuration/properties.ts Defines API-property metadata for the isoDuration action page.
website/src/routes/api/(actions)/isoDuration/index.mdx Adds the isoDuration action API reference page.
library/src/regex.ts Adds ISO_DURATION_REGEX.
library/src/actions/isoDuration/isoDuration.ts Implements isoDuration, IsoDurationIssue, and IsoDurationAction.
library/src/actions/isoDuration/isoDuration.test.ts Adds runtime tests for isoDuration.
library/src/actions/isoDuration/isoDuration.test-d.ts Adds type-level tests for isoDuration.
library/src/actions/isoDuration/index.ts Adds barrel export for isoDuration.
library/src/actions/index.ts Exports isoDuration from the actions index.
library/CHANGELOG.md Adds an unreleased changelog entry for isoDuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +66 to +73
* Creates an [ISO duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)
* validation action.
*
* Format: PnYnMnDTnHnMnS
*
* Hint: The regex used cannot validate the semantic order or plausibility of
* the components. For example, "P0D" is valid although it represents a zero
* duration.
Comment on lines +83 to +90
* Creates an [ISO duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)
* validation action.
*
* Format: PnYnMnDTnHnMnS
*
* Hint: The regex used cannot validate the semantic order or plausibility of
* the components. For example, "P0D" is valid although it represents a zero
* duration.
Comment on lines +14 to +18
Creates an [ISO duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) validation action.

Format: `PnYnMnDTnHnMnS`

> The regex used cannot validate the semantic order or plausibility of the components. For example, "P0D" is valid although it represents a zero duration.

### Explanation

With `isoDuration` you can validate the formatting of a string. If the input is not an ISO duration, you can use `message` to customize the error message.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@library/CHANGELOG.md`:
- Around line 5-8: Replace the placeholder heading in the changelog with the
repository’s actual release version and date, or use the project’s established
unreleased-heading format. Keep the isoDuration entry unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f41713a4-7bb4-4009-9d3c-c1e35f7a8fc9

📥 Commits

Reviewing files that changed from the base of the PR and between 32247b3 and c5fdfaa.

📒 Files selected for processing (32)
  • library/CHANGELOG.md
  • library/src/actions/index.ts
  • library/src/actions/isoDuration/index.ts
  • library/src/actions/isoDuration/isoDuration.test-d.ts
  • library/src/actions/isoDuration/isoDuration.test.ts
  • library/src/actions/isoDuration/isoDuration.ts
  • library/src/regex.ts
  • website/src/routes/api/(actions)/isoDuration/index.mdx
  • website/src/routes/api/(actions)/isoDuration/properties.ts
  • website/src/routes/api/(async)/customAsync/index.mdx
  • website/src/routes/api/(async)/fallbackAsync/index.mdx
  • website/src/routes/api/(async)/intersectAsync/index.mdx
  • website/src/routes/api/(async)/lazyAsync/index.mdx
  • website/src/routes/api/(async)/pipeAsync/index.mdx
  • website/src/routes/api/(async)/unionAsync/index.mdx
  • website/src/routes/api/(methods)/config/index.mdx
  • website/src/routes/api/(methods)/fallback/index.mdx
  • website/src/routes/api/(methods)/message/index.mdx
  • website/src/routes/api/(methods)/pipe/index.mdx
  • website/src/routes/api/(schemas)/any/index.mdx
  • website/src/routes/api/(schemas)/custom/index.mdx
  • website/src/routes/api/(schemas)/intersect/index.mdx
  • website/src/routes/api/(schemas)/lazy/index.mdx
  • website/src/routes/api/(schemas)/string/index.mdx
  • website/src/routes/api/(schemas)/union/index.mdx
  • website/src/routes/api/(schemas)/unknown/index.mdx
  • website/src/routes/api/(types)/IsoDurationAction/index.mdx
  • website/src/routes/api/(types)/IsoDurationAction/properties.ts
  • website/src/routes/api/(types)/IsoDurationIssue/index.mdx
  • website/src/routes/api/(types)/IsoDurationIssue/properties.ts
  • website/src/routes/api/menu.md
  • website/src/routes/guides/(main-concepts)/pipelines/index.mdx

Comment thread library/CHANGELOG.md
Comment on lines +5 to +8
## vX.X.X (Month DD, YYYY)

- Add `isoDuration` validation action to validate ISO 8601 / RFC 3339 duration strings (pull request #1540)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the placeholder release metadata before merging.

vX.X.X (Month DD, YYYY) is not valid release metadata and would leave the changelog with a placeholder version/date. Use the repository’s actual release version and date, or its established unreleased-heading format.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@library/CHANGELOG.md` around lines 5 - 8, Replace the placeholder heading in
the changelog with the repository’s actual release version and date, or use the
project’s established unreleased-heading format. Keep the isoDuration entry
unchanged.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="library/src/actions/isoDuration/isoDuration.ts">

<violation number="1" location="library/src/actions/isoDuration/isoDuration.ts:71">
P3: Generated API docs incorrectly say component order is not validated, although this action rejects out-of-order components. Remove or correct this hint so users understand the strict RFC 3339 behavior.</violation>
</file>

<file name="website/src/routes/api/(actions)/isoDuration/index.mdx">

<violation number="1" location="website/src/routes/api/(actions)/isoDuration/index.mdx:18">
P3: The note says the regex 'cannot validate the semantic order' of the components, but the ISO_DURATION_REGEX does enforce component order structurally — Y before M before D, and H before M before S, separated by T. The example (P0D) demonstrates a plausibility issue (zero duration), not an order issue. Suggest rewording to avoid implying the regex accepts out-of-order components (e.g., P1M1Y or P1S1H), which it does not.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

*
* Format: PnYnMnDTnHnMnS
*
* Hint: The regex used cannot validate the semantic order or plausibility of

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Generated API docs incorrectly say component order is not validated, although this action rejects out-of-order components. Remove or correct this hint so users understand the strict RFC 3339 behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At library/src/actions/isoDuration/isoDuration.ts, line 71:

<comment>Generated API docs incorrectly say component order is not validated, although this action rejects out-of-order components. Remove or correct this hint so users understand the strict RFC 3339 behavior.</comment>

<file context>
@@ -0,0 +1,123 @@
+ *
+ * Format: PnYnMnDTnHnMnS
+ *
+ * Hint: The regex used cannot validate the semantic order or plausibility of
+ * the components. For example, "P0D" is valid although it represents a zero
+ * duration.
</file context>


Format: `PnYnMnDTnHnMnS`

> The regex used cannot validate the semantic order or plausibility of the components. For example, "P0D" is valid although it represents a zero duration.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The note says the regex 'cannot validate the semantic order' of the components, but the ISO_DURATION_REGEX does enforce component order structurally — Y before M before D, and H before M before S, separated by T. The example (P0D) demonstrates a plausibility issue (zero duration), not an order issue. Suggest rewording to avoid implying the regex accepts out-of-order components (e.g., P1M1Y or P1S1H), which it does not.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/src/routes/api/(actions)/isoDuration/index.mdx, line 18:

<comment>The note says the regex 'cannot validate the semantic order' of the components, but the ISO_DURATION_REGEX does enforce component order structurally — Y before M before D, and H before M before S, separated by T. The example (P0D) demonstrates a plausibility issue (zero duration), not an order issue. Suggest rewording to avoid implying the regex accepts out-of-order components (e.g., P1M1Y or P1S1H), which it does not.</comment>

<file context>
@@ -0,0 +1,70 @@
+
+Format: `PnYnMnDTnHnMnS`
+
+> The regex used cannot validate the semantic order or plausibility of the components. For example, "P0D" is valid although it represents a zero duration.
+
+```ts
</file context>
Suggested change
> The regex used cannot validate the semantic order or plausibility of the components. For example, "P0D" is valid although it represents a zero duration.
> The regex used cannot validate the semantic plausibility of the components. For example, "P0D" is valid although it represents a zero duration.

@yslpn

yslpn commented Jul 18, 2026

Copy link
Copy Markdown
Member

Thanks all for the PRs (#1520, #1526, #1540). We're moving forward with #1520 first. If it stalls, we'll fall back to #1526 or #1540 instead of blocking the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: RFC 3339 duration Validator

3 participants