feat: add isoDuration action for RFC 3339 durations#1540
Conversation
WalkthroughAdds the Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
There was a problem hiding this comment.
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_REGEXand a newisoDurationvalidation action (with runtime + type tests) inlibrary/src/. - Added website API reference pages/types for
isoDuration, plus menu and “Related/combined with” list updates. - Added an unreleased
CHANGELOG.mdentry 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.
| * 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. |
| * 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. |
| 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. |
There was a problem hiding this comment.
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
📒 Files selected for processing (32)
library/CHANGELOG.mdlibrary/src/actions/index.tslibrary/src/actions/isoDuration/index.tslibrary/src/actions/isoDuration/isoDuration.test-d.tslibrary/src/actions/isoDuration/isoDuration.test.tslibrary/src/actions/isoDuration/isoDuration.tslibrary/src/regex.tswebsite/src/routes/api/(actions)/isoDuration/index.mdxwebsite/src/routes/api/(actions)/isoDuration/properties.tswebsite/src/routes/api/(async)/customAsync/index.mdxwebsite/src/routes/api/(async)/fallbackAsync/index.mdxwebsite/src/routes/api/(async)/intersectAsync/index.mdxwebsite/src/routes/api/(async)/lazyAsync/index.mdxwebsite/src/routes/api/(async)/pipeAsync/index.mdxwebsite/src/routes/api/(async)/unionAsync/index.mdxwebsite/src/routes/api/(methods)/config/index.mdxwebsite/src/routes/api/(methods)/fallback/index.mdxwebsite/src/routes/api/(methods)/message/index.mdxwebsite/src/routes/api/(methods)/pipe/index.mdxwebsite/src/routes/api/(schemas)/any/index.mdxwebsite/src/routes/api/(schemas)/custom/index.mdxwebsite/src/routes/api/(schemas)/intersect/index.mdxwebsite/src/routes/api/(schemas)/lazy/index.mdxwebsite/src/routes/api/(schemas)/string/index.mdxwebsite/src/routes/api/(schemas)/union/index.mdxwebsite/src/routes/api/(schemas)/unknown/index.mdxwebsite/src/routes/api/(types)/IsoDurationAction/index.mdxwebsite/src/routes/api/(types)/IsoDurationAction/properties.tswebsite/src/routes/api/(types)/IsoDurationIssue/index.mdxwebsite/src/routes/api/(types)/IsoDurationIssue/properties.tswebsite/src/routes/api/menu.mdwebsite/src/routes/guides/(main-concepts)/pipelines/index.mdx
| ## vX.X.X (Month DD, YYYY) | ||
|
|
||
| - Add `isoDuration` validation action to validate ISO 8601 / RFC 3339 duration strings (pull request #1540) | ||
|
|
There was a problem hiding this comment.
📐 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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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>
| > 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. |
Closes #1497
Adds an
isoDurationvalidation action for RFC 3339 duration strings (e.g.P1D,PT5H30M,P1Y2M3DT4H5M6S), useful for validating OpenAPIformat: durationfields.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.tsISO_DURATION_REGEXinlibrary/src/regex.tslibrary/src/actions/index.tsisoDuration,IsoDurationAction,IsoDurationIssue, plus the menu and the "Related" listsCHANGELOG.mdentryValidation
The pattern is a direct transcription of the RFC 3339 Appendix A
durationABNF, so it enforces structure, not just characters:Pand contain at least one component (PandPTare rejected)Tdesignator (PT1Sis valid,P1Sis not)P4W;P1W2Dis rejected)Y M D T H M Sorder; no fractional valuesNote 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 nestingdur-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_REGEXredos-detectorsuppressions.Tests
20 runtime tests and 6 type tests, mirroring
isoWeek's test structure, covering the accept/reject matrix and message behaviour. The fullactionssuite passes andtsc --noEmitis 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: noduration→ JSON Schemapatternconverter yet.Summary by CodeRabbit
New Features
isoDurationvalidation for ISO 8601/RFC 3339 duration strings.Documentation
isoDuration,IsoDurationAction, andIsoDurationIssue.