Skip to content

Conversation

@Shubh-Raj
Copy link

@Shubh-Raj Shubh-Raj commented Jan 1, 2026

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

  • Added src/drafting/Duration/index.ts - formats Duration/Period as "{amount} {unit}"
  • Registered drafters in src/drafting/index.ts (3 lines)
  • Added unit tests in test/DurationDrafter.test.ts

Testing

All 53 tests pass.

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>
Copy link

Copilot AI left a 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.

Comment on lines 579 to 583
}
catch (err) {
throw new Error(`Generated invalid agreement: ${err}: ${JSON.stringify(templateMark, null, 2)}`);
}

// Check for unguarded optional property access
Copy link

Copilot AI Jan 6, 2026

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).

Copilot uses AI. Check for mistakes.
* @returns {string} the text (e.g., "2 days")
*/
export default function durationDrafter(value: Duration): string {
return `${value.amount} ${value.unit}`;
Copy link
Member

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"

Copy link
Member

@mttrbrts mttrbrts left a 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

@Shubh-Raj Shubh-Raj force-pushed the shubh-raj/fix/complex-type-formatting branch from 939d8df to 4ee2c10 Compare January 6, 2026 19:32
@Shubh-Raj
Copy link
Author

@mttrbrts Thank you for the feedback! I've addressed all the review comments:

Locale-Aware Duration Formatting

Implemented Intl.NumberFormat with style: 'unit' as you suggested. This properly handles:

  • Locale-specific formatting (e.g., "2 days" → "2 jours" in French)
  • Correct pluralization ("1 day" vs "2 days")
  • Non-breaking spaces where required by locale conventions

Copilot Suggestion #2 - Path Comparison

Fixed the false positive issue by using segment-wise path comparison instead of string startsWith().

Copilot Suggestion #1 - Return Statement

After reviewing this, the current code flow appears to be correct:

  1. Serialization validation → throws on error
  2. Optional property validation → throws on error
  3. Return templateMark

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!

@Shubh-Raj Shubh-Raj force-pushed the shubh-raj/fix/complex-type-formatting branch from 4ee2c10 to ca05096 Compare January 7, 2026 19:44
@Shubh-Raj
Copy link
Author

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>
@Shubh-Raj Shubh-Raj force-pushed the shubh-raj/fix/complex-type-formatting branch from 5edc467 to 926a14e Compare January 8, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TemplateMark not rendering complex data types

2 participants