Skip to content

Commit d302c4e

Browse files
LaunchDarklyReleaseBoteli-darklyLaunchDarklyCIbwoskow-ldSam Stokes
authored
prepare 3.0.0 release (#23)
* update release config * update release config * fix package references * add ldlog package to go-sdk-common * lint * drop Go 1.8-1.11 and update linter * gitignore * lint * add ldtime package for time helpers * add Go 1.14 in CI * desupport Go 1.12 * makefile improvement * make repo a module * don't install dep * yaml fix * update golangci-lint + misc code cleanup * add methods for detecting current log level * enforce consistent import groups * enable stylecheck, fix comment * add prerelease readme note * improve test coverage and enforce coverage goals (#18) * update readme note about import path, add godoc badge * better badge * omit unset properties in user JSON instead of serializing null value * don't allocate extra objects when setting user builder properties * add generic user attr setter and more Value helper methods * add benchmarks and enforce zero-allocation goals * implement streaming JSON serialization (#23) * fix bug in JSONBuffer state when writing zeroes * fix note about import path * go mod tidy * fix JSONBuffer string escaping, + slight refactor * remove accidental inclusions from another branch * lint * remove inapplicable comments * add ability to send buffered JSON output to another writer * add log test helper package * add UnmarshalText and other helper methods to OptionalString * use go-test-helpers v2 (removes unwanted eventsource dependency) (#28) * user unmarshaling should fail if key is missing (#30) * add OptionalInt type * test coverage * keep method signature of NewEvaluationDetail the same as it used to be * comment * add OptionalBool type and use it for User.Anonymous (#32) * add OptionalBool type and use it for User.Anonymous * comment * add ldlogtest helper for dumping captured log output * add Go 1.15 build and remove beta changelog * update Go version in readme * rm prerelease note * better error reporting when unmarshaling User, OptionalString, etc. (#35) * add IsDefined() methods to optional-like types * better copy-on-write behavior for maps/slices; expose map & array types * use new go-jsonstream API (#38) * change go-jsonstream import path back to gopkg.in since the repo is public now * add conditionally-compiled EasyJSON methods * update for go-jsonstream API changes * build in Windows with Go 1.14 * update CircleCI Windows image * treat null as equivalent to empty array for privateAttributeNames in user JSON * EasyJSON optimizations for ldvalue and lduser types (#43) * EasyJSON optimizations for ldvalue and lduser types * revert unnecessary changes to non-easyjson implementation * fix test (detection of trailing comma is not a well-defined use case) * require a JSON object (not null) when parsing a User * Removed the guides link * Add inExperiment attribute to FALLTHROUGH and RULE_MATCH reasons (#45) This adds an attribute inExperiment to reasons of kinds FALLTHROUGH and RULE_MATCH, as specified in the Experiment Traffic Allocation spec. This attribute is intended to indicate whether the user was targeted by an experiment rollout, and if so, whether they were allocated to one of the experiment variations. We currently plan to use this for two things: * to allow event consumers (currently, the experimentation pipeline and Data Export customers) to filter feature events to only those from users who are part of an experiment. * to allow some SDKs, which use reasons to determine whether to send full events, to avoid sending feature events in the first place after evaluating experiment rollouts for users who are not part of the experiment. (It might seem like this makes the filtering requirement redundant, since there's no need to filter out events that the SDKs declined to send in the first place, but for Data Export customers we want to send all of the events but still filter them for experiment analysis.) * Enable tests when releasing (#46) * Enable tests when releasing (#46) * add unbounded segments status to evaluation reasons (#44) * "big" is the new "unbounded" (#47) * update go-jsonstream version for ch110425 bugfix * update to newer Releaser config format, add Go 1.16 CI (#50) * update to newer Releaser config format, add Go 1.16 CI * run code coverage job in Go 1.15 * Updates docs URLs * add CI job for Go 1.17; update linter & test coverage script * remove deprecated old copy of jsonstream package * remove references to now-removed package * rm tests for obsolete package * (#1) basic context model/builders/constructors, not including private attrs (#55) * (#2) implement attribute reference parsing and lookup (#56) * (#4) add private attributes to context model (#61) * (#5) add JSON serialization and deserialization, including from old user format (#62) * (#6) reimplement UserBuilder to build Context (#64) * implementation of context serialization/redaction in events (to be moved to go-sdk-events) (#63) * add comparative benchmarks for v2 (#66) * add comparative benchmarks for v2 * DRY * add ldcontext benchmarks + alternate marshal/unmarshal methods (#65) * update major version and Go version * optimizations for context unmarshaling, especially with EasyJSON (#67) * move "transient" to top level, clarify distinction between attributes & meta * fix import path * change JSON prop name of "privateAttributeNames" to "privateAttributes" * fix import path * fix mistake in old user schema * add option to deserialize in event format; move special JSON APIs into their own type * revise implementation of previously-redacted attr list to be separate from private attrs * miscellaneous API & test coverage improvements * remove tempevents code * change ldcontext.AttrRef to ldattr.Ref * misc doc fixes * import ordering * rm unused * remove support for unmarshaling in "event output format" (#74) * stop using gopkg.in in import paths (#75) * stop using gopkg.in in import paths * update go-jsonstream import * miscellaneous ldvalue/ldcontext API improvements * add ldattr.Ref.Equal * don't allow marshaling of uninitialized Context * disallow empty string for kind in JSON * "multi-kind" context with 1 kind should become single-kind * comment * rename NewNameRef to NewLiteralRef * disallow use of escape character other than ~0 or ~1 * add marshaling/unmarshaling for "event context" * fix EasyJSON parser that failed to consume a closing curly brace; improve tests * ensure privateAttrs list is zeroed out initially; add "unmarshal twice" test * better accessor methods for individual contexts + IsDefined * further simplify: don't need 2nd return value now that we have IsDefined * transparently convert empty raw JSON value to null * fix linter in build * lint * rename "transient" back to "anonymous" * treat null as equivalent to {} when unmarshaling sub-objects from user/context JSON * export types for specific validation errors * clarify rules about custom attributes with same names as meta things * use percent-encoding for specific characters in fully-qualified key, not url.PathEscape * flatten nested multi-kind contexts when building a multi-kind context * doc comments * require Go 1.18 or higher; use generics * fix release configuration * use go-test-helpers 3.x * rm obsolete linter * update go-jsonstream dependency * attribute ref components are always properties, not array indices * indents * disallow setting "secondary" in contexts (but still support it internally for old user JSON) * add ldvalue.FromJSONMarshal, improve behavior of complex types & raw type * reduce boilerplate code in ldvalue using generics * consistent support for MarshalText/UnmarshalText * add another test case * big copyedit of doc comments + Go 1.19 formatting * don't add any methods in this PR * add Context.JSONString() * add Context.JSONString * lint: consistent receiver names * typo * fix comment * Remove quadratic duplicate check in MultiBuilder's Build method MultiBuilder needs to check for duplicate context kinds when building a multi-context. The previous behavior was O(N^2), which can be improved to O(N) since the list of contexts is sorted by kind. * re-add lduser.User as an alias for ldcontext.Context * disallow empty attribute name * misc doc comment formatting fixes (#98) * misc doc comment formatting fixes * indents * add online doc links * add readme note Co-authored-by: Eli Bishop <eli@launchdarkly.com> Co-authored-by: LaunchDarklyCI <dev@launchdarkly.com> Co-authored-by: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Co-authored-by: Sam Stokes <sstokes@launchdarkly.com> Co-authored-by: LaunchDarklyReleaseBot <launchdarklyreleasebot@launchdarkly.com> Co-authored-by: Ember Stevens <ember.stevens@launchdarkly.com> Co-authored-by: ember-stevens <79482775+ember-stevens@users.noreply.github.com> Co-authored-by: Casey Waldren <cwaldren@launchdarkly.com>
1 parent 5bfff39 commit d302c4e

40 files changed

+800
-608
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
This repository contains packages and types that are shared between the [LaunchDarkly Go SDK](https://github.com/launchdarkly/go-server-sdk) and other LaunchDarkly Go components.
88

9+
Version 3.x of `go-sdk-common` is used by version 6.x of the LaunchDarkly Go SDK. It is not usable with earlier SDK versions.
10+
911
Applications using the LaunchDarkly Go SDK will generally use the `ldcontext` subpackage, which contains the `Context` type, and may also use the `ldvalue` package, which contains the `Value` type that represents arbitrary JSON values. Other packages are less frequently used.
1012

1113
## Supported Go versions

ldattr/constants.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,21 @@ package ldattr
33
const (
44
// KeyAttr is a constant for the attribute name that corresponds to the Key() method in
55
// ldcontext.Context and ldcontext.Builder. This name is used in JSON representations and flag
6-
// rules, and can be passed to ldcontext.Context.GetValue() or ldcontext.Context.SetValue().
7-
// representations and flag rules.
6+
// rules, and can be passed to ldcontext.Context.GetValue or ldcontext.Builder.SetValue.
87
KeyAttr = "key"
98

109
// KindAttr is a constant for the attribute name that corresponds to the Kind() method in
1110
// ldcontext.Context and ldcontext.Builder. This name is used in JSON representations and flag
12-
// rules, and can be passed to ldcontext.Context.GetValue() or ldcontext.Context.SetValue().
13-
// representations and flag rules.
11+
// rules, and can be passed to ldcontext.Context.GetValue or ldcontext.Builder.SetValue.
1412
KindAttr = "kind"
1513

1614
// NameAttr is a constant for the attribute name that corresponds to the Name() method in
1715
// ldcontext.Context and ldcontext.Builder. This name is used in JSON representations and flag
18-
// rules, and can be passed to ldcontext.Context.GetValue() or ldcontext.Context.SetValue().
19-
// representations and flag rules.
16+
// rules, and can be passed to ldcontext.Context.GetValue or ldcontext.Builder.SetValue.
2017
NameAttr = "name"
2118

2219
// AnonymousAttr is a constant for the attribute name that corresponds to the Anonymous() method
23-
// in ldcontext.Context and ldcontext.Builder. This name is used in JSON representations and flag
24-
// rules, and can be passed to ldcontext.Context.GetValue() or ldcontext.Context.SetValue().
25-
// representations and flag rules.
20+
// ldcontext.Context and ldcontext.Builder. This name is used in JSON representations and flag
21+
// rules, and can be passed to ldcontext.Context.GetValue or ldcontext.Builder.SetValue.
2622
AnonymousAttr = "anonymous"
2723
)

ldattr/package.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// Package ldattr defines the model for context attribute references used by the LaunchDarkly SDK.
22
//
3-
// This includes the ldattr.Ref type, which provides a syntax similar to JSON Pointer for
3+
// This includes the [Ref] type, which provides a syntax similar to JSON Pointer for
44
// referencing values either of a top-level context attribute, or of a value within a JSON object
55
// or JSON array. It also includes constants for the names of some built-in attributes.
66
//
77
// These types and constants are mainly intended to be used internally by LaunchDarkly SDK and
8-
// service code. Applications are unlikely to need to use them directly.
8+
// service code. Applications are unlikely to need to use them directly; context attributes are
9+
// normally set via methods in [github.com/launchdarkly/go-sdk-common/v3/ldcontext].
910
package ldattr

ldattr/ref.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import (
1515
// efficiency is a major concern so it's desirable to do any parsing or preprocessing just once.
1616
// Applications are unlikely to need to use the Ref type directly.
1717
//
18-
// It can be used to retrieve a value with Context.GetValueForRef(), or to identify an attribute or
19-
// nested value that should be considered private with Builder.Private() (the SDK configuration can also
20-
// have a list of private attribute references).
18+
// It can be used to retrieve a value with Context.GetValueForRef, or to identify an attribute or
19+
// nested value that should be considered private with Builder.PrivateRef (the SDK configuration
20+
// can also have a list of private attribute references).
2121
//
22-
// Parsing and validation are done at the time that the NewRef or NewLiteralRef constructor is called.
22+
// Parsing and validation are done at the time that the [NewRef] or [NewLiteralRef] constructor is called.
2323
// If a Ref instance was created from an invalid string, or if it is an uninitialized Ref{}, it is
24-
// considered invalid and its Err() method will return a non-nil error.
24+
// considered invalid and its [Ref.Err] method will return a non-nil error.
2525
//
2626
// # Syntax
2727
//
@@ -66,11 +66,11 @@ type Ref struct {
6666
components []string
6767
}
6868

69-
// NewRef creates a Ref from a string. For the supported syntax and examples, see comments on the Ref type.
69+
// NewRef creates a Ref from a string. For the supported syntax and examples, see [Ref].
7070
//
7171
// This constructor always returns a Ref that preserves the original string, even if validation fails,
72-
// so that calling String() (or serializing the Ref to JSON) will produce the original string. If
73-
// validation fails, Err() will return a non-nil error and any SDK method that takes this Ref as a
72+
// so that calling [Ref.String] (or serializing the Ref to JSON) will produce the original string. If
73+
// validation fails, [Ref.Err] will return a non-nil error and any SDK method that takes this Ref as a
7474
// parameter will consider it invalid.
7575
func NewRef(referenceString string) Ref {
7676
if referenceString == "" || referenceString == "/" {
@@ -105,7 +105,7 @@ func NewRef(referenceString string) Ref {
105105
return ret
106106
}
107107

108-
// NewLiteralRef is similar to NewRef except that it always interprets the string as a literal
108+
// NewLiteralRef is similar to [NewRef] except that it always interprets the string as a literal
109109
// attribute name, never as a slash-delimited path expression. There is no escaping or unescaping,
110110
// even if the name contains literal '/' or '~' characters. Since an attribute name can contain
111111
// any characters, this method always returns a valid Ref unless the name is empty.
@@ -129,15 +129,15 @@ func NewLiteralRef(attrName string) Ref {
129129
}
130130

131131
// IsDefined returns true if the Ref has a value, meaning that it is not an uninitialized Ref{}.
132-
// That does not guarantee that the value is valid; use Err() to test that.
132+
// That does not guarantee that the value is valid; use [Ref.Err] to test that.
133133
func (a Ref) IsDefined() bool {
134134
return a.rawPath != "" || a.err != nil
135135
}
136136

137137
// Equal returns true if the two Ref instances have the same value.
138138
//
139139
// You cannot compare Ref instances with the == operator, because the struct may contain a slice;
140-
// reflect.DeepEqual will work, but is less efficient.
140+
// [reflect.DeepEqual] will work, but is less efficient.
141141
func (a Ref) Equal(other Ref) bool {
142142
if a.err != other.err || a.rawPath != other.rawPath || a.singlePathComponent != other.singlePathComponent {
143143
return false
@@ -151,7 +151,7 @@ func (a Ref) Equal(other Ref) bool {
151151
//
152152
// A Ref is invalid if the input string is empty, or starts with a slash but is not a valid
153153
// slash-delimited path, or starts with a slash and contains an invalid escape sequence. For a list of
154-
// the possible validation errors, see the ErrAttribute___ types in the lderrors package.
154+
// the possible validation errors, see the [lderrors] package.
155155
//
156156
// Otherwise, the Ref is valid, but that does not guarantee that such an attribute exists in any
157157
// given Context. For instance, NewRef("name") is a valid Ref, but a specific Context might or might
@@ -204,15 +204,15 @@ func (a Ref) Component(index int) string {
204204
}
205205

206206
// String returns the attribute reference as a string, in the same format used by NewRef().
207-
// If the Ref was created with NewRef(), this value is identical to the original string. If it
208-
// was created with NewRefForName(), the value may be different due to unescaping (for instance,
207+
// If the Ref was created with [NewRef], this value is identical to the original string. If it
208+
// was created with [NewLiteralRef], the value may be different due to unescaping (for instance,
209209
// an attribute whose name is "/a" would be represented as "~1a".
210210
func (a Ref) String() string {
211211
return a.rawPath
212212
}
213213

214214
// MarshalJSON produces a JSON representation of the Ref. If it is an uninitialized Ref{}, this
215-
// is a JSON null token. Otherwise, it is a JSON string using the same value returned by String().
215+
// is a JSON null token. Otherwise, it is a JSON string using the same value returned by [Ref.String].
216216
func (a Ref) MarshalJSON() ([]byte, error) {
217217
if !a.IsDefined() {
218218
return []byte(`null`), nil
@@ -221,12 +221,12 @@ func (a Ref) MarshalJSON() ([]byte, error) {
221221
}
222222

223223
// UnmarshalJSON parses a Ref from a JSON value. If the value is null, the result is an
224-
// uninitialized Ref(). If the value is a string, it is passed to NewRef(). Any other type
224+
// uninitialized Ref(). If the value is a string, it is passed to [NewRef]. Any other type
225225
// causes an error.
226226
//
227227
// A valid JSON string that is not valid as a Ref path (such as "" or "///") does not cause
228228
// UnmarshalJSON to return an error; instead, it stores the string in the Ref and the error
229-
// can be obtained from Ref.Err(). This is deliberate, so that the LaunchDarkly SDK will be
229+
// can be obtained from [Ref.Err]. This is deliberate, so that the LaunchDarkly SDK will be
230230
// able to parse a set of feature flag data even if one of the flags contains an invalid Ref.
231231
func (a *Ref) UnmarshalJSON(data []byte) error {
232232
r := jreader.NewReader(data)
@@ -244,9 +244,9 @@ func (a *Ref) UnmarshalJSON(data []byte) error {
244244

245245
// Performs unescaping of attribute reference path components:
246246
//
247-
// "~1" becomes "/"
248-
// "~0" becomes "~"
249-
// "~" followed by any character other than "0" or "1" is invalid
247+
// - "~1" becomes "/"
248+
// - "~0" becomes "~"
249+
// - "~" followed by any character other than "0" or "1" is invalid
250250
//
251251
// The second return value is true if successful, or false if there was an invalid escape sequence.
252252
func unescapePath(path string) (string, bool) {

ldcontext/builder_multi.go

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,48 +10,50 @@ import (
1010

1111
const defaultMultiBuilderCapacity = 3 // arbitrary value based on presumed likely use cases
1212

13-
// MultiBuilder is a mutable object that uses the builder pattern to specify properties for a Context.
13+
// MultiBuilder is a mutable object that uses the builder pattern to create a multi-context,
14+
// as an alternative to [NewMulti].
1415
//
1516
// Use this type if you need to construct a Context that has multiple Kind values, each with its
16-
// own nested Context. To define a single-kind context, use Builder instead.
17+
// own nested [Context]. To define a single context, use [Builder] instead.
1718
//
18-
// Obtain an instance of MultiBuilder by calling NewMultiBuilder; then, call Add to specify the
19-
// nested Context for each Kind. MultiBuilder setters return a reference the same builder, so they
20-
// can be chained together:
19+
// Obtain an instance of MultiBuilder by calling [NewMultiBuilder]; then, call [MultiBuilder.Add] to
20+
// specify the nested [Context] for each Kind. Finally, call [MultiBuilder.Build]. MultiBuilder
21+
// setters return a reference to the same builder, so they can be chained together:
2122
//
2223
// context := ldcontext.NewMultiBuilder().
23-
// Add(ldcontext.New("my-user-key")).
24-
// Add(ldcontext.NewBuilder("my-org-key").Kind("organization").Name("Org1").Build()).
25-
// Build()
24+
// Add(ldcontext.New("my-user-key")).
25+
// Add(ldcontext.NewBuilder("my-org-key").Kind("organization").Name("Org1").Build()).
26+
// Build()
2627
//
27-
// A MultiBuilder should not be accessed by multiple goroutines at once. Once you have called Build(),
28-
// the resulting Context is immutable and is safe to use from multiple goroutines. Instances
29-
// created with Build() are not affected by subsequent actions taken on the MultiBuilder.
28+
// A MultiBuilder should not be accessed by multiple goroutines at once. Once you have called
29+
// [MultiBuilder.Build], the resulting Context is immutable and safe to use from multiple
30+
// goroutines.
3031
type MultiBuilder struct {
3132
contexts []Context
3233
contextsCopyOnWrite bool
3334
}
3435

35-
// NewMultiBuilder creates a MultiBuilder for building a Context.
36+
// NewMultiBuilder creates a MultiBuilder for building a multi-context.
3637
//
37-
// This method is for building a Context athat has multiple Kind values, each with its own
38-
// nested Context. To define a single-kind context, use NewBuilder() instead.
38+
// This method is for building a [Context] that has multiple [Context.Kind] values, each with its
39+
// own nested Context. To define a single context, use [NewBuilder] instead.
3940
func NewMultiBuilder() *MultiBuilder {
4041
return &MultiBuilder{contexts: make([]Context, 0, defaultMultiBuilderCapacity)}
4142
}
4243

4344
// Build creates a Context from the current MultiBuilder properties.
4445
//
45-
// The Context is immutable and will not be affected by any subsequent actions on the MultiBuilder.
46+
// The [Context] is immutable and will not be affected by any subsequent actions on the MultiBuilder.
4647
//
4748
// It is possible for a MultiBuilder to represent an invalid state. Instead of returning two
4849
// values (Context, error), the Builder always returns a Context and you can call Context.Err()
49-
// to see if it has an error. See Context.Err() for more information about invalid Context
50+
// to see if it has an error. See [Context.Err] for more information about invalid Context
5051
// conditions. Using a single-return-value syntax is more convenient for application code, since
5152
// in normal usage an application will never build an invalid Context.
5253
//
53-
// If only one context kind was added to the builder, Build returns a single-kind context rather
54-
// than a multi-kind context.
54+
// If only one context was added to the builder, Build returns that same context, rather than a
55+
// multi-context-- since there is no logical difference in LaunchDarkly between a single context and
56+
// a multi-context that only contains one context.
5557
func (m *MultiBuilder) Build() Context {
5658
if len(m.contexts) == 0 {
5759
return Context{defined: true, err: lderrors.ErrContextKindMultiWithNoKinds{}}
@@ -68,7 +70,7 @@ func (m *MultiBuilder) Build() Context {
6870
// compute a fully qualified key.
6971
sort.Slice(m.contexts, func(i, j int) bool { return m.contexts[i].Kind() < m.contexts[j].Kind() })
7072

71-
// Check for conditions that could make a multi-kind context invalid
73+
// Check for conditions that could make a multi-context invalid
7274
var individualErrors map[string]error
7375
duplicates := false
7476
for i, c := range m.contexts {
@@ -106,7 +108,7 @@ func (m *MultiBuilder) Build() Context {
106108
multiContexts: m.contexts,
107109
}
108110

109-
// Fully-qualified key for multi-kind is defined as "kind1:key1:kind2:key2" etc., where kinds are in
111+
// Fully-qualified key for multi-context is defined as "kind1:key1:kind2:key2" etc., where kinds are in
110112
// alphabetical order (we have already sorted them above) and keys are URL-encoded. In this case we
111113
// do _not_ omit a default kind of "user".
112114
for _, c := range m.contexts {
@@ -121,29 +123,29 @@ func (m *MultiBuilder) Build() Context {
121123

122124
// TryBuild is an alternative to Build that returns any validation errors as a second value.
123125
//
124-
// As described in Build(), there are several ways the state of a Context could be invalid.
125-
// Since in normal usage it is possible to be confident that these will not occur, the Build()
126-
// method is designed for convenient use within expressions by returning a single Context
127-
// value, and any validation problems are contained within that value where they can be
128-
// detected by calling the context's Err() method. But, if you prefer to use the two-value
129-
// pattern that is common in Go, you can call TryBuild instead:
126+
// As described in [MultiBuilder.Build], there are several ways the state of a [Context] could
127+
// be invalid. Since in normal usage it is possible to be confident that these will not occur,
128+
// the Build method is designed for convenient use within expressions by returning a single
129+
// Context value, and any validation problems are contained within that value where they can be
130+
// detected by calling the context's [Context.Err] method. But, if you prefer to use the
131+
// two-value pattern that is common in Go, you can call TryBuild instead:
130132
//
131133
// c, err := ldcontext.NewMultiBuilder().
132-
// Add(context1).Add(context2).
133-
// TryBuild()
134+
// Add(context1).Add(context2).
135+
// TryBuild()
134136
// if err != nil {
135-
// // do whatever is appropriate if building the context failed
137+
// // do whatever is appropriate if building the context failed
136138
// }
137139
//
138140
// The two return values are the same as to 1. the Context that would be returned by Build(),
139-
// and 2. the result of calling Err() on that Context. So, the above example is exactly
141+
// and 2. the result of calling [Context.Err] on that Context. So, the above example is exactly
140142
// equivalent to:
141143
//
142144
// c := ldcontext.NewMultiBuilder().
143-
// Add(context1).Add(context2).
144-
// Build()
145+
// Add(context1).Add(context2).
146+
// Build()
145147
// if c.Err() != nil {
146-
// // do whatever is appropriate if building the context failed
148+
// // do whatever is appropriate if building the context failed
147149
// }
148150
//
149151
// Note that unlike some Go methods where the first return value is normally an
@@ -158,9 +160,9 @@ func (m *MultiBuilder) TryBuild() (Context, error) {
158160
// Add adds a nested context for a specific Kind to a MultiBuilder.
159161
//
160162
// It is invalid to add more than one context with the same Kind. This error is detected
161-
// when you call Build() or TryBuild().
163+
// when you call [MultiBuilder.Build] or [MultiBuilder.TryBuild].
162164
//
163-
// If the nested context is multi-kind, this is exactly equivalent to adding each of the
165+
// If the parameter is a multi-context, this is exactly equivalent to adding each of the
164166
// individual kinds from it separately. For instance, in the following example, "multi1" and
165167
// "multi2" end up being exactly the same:
166168
//

ldcontext/builder_multi_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestMultiBuilder(t *testing.T) {
3030
// other accessors are tested in context_test.go
3131
})
3232

33-
t.Run("nested multi-kind contexts are flattened", func(t *testing.T) {
33+
t.Run("nested multi-contexts are flattened", func(t *testing.T) {
3434
sub1 := NewWithKind("kind1", "key1")
3535
sub2 := NewWithKind("kind2", "key2")
3636
sub3 := NewWithKind("kind3", "key3")

0 commit comments

Comments
 (0)