-
-
Notifications
You must be signed in to change notification settings - Fork 16
fix: add formatters for Duration and Period types #52
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
base: main
Are you sure you want to change the base?
fix: add formatters for Duration and Period types #52
Conversation
Fixes: accordproject/template-playground#14 When Duration or Period types were used in TemplateMark templates, they rendered as raw JSON. This adds a drafter that formats them as human-readable text (e.g., '2 days' instead of JSON). Signed-off-by: Shubh-Raj <shubhraj625@gmail.com>
There was a problem hiding this comment.
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 support for formatting Duration and Period types in TemplateMark templates, converting them from raw JSON objects to human-readable text. Additionally, it implements validation to prevent unguarded access to optional properties in templates.
- Adds formatters for Duration/Period types that render as "{amount} {unit}"
- Implements optional property access validation in the template interpreter
- Enhances template playground to use optional guards for age field
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/drafting/Duration/index.ts | New drafter implementation for Duration/Period formatting |
| src/drafting/index.ts | Registers Duration and Period drafters |
| test/DurationDrafter.test.ts | Unit tests for Duration/Period formatting |
| src/TemplateMarkInterpreter.ts | Adds validation logic for unguarded optional property access |
| test/templates/good/playground/template.md | Updates age field to use optional guard syntax |
| test/templates/bad/optional-noguard/* | New test case for validating optional property guards |
| test/snapshots/TemplateArchiveProcessor.test.ts.snap | Updated snapshot showing Duration formatting output |
| test/snapshots/TemplateMarkInterpreter.test.ts.snap | Updated snapshots reflecting optional guard changes and validation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/TemplateMarkInterpreter.ts
Outdated
| } | ||
| catch (err) { | ||
| throw new Error(`Generated invalid agreement: ${err}: ${JSON.stringify(templateMark, null, 2)}`); | ||
| } | ||
|
|
||
| // Check for unguarded optional property access |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The serialization validation code returns early on success (line 577 was removed), which prevents the optional property access validation from executing when serialization succeeds. The return statement should be moved to after the optional property validation (after line 637).
| * @returns {string} the text (e.g., "2 days") | ||
| */ | ||
| export default function durationDrafter(value: Duration): string { | ||
| return `${value.amount} ${value.unit}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting that this doesn't scale to international durations yet (although the same problem exists for other compound types). We would need to make the template engine aware of Concerto vocabularies to solve this problem.
Similarly, the ordering is not consistent across locales.
| Language | Format Style | Example (2 Days) | Note |
|---|---|---|---|
| English | Number + Unit | 2 days | Pluralizes unit |
| French | Number + Unit | 2 jours | Space is mandatory |
| Hungarian | Number + Unit | 2 nap | Unit is always singular |
| Arabic | Dual Form | يومان | The number 2 is often built into the word |
| Chinese | Number + Counter | 2天 | No spaces between parts |
The following code snippet would help if we have the locale available in the template.
// Using Intl.RelativeTimeFormat (Standard in modern JS)
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
console.log(rtf.format(2, 'day')); // "in 2 days"
mttrbrts
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review Copilot suggestions
939d8df to
4ee2c10
Compare
|
@mttrbrts Thank you for the feedback! I've addressed all the review comments: Locale-Aware Duration FormattingImplemented
Copilot Suggestion #2 - Path ComparisonFixed the false positive issue by using segment-wise path comparison instead of string Copilot Suggestion #1 - Return StatementAfter reviewing this, the current code flow appears to be correct:
The return is already placed after both validations, so no change was needed. Please let me know if I'm missing something here. All 56 tests pass. Happy to make any further changes based on your feedback! |
4ee2c10 to
ca05096
Compare
|
Fixed the clone PR issue as discussed in meet. |
Signed-off-by: Shubh-Raj <shubhraj625@gmail.com>
- Changed parameter type from Duration to unknown - Added isDuration type guard for proper type narrowing - TypeScript signature now matches runtime validation behavior Signed-off-by: Shubh-Raj <shubhraj625@gmail.com>
5edc467 to
926a14e
Compare
Summary
Fixes: accordproject/template-playground#14
When Duration or Period types are used in TemplateMark templates, they were rendering as raw JSON instead of human-readable text.
Before
The penalty is {"$class":"
org.accordproject.time@0.3.0.Duration
","amount":2,"unit":"days"}.
After
The penalty is 2 days.
Changes
src/drafting/Duration/index.ts- formats Duration/Period as "{amount} {unit}"src/drafting/index.ts(3 lines)test/DurationDrafter.test.tsTesting
All 53 tests pass.