diff --git a/website/content/docs/language-guide/03-constraints.md b/website/content/docs/language-guide/03-constraints.md index 569dc47..0f0a6a5 100644 --- a/website/content/docs/language-guide/03-constraints.md +++ b/website/content/docs/language-guide/03-constraints.md @@ -107,16 +107,48 @@ isActive: boolean constrained { ## Array Constraints -Arrays can be constrained by length: +A constraint block written after `T[]` applies to **the array itself** — typically bounding the number of items: ```mlf tags: string[] constrained { minLength: 1, - maxLength: 10, + maxLength: 10, // at most 10 tags } images: Uri[] constrained { - maxLength: 4, + maxLength: 4, // at most 4 image URLs +} +``` + +### Constraining Array Items + +To constrain **each item** rather than the array, wrap the item type in parentheses and put the constraint block inside: + +```mlf +record post { + /// Each tag: at most 100 characters + tags: (string constrained { maxLength: 100 })[], +} +``` + +Without the parentheses, the constraint binds to the array, not the items. The two forms can also be combined when you need both levels: + +```mlf +record post { + /// At most 20 tags; each tag at most 50 chars + tags: (string constrained { maxLength: 50 })[] constrained { + maxLength: 20, + }, +} +``` + +For patterns you'll reuse, naming the constrained item type keeps the field declarations short — see [Custom Types](/docs/language-guide/custom-types/#array-items): + +```mlf +inline type Tag = string constrained { maxLength: 100 }; + +record post { + tags: Tag[], } ``` diff --git a/website/content/docs/language-guide/04-custom-types.md b/website/content/docs/language-guide/04-custom-types.md index 242643a..743f31c 100644 --- a/website/content/docs/language-guide/04-custom-types.md +++ b/website/content/docs/language-guide/04-custom-types.md @@ -71,6 +71,22 @@ record location { } ``` +### Array Items + +Inline types are the cleanest way to constrain the items of an array. Writing the constraint directly on `T[]` binds it to the array (see [Array Constraints](/docs/language-guide/constraints/#array-constraints)); defining an inline type for the item lets the field declaration stay short while each element is still validated: + +```mlf +inline type Tag = string constrained { maxLength: 100 }; +inline type PositiveInt = integer constrained { minimum: 0 }; + +record post { + tags!: Tag[], // each tag constrained to 100 chars + viewCounts!: PositiveInt[], // each integer must be ≥ 0 +} +``` + +This is equivalent to the parenthesized inline form `(string constrained { maxLength: 100 })[]` — pick whichever reads better at the call site. The inline-type form wins when the same shape appears in multiple fields. + ## Def Types When you want a type to be **shared and referenced by name** in the generated lexicon, use `def type`: