diff --git a/docs/README.md b/docs/README.md index 61d9c39..6d600a4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,5 +22,6 @@ in the future, but also provides a place for less general, yet useful utilities. * [inspect](inspect.md) * [jsonpath](jsonpath.md) * [number](number.md) +* [reflect](reflect.md) * [string](string.md) * [url](url.md) \ No newline at end of file diff --git a/docs/reflect.md b/docs/reflect.md new file mode 100644 index 0000000..6a176cc --- /dev/null +++ b/docs/reflect.md @@ -0,0 +1,25 @@ +--- +permalink: /reflect/ +--- + +# reflect + +```jsonnet +local reflect = import "github.com/jsonnet-libs/xtd/reflect.libsonnet" +``` + +`reflect` implements helper functions for processing json data. + +## Index + +* [`fn prune(a, recurse=true, only_null=false)`](#fn-prune) + +## Fields + +### fn prune + +```ts +prune(a, recurse=true, only_null=false) +``` + +`prune` works the same as `std.prune` but with the options to disable recursion and only pruning `null` values. \ No newline at end of file diff --git a/main.libsonnet b/main.libsonnet index 5bda297..0a39198 100644 --- a/main.libsonnet +++ b/main.libsonnet @@ -20,6 +20,7 @@ local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet'; inspect: (import './inspect.libsonnet'), jsonpath: (import './jsonpath.libsonnet'), number: (import './number.libsonnet'), + reflect: (import './reflect.libsonnet'), string: (import './string.libsonnet'), url: (import './url.libsonnet'), } diff --git a/reflect.libsonnet b/reflect.libsonnet new file mode 100644 index 0000000..e8a87f6 --- /dev/null +++ b/reflect.libsonnet @@ -0,0 +1,47 @@ +local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet'; + +{ + '#': d.pkg( + name='reflect', + url='github.com/jsonnet-libs/xtd/reflect.libsonnet', + help='`reflect` implements helper functions for processing json data.', + ), + + '#prune':: d.fn( + '`prune` works the same as `std.prune` but with the options to disable recursion and only pruning `null` values.', + [ + d.arg('a', d.T.any), + d.arg('recurse', d.T.bool, default=true), + d.arg('only_null', d.T.bool, default=false), + ] + ), + prune(a, recurse=true, only_null=false):: + local isContent(b) = + if b == null + then false + else if only_null + then true + else if std.isArray(b) + then std.length(b) > 0 + else if std.isObject(b) + then std.length(b) > 0 + else true; + local doRecursion(x) = + if recurse + then self.prune(x, only_null=only_null) + else x; + if std.isArray(a) + then [ + doRecursion(x) + for x in a + if isContent(doRecursion(x)) + ] + else if std.isObject(a) + then { + [x]: doRecursion(a[x]) + for x in std.objectFields(a) + if isContent(doRecursion(a[x])) + } + else + a, +} diff --git a/test/reflect_test.jsonnet b/test/reflect_test.jsonnet new file mode 100644 index 0000000..d59630d --- /dev/null +++ b/test/reflect_test.jsonnet @@ -0,0 +1,42 @@ +local reflect = import '../reflect.libsonnet'; +local test = import 'github.com/jsonnet-libs/testonnet/main.libsonnet'; + +local obj = { + a: {}, + b: null, + c: { + d: {}, + e: null, + }, +}; + +test.new(std.thisFile) + ++ test.case.new( + name='prune: vanilla', + test=test.expect.eq( + actual=reflect.prune(obj), // true/false + expected={}, + ) +) ++ test.case.new( + name='prune: no recurse', + test=test.expect.eq( + actual=reflect.prune(obj, recurse=false), // false/false + expected={ c: { d: {}, e: null } }, + ) +) ++ test.case.new( + name='prune: only null', + test=test.expect.eq( + actual=reflect.prune(obj, only_null=true), // true/true + expected={ a: {}, c: { d: {} } }, + ) +) ++ test.case.new( + name='prune: no recurse && only null', + test=test.expect.eq( + actual=reflect.prune(obj, recurse=false, only_null=true), // false/true + expected={ a: {}, c: { d: {}, e: null } }, + ) +)