@@ -18,6 +18,7 @@ import (
1818 "fmt"
1919 "math"
2020
21+ "github.com/google/cel-go/common"
2122 "github.com/google/cel-go/common/ast"
2223 "github.com/google/cel-go/common/decls"
2324 "github.com/google/cel-go/common/env"
@@ -421,16 +422,29 @@ func (lib *optionalLib) CompileOptions() []EnvOption {
421422 Types (types .OptionalType ),
422423
423424 // Configure the optMap and optFlatMap macros.
424- Macros (ReceiverMacro (optMapMacro , 2 , optMap )),
425+ Macros (ReceiverMacro (optMapMacro , 2 , optMap ,
426+ MacroDocs (`perform computation on the value if present and return the result as an optional` ),
427+ MacroExamples (
428+ common .MultilineDescription (
429+ `// sub with the prefix 'dev.cel' or optional.none()` ,
430+ `request.auth.tokens.?sub.optMap(id, 'dev.cel.' + id)` ),
431+ `optional.none().optMap(i, i * 2) // optional.none()` ))),
425432
426433 // Global and member functions for working with optional values.
427434 Function (optionalOfFunc ,
435+ FunctionDocs (`create a new optional_type(T) with a value where any value is considered valid` ),
428436 Overload ("optional_of" , []* Type {paramTypeV }, optionalTypeV ,
437+ OverloadExamples (`optional.of(1) // optional(1)` ),
429438 UnaryBinding (func (value ref.Val ) ref.Val {
430439 return types .OptionalOf (value )
431440 }))),
432441 Function (optionalOfNonZeroValueFunc ,
442+ FunctionDocs (`create a new optional_type(T) with a value, if the value is not a zero or empty value` ),
433443 Overload ("optional_ofNonZeroValue" , []* Type {paramTypeV }, optionalTypeV ,
444+ OverloadExamples (
445+ `optional.ofNonZeroValue(null) // optional.none()` ,
446+ `optional.ofNonZeroValue("") // optional.none()` ,
447+ `optional.ofNonZeroValue("hello") // optional.of('hello')` ),
434448 UnaryBinding (func (value ref.Val ) ref.Val {
435449 v , isZeroer := value .(traits.Zeroer )
436450 if ! isZeroer || ! v .IsZeroValue () {
@@ -439,18 +453,26 @@ func (lib *optionalLib) CompileOptions() []EnvOption {
439453 return types .OptionalNone
440454 }))),
441455 Function (optionalNoneFunc ,
456+ FunctionDocs (`singleton value representing an optional without a value` ),
442457 Overload ("optional_none" , []* Type {}, optionalTypeV ,
458+ OverloadExamples (`optional.none()` ),
443459 FunctionBinding (func (values ... ref.Val ) ref.Val {
444460 return types .OptionalNone
445461 }))),
446462 Function (valueFunc ,
463+ FunctionDocs (`obtain the value contained by the optional, error if optional.none()` ),
447464 MemberOverload ("optional_value" , []* Type {optionalTypeV }, paramTypeV ,
465+ OverloadExamples (
466+ `optional.of(1).value() // 1` ,
467+ `optional.none().value() // error` ),
448468 UnaryBinding (func (value ref.Val ) ref.Val {
449469 opt := value .(* types.Optional )
450470 return opt .GetValue ()
451471 }))),
452472 Function (hasValueFunc ,
473+ FunctionDocs (`determine whether the optional contains a value` ),
453474 MemberOverload ("optional_hasValue" , []* Type {optionalTypeV }, BoolType ,
475+ OverloadExamples (`optional.of({1: 2}).hasValue() // true` ),
454476 UnaryBinding (func (value ref.Val ) ref.Val {
455477 opt := value .(* types.Optional )
456478 return types .Bool (opt .HasValue ())
@@ -459,21 +481,43 @@ func (lib *optionalLib) CompileOptions() []EnvOption {
459481 // Implementation of 'or' and 'orValue' are special-cased to support short-circuiting in the
460482 // evaluation chain.
461483 Function ("or" ,
462- MemberOverload ("optional_or_optional" , []* Type {optionalTypeV , optionalTypeV }, optionalTypeV )),
484+ FunctionDocs (`chain optional expressions together, picking the first valued optional expression` ),
485+ MemberOverload ("optional_or_optional" , []* Type {optionalTypeV , optionalTypeV }, optionalTypeV ,
486+ OverloadExamples (
487+ `optional.none().or(optional.of(1)) // optional.of(1)` ,
488+ common .MultilineDescription (
489+ `// either a value from the first list, a value from the second, or optional.none()` ,
490+ `[1, 2, 3][?x].or([3, 4, 5][?y])` )))),
463491 Function ("orValue" ,
464- MemberOverload ("optional_orValue_value" , []* Type {optionalTypeV , paramTypeV }, paramTypeV )),
492+ FunctionDocs (`chain optional expressions together picking the first valued optional or the default value` ),
493+ MemberOverload ("optional_orValue_value" , []* Type {optionalTypeV , paramTypeV }, paramTypeV ,
494+ OverloadExamples (
495+ common .MultilineDescription (
496+ `// pick the value for the given key if the key exists, otherwise return 'you'` ,
497+ `{'hello': 'world', 'goodbye': 'cruel world'}[?greeting].orValue('you')` )))),
465498
466499 // OptSelect is handled specially by the type-checker, so the receiver's field type is used to determine the
467500 // optput type.
468501 Function (operators .OptSelect ,
469- Overload ("select_optional_field" , []* Type {DynType , StringType }, optionalTypeV )),
502+ FunctionDocs (`if the field is present create an optional of the field value, otherwise return optional.none()` ),
503+ Overload ("select_optional_field" , []* Type {DynType , StringType }, optionalTypeV ,
504+ OverloadExamples (
505+ `msg.?field // optional.of(field) if non-empty, otherwise optional.none()` ,
506+ `msg.?field.?nested_field // optional.of(nested_field) if both field and nested_field are non-empty.` ))),
470507
471508 // OptIndex is handled mostly like any other indexing operation on a list or map, so the type-checker can use
472509 // these signatures to determine type-agreement without any special handling.
473510 Function (operators .OptIndex ,
474- Overload ("list_optindex_optional_int" , []* Type {listTypeV , IntType }, optionalTypeV ),
511+ FunctionDocs (`if the index is present create an optional of the field value, otherwise return optional.none()` ),
512+ Overload ("list_optindex_optional_int" , []* Type {listTypeV , IntType }, optionalTypeV ,
513+ OverloadExamples (`[1, 2, 3][?x] // element value if x is in the list size, else optional.none()` )),
475514 Overload ("optional_list_optindex_optional_int" , []* Type {OptionalType (listTypeV ), IntType }, optionalTypeV ),
476- Overload ("map_optindex_optional_value" , []* Type {mapTypeKV , paramTypeK }, optionalTypeV ),
515+ Overload ("map_optindex_optional_value" , []* Type {mapTypeKV , paramTypeK }, optionalTypeV ,
516+ OverloadExamples (
517+ `map_value[?key] // value at the key if present, else optional.none()` ,
518+ common .MultilineDescription (
519+ `// map key-value if index is a valid map key, else optional.none()` ,
520+ `{0: 2, 2: 4, 6: 8}[?index]` ))),
477521 Overload ("optional_map_optindex_optional_value" , []* Type {OptionalType (mapTypeKV ), paramTypeK }, optionalTypeV )),
478522
479523 // Index overloads to accommodate using an optional value as the operand.
@@ -482,45 +526,62 @@ func (lib *optionalLib) CompileOptions() []EnvOption {
482526 Overload ("optional_map_index_value" , []* Type {OptionalType (mapTypeKV ), paramTypeK }, optionalTypeV )),
483527 }
484528 if lib .version >= 1 {
485- opts = append (opts , Macros (ReceiverMacro (optFlatMapMacro , 2 , optFlatMap )))
529+ opts = append (opts , Macros (ReceiverMacro (optFlatMapMacro , 2 , optFlatMap ,
530+ MacroDocs (`perform computation on the value if present and produce an optional value within the computation` ),
531+ MacroExamples (
532+ common .MultilineDescription (
533+ `// m = {'key': {}}` ,
534+ `m.?key.optFlatMap(k, k.?subkey) // optional.none()` ),
535+ common .MultilineDescription (
536+ `// m = {'key': {'subkey': 'value'}}` ,
537+ `m.?key.optFlatMap(k, k.?subkey) // optional.of('value')` ),
538+ ))))
486539 }
487540
488541 if lib .version >= 2 {
489542 opts = append (opts , Function ("last" ,
543+ FunctionDocs (`return the last value in a list if present, otherwise optional.none()` ),
490544 MemberOverload ("list_last" , []* Type {listTypeV }, optionalTypeV ,
545+ OverloadExamples (
546+ `[].last() // optional.none()` ,
547+ `[1, 2, 3].last() ? optional.of(3)` ),
491548 UnaryBinding (func (v ref.Val ) ref.Val {
492549 list := v .(traits.Lister )
493- sz := list .Size ().Value ().(int64 )
494-
495- if sz == 0 {
550+ sz := list .Size ().(types.Int )
551+ if sz == types .IntZero {
496552 return types .OptionalNone
497553 }
498-
499554 return types .OptionalOf (list .Get (types .Int (sz - 1 )))
500555 }),
501556 ),
502557 ))
503558
504559 opts = append (opts , Function ("first" ,
560+ FunctionDocs (`return the first value in a list if present, otherwise optional.none()` ),
505561 MemberOverload ("list_first" , []* Type {listTypeV }, optionalTypeV ,
562+ OverloadExamples (
563+ `[].first() // optional.none()` ,
564+ `[1, 2, 3].first() ? optional.of(1)` ),
506565 UnaryBinding (func (v ref.Val ) ref.Val {
507566 list := v .(traits.Lister )
508- sz := list .Size ().Value ().(int64 )
509-
510- if sz == 0 {
567+ sz := list .Size ().(types.Int )
568+ if sz == types .IntZero {
511569 return types .OptionalNone
512570 }
513-
514571 return types .OptionalOf (list .Get (types .Int (0 )))
515572 }),
516573 ),
517574 ))
518575
519576 opts = append (opts , Function (optionalUnwrapFunc ,
577+ FunctionDocs (`convert a list of optional values to a list containing only value which are not optional.none()` ),
520578 Overload ("optional_unwrap" , []* Type {listOptionalTypeV }, listTypeV ,
579+ OverloadExamples (`optional.unwrap([optional.of(1), optional.none()]) // [1]` ),
521580 UnaryBinding (optUnwrap ))))
522581 opts = append (opts , Function (unwrapOptFunc ,
582+ FunctionDocs (`convert a list of optional values to a list containing only value which are not optional.none()` ),
523583 MemberOverload ("optional_unwrapOpt" , []* Type {listOptionalTypeV }, listTypeV ,
584+ OverloadExamples (`[optional.of(1), optional.none()].unwrapOpt() // [1]` ),
524585 UnaryBinding (optUnwrap ))))
525586 }
526587
0 commit comments