2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Functions that generate widespread file
|
|
|
|
|
formats from nix data structures.
|
|
|
|
|
|
|
|
|
|
They all follow a similar interface:
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
generator { config-attrs } data
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`config-attrs` are “holes” in the generators
|
|
|
|
|
with sensible default implementations that
|
|
|
|
|
can be overwritten. The default implementations
|
|
|
|
|
are mostly generators themselves, called with
|
|
|
|
|
their respective default values; they can be reused.
|
|
|
|
|
|
|
|
|
|
Tests can be found in ./tests/misc.nix
|
|
|
|
|
|
|
|
|
|
Further Documentation can be found [here](#sec-generators).
|
|
|
|
|
*/
|
2017-07-29 00:05:35 +00:00
|
|
|
|
{ lib }:
|
2024-03-07 00:27:00 +00:00
|
|
|
|
|
2016-11-06 00:51:13 +00:00
|
|
|
|
let
|
2024-03-14 20:14:26 +00:00
|
|
|
|
inherit (lib)
|
2024-03-06 23:49:31 +00:00
|
|
|
|
addErrorContext
|
2024-03-14 20:14:26 +00:00
|
|
|
|
assertMsg
|
2024-03-06 23:49:31 +00:00
|
|
|
|
attrNames
|
2024-03-07 00:15:07 +00:00
|
|
|
|
concatLists
|
2024-03-14 20:14:26 +00:00
|
|
|
|
concatMapStringsSep
|
|
|
|
|
concatStrings
|
2024-03-06 23:49:31 +00:00
|
|
|
|
concatStringsSep
|
2024-03-14 20:14:26 +00:00
|
|
|
|
const
|
2024-03-06 23:49:31 +00:00
|
|
|
|
elem
|
2024-03-14 20:14:26 +00:00
|
|
|
|
escape
|
2024-03-06 23:49:31 +00:00
|
|
|
|
filter
|
2024-03-14 20:14:26 +00:00
|
|
|
|
flatten
|
|
|
|
|
foldl
|
|
|
|
|
functionArgs # Note: not the builtin; considers `__functor` in attrsets.
|
|
|
|
|
gvariant
|
|
|
|
|
hasInfix
|
2024-03-06 23:49:31 +00:00
|
|
|
|
head
|
2024-03-14 20:14:26 +00:00
|
|
|
|
id
|
|
|
|
|
init
|
2024-03-06 23:49:31 +00:00
|
|
|
|
isAttrs
|
2024-03-07 00:27:00 +00:00
|
|
|
|
isBool
|
2024-03-14 20:14:26 +00:00
|
|
|
|
isDerivation
|
2024-03-06 23:49:31 +00:00
|
|
|
|
isFloat
|
2024-03-14 20:14:26 +00:00
|
|
|
|
isFunction # Note: not the builtin; considers `__functor` in attrsets.
|
2024-03-06 23:49:31 +00:00
|
|
|
|
isInt
|
|
|
|
|
isList
|
|
|
|
|
isPath
|
|
|
|
|
isString
|
2024-03-14 20:14:26 +00:00
|
|
|
|
last
|
2024-03-06 23:49:31 +00:00
|
|
|
|
length
|
|
|
|
|
mapAttrs
|
2024-03-07 00:15:07 +00:00
|
|
|
|
mapAttrsToList
|
|
|
|
|
optionals
|
2024-03-14 20:14:26 +00:00
|
|
|
|
recursiveUpdate
|
|
|
|
|
replaceStrings
|
2024-03-07 00:15:07 +00:00
|
|
|
|
reverseList
|
2024-03-14 20:14:26 +00:00
|
|
|
|
splitString
|
|
|
|
|
tail
|
2024-03-07 00:15:07 +00:00
|
|
|
|
toList
|
|
|
|
|
;
|
|
|
|
|
|
2024-03-07 00:21:07 +00:00
|
|
|
|
inherit (lib.strings)
|
|
|
|
|
escapeNixIdentifier
|
|
|
|
|
floatToString
|
2024-03-14 20:14:26 +00:00
|
|
|
|
match
|
|
|
|
|
split
|
|
|
|
|
toJSON
|
|
|
|
|
typeOf
|
2024-03-06 23:49:31 +00:00
|
|
|
|
;
|
2016-11-06 00:51:13 +00:00
|
|
|
|
|
2018-03-26 15:28:17 +00:00
|
|
|
|
## -- HELPER FUNCTIONS & DEFAULTS --
|
2024-05-21 19:54:47 +00:00
|
|
|
|
in rec {
|
|
|
|
|
/**
|
|
|
|
|
Convert a value to a sensible default string representation.
|
|
|
|
|
The builtin `toString` function has some strange defaults,
|
|
|
|
|
suitable for bash scripts but not much else.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Options
|
|
|
|
|
: Empty set, there may be configuration options in the future
|
2018-03-26 15:28:17 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
`v`
|
|
|
|
|
: 2\. Function argument
|
|
|
|
|
*/
|
2024-03-06 23:49:31 +00:00
|
|
|
|
mkValueStringDefault = {}: v:
|
2018-03-26 15:31:05 +00:00
|
|
|
|
let err = t: v: abort
|
|
|
|
|
("generators.mkValueStringDefault: " +
|
|
|
|
|
"${t} not supported: ${toPretty {} v}");
|
|
|
|
|
in if isInt v then toString v
|
2021-09-12 04:23:30 +00:00
|
|
|
|
# convert derivations to store paths
|
2024-03-07 00:15:07 +00:00
|
|
|
|
else if isDerivation v then toString v
|
2018-03-26 15:31:05 +00:00
|
|
|
|
# we default to not quoting strings
|
|
|
|
|
else if isString v then v
|
|
|
|
|
# isString returns "1", which is not a good default
|
|
|
|
|
else if true == v then "true"
|
|
|
|
|
# here it returns to "", which is even less of a good default
|
|
|
|
|
else if false == v then "false"
|
|
|
|
|
else if null == v then "null"
|
|
|
|
|
# if you have lists you probably want to replace this
|
|
|
|
|
else if isList v then err "lists" v
|
|
|
|
|
# same as for lists, might want to replace
|
|
|
|
|
else if isAttrs v then err "attrsets" v
|
2020-01-23 00:07:02 +00:00
|
|
|
|
# functions can’t be printed of course
|
2018-03-26 15:31:05 +00:00
|
|
|
|
else if isFunction v then err "functions" v
|
2019-12-12 23:24:30 +00:00
|
|
|
|
# Floats currently can't be converted to precise strings,
|
|
|
|
|
# condition warning on nix version once this isn't a problem anymore
|
|
|
|
|
# See https://github.com/NixOS/nix/pull/3480
|
2024-03-07 00:21:07 +00:00
|
|
|
|
else if isFloat v then floatToString v
|
2018-03-26 15:31:05 +00:00
|
|
|
|
else err "this value is" (toString v);
|
|
|
|
|
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generate a line of key k and value v, separated by
|
|
|
|
|
character sep. If sep appears in k, it is escaped.
|
|
|
|
|
Helper for synaxes with different separators.
|
|
|
|
|
|
|
|
|
|
mkValueString specifies how values should be formatted.
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
mkKeyValueDefault {} ":" "f:oo" "bar"
|
|
|
|
|
> "f\:oo:bar"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
: mkValueString (optional, default: `mkValueStringDefault {}`)
|
|
|
|
|
: Function to convert values to strings
|
|
|
|
|
|
|
|
|
|
`sep`
|
|
|
|
|
|
|
|
|
|
: 2\. Function argument
|
|
|
|
|
|
|
|
|
|
`k`
|
|
|
|
|
|
|
|
|
|
: 3\. Function argument
|
|
|
|
|
|
|
|
|
|
`v`
|
|
|
|
|
|
|
|
|
|
: 4\. Function argument
|
|
|
|
|
*/
|
2017-11-09 14:58:14 +00:00
|
|
|
|
mkKeyValueDefault = {
|
2018-03-26 15:31:05 +00:00
|
|
|
|
mkValueString ? mkValueStringDefault {}
|
2017-11-09 14:58:14 +00:00
|
|
|
|
}: sep: k: v:
|
2024-03-07 00:21:07 +00:00
|
|
|
|
"${escape [sep] k}${sep}${mkValueString v}";
|
2016-12-04 21:11:24 +00:00
|
|
|
|
|
|
|
|
|
|
2018-03-26 15:28:17 +00:00
|
|
|
|
## -- FILE FORMAT GENERATORS --
|
|
|
|
|
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generate a key-value-style config file from an attrset.
|
2024-05-21 20:05:18 +00:00
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
|
|
|
|
|
: mkKeyValue (optional, default: `mkKeyValueDefault {} "="`)
|
|
|
|
|
: format a setting line from key and value
|
|
|
|
|
|
|
|
|
|
: listsAsDuplicateKeys (optional, default: `false`)
|
|
|
|
|
: allow lists as values for duplicate keys
|
|
|
|
|
|
|
|
|
|
: indent (optional, default: `""`)
|
|
|
|
|
: Initial indentation level
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
*/
|
2016-12-04 21:11:24 +00:00
|
|
|
|
toKeyValue = {
|
2020-03-10 01:38:28 +00:00
|
|
|
|
mkKeyValue ? mkKeyValueDefault {} "=",
|
2023-07-22 11:49:30 +00:00
|
|
|
|
listsAsDuplicateKeys ? false,
|
|
|
|
|
indent ? ""
|
2020-03-10 01:38:28 +00:00
|
|
|
|
}:
|
2023-07-22 11:49:30 +00:00
|
|
|
|
let mkLine = k: v: indent + mkKeyValue k v + "\n";
|
2020-03-10 01:38:28 +00:00
|
|
|
|
mkLines = if listsAsDuplicateKeys
|
2024-03-06 23:49:31 +00:00
|
|
|
|
then k: v: map (mkLine k) (if isList v then v else [v])
|
2020-03-10 01:38:28 +00:00
|
|
|
|
else k: v: [ (mkLine k v) ];
|
2024-03-07 00:22:49 +00:00
|
|
|
|
in attrs: concatStrings (concatLists (mapAttrsToList mkLines attrs));
|
2016-12-04 21:11:24 +00:00
|
|
|
|
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generate an INI-style config file from an
|
|
|
|
|
attrset of sections to an attrset of key-value pairs.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
|
|
|
|
|
: mkSectionName (optional, default: `(name: escape [ "[" "]" ] name)`)
|
|
|
|
|
: apply transformations (e.g. escapes) to section names
|
|
|
|
|
|
|
|
|
|
: mkKeyValue (optional, default: `{} "="`)
|
|
|
|
|
: format a setting line from key and value
|
|
|
|
|
|
|
|
|
|
: listsAsDuplicateKeys (optional, default: `false`)
|
|
|
|
|
: allow lists as values for duplicate keys
|
|
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
:::{.example}
|
|
|
|
|
## `lib.generators.toINI` usage example
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
generators.toINI {} {
|
|
|
|
|
foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
|
|
|
|
|
baz = { "also, integers" = 42; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
> [baz]
|
|
|
|
|
> also, integers=42
|
|
|
|
|
>
|
|
|
|
|
> [foo]
|
|
|
|
|
> ciao=bar
|
|
|
|
|
> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The mk* configuration attributes can generically change
|
|
|
|
|
the way sections and key-value strings are generated.
|
|
|
|
|
|
|
|
|
|
For more examples see the test cases in ./tests/misc.nix.
|
|
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
*/
|
2016-11-06 00:51:13 +00:00
|
|
|
|
toINI = {
|
2024-03-07 00:21:07 +00:00
|
|
|
|
mkSectionName ? (name: escape [ "[" "]" ] name),
|
2020-03-10 01:38:28 +00:00
|
|
|
|
mkKeyValue ? mkKeyValueDefault {} "=",
|
|
|
|
|
listsAsDuplicateKeys ? false
|
2016-11-06 00:51:13 +00:00
|
|
|
|
}: attrsOfAttrs:
|
|
|
|
|
let
|
|
|
|
|
# map function to string for each key val
|
|
|
|
|
mapAttrsToStringsSep = sep: mapFn: attrs:
|
2024-03-07 00:21:07 +00:00
|
|
|
|
concatStringsSep sep
|
2024-03-07 00:22:49 +00:00
|
|
|
|
(mapAttrsToList mapFn attrs);
|
2016-11-06 00:51:13 +00:00
|
|
|
|
mkSection = sectName: sectValues: ''
|
|
|
|
|
[${mkSectionName sectName}]
|
2020-03-10 01:38:28 +00:00
|
|
|
|
'' + toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } sectValues;
|
2016-11-06 00:51:13 +00:00
|
|
|
|
in
|
|
|
|
|
# map input to ini sections
|
|
|
|
|
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
|
2016-11-06 13:14:24 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generate an INI-style config file from an attrset
|
|
|
|
|
specifying the global section (no header), and an
|
|
|
|
|
attrset of sections to an attrset of key-value pairs.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
1\. Structured function argument
|
|
|
|
|
|
|
|
|
|
: mkSectionName (optional, default: `(name: escape [ "[" "]" ] name)`)
|
|
|
|
|
: apply transformations (e.g. escapes) to section names
|
|
|
|
|
|
|
|
|
|
: mkKeyValue (optional, default: `{} "="`)
|
|
|
|
|
: format a setting line from key and value
|
|
|
|
|
|
|
|
|
|
: listsAsDuplicateKeys (optional, default: `false`)
|
|
|
|
|
: allow lists as values for duplicate keys
|
|
|
|
|
|
|
|
|
|
2\. Structured function argument
|
|
|
|
|
|
|
|
|
|
: globalSection (required)
|
|
|
|
|
: global section key-value pairs
|
|
|
|
|
|
|
|
|
|
: sections (optional, default: `{}`)
|
|
|
|
|
: attrset of sections to key-value pairs
|
|
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
:::{.example}
|
|
|
|
|
## `lib.generators.toINIWithGlobalSection` usage example
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
generators.toINIWithGlobalSection {} {
|
|
|
|
|
globalSection = {
|
|
|
|
|
someGlobalKey = "hi";
|
|
|
|
|
};
|
|
|
|
|
sections = {
|
|
|
|
|
foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
|
|
|
|
|
baz = { "also, integers" = 42; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
> someGlobalKey=hi
|
|
|
|
|
>
|
|
|
|
|
> [baz]
|
|
|
|
|
> also, integers=42
|
|
|
|
|
>
|
|
|
|
|
> [foo]
|
|
|
|
|
> ciao=bar
|
|
|
|
|
> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The mk* configuration attributes can generically change
|
|
|
|
|
the way sections and key-value strings are generated.
|
|
|
|
|
|
|
|
|
|
For more examples see the test cases in ./tests/misc.nix.
|
|
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
If you don’t need a global section, you can also use
|
|
|
|
|
`generators.toINI` directly, which only takes
|
|
|
|
|
the part in `sections`.
|
|
|
|
|
*/
|
2022-03-14 09:14:18 +00:00
|
|
|
|
toINIWithGlobalSection = {
|
2024-03-07 00:21:07 +00:00
|
|
|
|
mkSectionName ? (name: escape [ "[" "]" ] name),
|
2022-03-14 09:14:18 +00:00
|
|
|
|
mkKeyValue ? mkKeyValueDefault {} "=",
|
|
|
|
|
listsAsDuplicateKeys ? false
|
2023-06-29 15:36:25 +00:00
|
|
|
|
}: { globalSection, sections ? {} }:
|
2022-03-14 09:14:18 +00:00
|
|
|
|
( if globalSection == {}
|
|
|
|
|
then ""
|
|
|
|
|
else (toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } globalSection)
|
|
|
|
|
+ "\n")
|
|
|
|
|
+ (toINI { inherit mkSectionName mkKeyValue listsAsDuplicateKeys; } sections);
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generate a git-config file from an attrset.
|
|
|
|
|
|
|
|
|
|
It has two major differences from the regular INI format:
|
|
|
|
|
|
|
|
|
|
1. values are indented with tabs
|
|
|
|
|
2. sections can have sub-sections
|
|
|
|
|
|
|
|
|
|
Further: https://git-scm.com/docs/git-config#EXAMPLES
|
|
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
:::{.example}
|
|
|
|
|
## `lib.generators.toGitINI` usage example
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
generators.toGitINI {
|
|
|
|
|
url."ssh://git@github.com/".insteadOf = "https://github.com";
|
|
|
|
|
user.name = "edolstra";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
> [url "ssh://git@github.com/"]
|
|
|
|
|
> insteadOf = "https://github.com"
|
|
|
|
|
>
|
|
|
|
|
> [user]
|
|
|
|
|
> name = "edolstra"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
`attrs`
|
|
|
|
|
|
|
|
|
|
: Key-value pairs to be converted to a git-config file.
|
|
|
|
|
See: https://git-scm.com/docs/git-config#_variables for possible values.
|
|
|
|
|
|
|
|
|
|
*/
|
2020-03-05 17:59:32 +00:00
|
|
|
|
toGitINI = attrs:
|
|
|
|
|
let
|
|
|
|
|
mkSectionName = name:
|
|
|
|
|
let
|
2024-03-07 00:21:07 +00:00
|
|
|
|
containsQuote = hasInfix ''"'' name;
|
|
|
|
|
sections = splitString "." name;
|
2020-03-05 17:59:32 +00:00
|
|
|
|
section = head sections;
|
|
|
|
|
subsections = tail sections;
|
|
|
|
|
subsection = concatStringsSep "." subsections;
|
|
|
|
|
in if containsQuote || subsections == [ ] then
|
|
|
|
|
name
|
|
|
|
|
else
|
|
|
|
|
''${section} "${subsection}"'';
|
|
|
|
|
|
2023-08-19 16:49:03 +00:00
|
|
|
|
mkValueString = v:
|
|
|
|
|
let
|
|
|
|
|
escapedV = ''
|
|
|
|
|
"${
|
|
|
|
|
replaceStrings [ "\n" " " ''"'' "\\" ] [ "\\n" "\\t" ''\"'' "\\\\" ] v
|
|
|
|
|
}"'';
|
|
|
|
|
in mkValueStringDefault { } (if isString v then escapedV else v);
|
|
|
|
|
|
2020-03-05 17:59:32 +00:00
|
|
|
|
# generation for multiple ini values
|
|
|
|
|
mkKeyValue = k: v:
|
2023-08-19 16:49:03 +00:00
|
|
|
|
let mkKeyValue = mkKeyValueDefault { inherit mkValueString; } " = " k;
|
2024-03-07 00:15:07 +00:00
|
|
|
|
in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (toList v));
|
2020-03-05 17:59:32 +00:00
|
|
|
|
|
|
|
|
|
# converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
|
|
|
|
|
gitFlattenAttrs = let
|
|
|
|
|
recurse = path: value:
|
2024-03-07 00:15:07 +00:00
|
|
|
|
if isAttrs value && !isDerivation value then
|
|
|
|
|
mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
|
2020-03-05 17:59:32 +00:00
|
|
|
|
else if length path > 1 then {
|
2024-03-07 00:15:07 +00:00
|
|
|
|
${concatStringsSep "." (reverseList (tail path))}.${head path} = value;
|
2020-03-05 17:59:32 +00:00
|
|
|
|
} else {
|
|
|
|
|
${head path} = value;
|
|
|
|
|
};
|
2024-03-07 00:15:07 +00:00
|
|
|
|
in attrs: foldl recursiveUpdate { } (flatten (recurse [ ] attrs));
|
2020-03-05 17:59:32 +00:00
|
|
|
|
|
|
|
|
|
toINI_ = toINI { inherit mkKeyValue mkSectionName; };
|
|
|
|
|
in
|
|
|
|
|
toINI_ (gitFlattenAttrs attrs);
|
2016-11-06 13:14:24 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
mkKeyValueDefault wrapper that handles dconf INI quirks.
|
|
|
|
|
The main differences of the format is that it requires strings to be quoted.
|
|
|
|
|
*/
|
2024-03-07 00:15:07 +00:00
|
|
|
|
mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (gvariant.mkValue v); } "=";
|
2023-08-15 09:58:02 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Generates INI in dconf keyfile style. See https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en
|
|
|
|
|
for details.
|
|
|
|
|
*/
|
2023-08-15 09:58:02 +00:00
|
|
|
|
toDconfINI = toINI { mkKeyValue = mkDconfKeyValue; };
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Recurses through a `Value` limited to a certain depth. (`depthLimit`)
|
|
|
|
|
|
|
|
|
|
If the depth is exceeded, an error is thrown, unless `throwOnDepthLimit` is set to `false`.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
|
|
|
|
|
: depthLimit (required)
|
|
|
|
|
: If this option is not null, the given value will stop evaluating at a certain depth
|
|
|
|
|
|
|
|
|
|
: throwOnDepthLimit (optional, default: `true`)
|
|
|
|
|
: If this option is true, an error will be thrown, if a certain given depth is exceeded
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
: The value to be evaluated recursively
|
|
|
|
|
*/
|
2021-08-25 22:28:49 +00:00
|
|
|
|
withRecursion =
|
2022-09-27 02:04:07 +00:00
|
|
|
|
{
|
2024-05-21 19:54:47 +00:00
|
|
|
|
depthLimit,
|
|
|
|
|
throwOnDepthLimit ? true
|
2021-08-25 22:28:49 +00:00
|
|
|
|
}:
|
2024-03-06 23:49:31 +00:00
|
|
|
|
assert isInt depthLimit;
|
2021-08-25 22:28:49 +00:00
|
|
|
|
let
|
2022-04-12 10:26:25 +00:00
|
|
|
|
specialAttrs = [
|
|
|
|
|
"__functor"
|
|
|
|
|
"__functionArgs"
|
|
|
|
|
"__toString"
|
|
|
|
|
"__pretty"
|
|
|
|
|
];
|
|
|
|
|
stepIntoAttr = evalNext: name:
|
2024-03-06 23:49:31 +00:00
|
|
|
|
if elem name specialAttrs
|
2022-04-12 10:26:25 +00:00
|
|
|
|
then id
|
|
|
|
|
else evalNext;
|
2021-08-25 22:28:49 +00:00
|
|
|
|
transform = depth:
|
|
|
|
|
if depthLimit != null && depth > depthLimit then
|
|
|
|
|
if throwOnDepthLimit
|
2021-09-28 20:26:51 +00:00
|
|
|
|
then throw "Exceeded maximum eval-depth limit of ${toString depthLimit} while trying to evaluate with `generators.withRecursion'!"
|
2021-08-25 22:28:49 +00:00
|
|
|
|
else const "<unevaluated>"
|
|
|
|
|
else id;
|
2024-03-06 23:49:31 +00:00
|
|
|
|
mapAny = depth: v:
|
2021-08-25 22:28:49 +00:00
|
|
|
|
let
|
|
|
|
|
evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
|
|
|
|
|
in
|
2022-04-12 10:26:25 +00:00
|
|
|
|
if isAttrs v then mapAttrs (stepIntoAttr evalNext) v
|
2021-08-25 22:28:49 +00:00
|
|
|
|
else if isList v then map evalNext v
|
|
|
|
|
else transform (depth + 1) v;
|
|
|
|
|
in
|
|
|
|
|
mapAny 0;
|
2018-03-26 15:26:20 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Pretty print a value, akin to `builtins.trace`.
|
|
|
|
|
|
|
|
|
|
Should probably be a builtin as well.
|
|
|
|
|
|
|
|
|
|
The pretty-printed string should be suitable for rendering default values
|
|
|
|
|
in the NixOS manual. In particular, it should be as close to a valid Nix expression
|
|
|
|
|
as possible.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
: allowPrettyValues
|
|
|
|
|
: If this option is true, attrsets like { __pretty = fn; val = …; }
|
|
|
|
|
will use fn to convert val to a pretty printed representation.
|
|
|
|
|
(This means fn is type Val -> String.)
|
|
|
|
|
: multiline
|
|
|
|
|
: If this option is true, the output is indented with newlines for attribute sets and lists
|
|
|
|
|
: indent
|
|
|
|
|
: Initial indentation level
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
: The value to be pretty printed
|
|
|
|
|
*/
|
2017-06-06 20:41:22 +00:00
|
|
|
|
toPretty = {
|
2020-09-04 15:46:12 +00:00
|
|
|
|
allowPrettyValues ? false,
|
2022-12-18 11:42:43 +00:00
|
|
|
|
multiline ? true,
|
|
|
|
|
indent ? ""
|
2022-09-27 02:04:07 +00:00
|
|
|
|
}:
|
2021-07-23 08:43:44 +00:00
|
|
|
|
let
|
2024-03-06 23:49:31 +00:00
|
|
|
|
go = indent: v:
|
|
|
|
|
let introSpace = if multiline then "\n${indent} " else " ";
|
2020-09-04 15:46:12 +00:00
|
|
|
|
outroSpace = if multiline then "\n${indent}" else " ";
|
2018-04-25 13:04:30 +00:00
|
|
|
|
in if isInt v then toString v
|
2022-11-03 14:56:27 +00:00
|
|
|
|
# toString loses precision on floats, so we use toJSON instead. This isn't perfect
|
|
|
|
|
# as the resulting string may not parse back as a float (e.g. 42, 1e-06), but for
|
|
|
|
|
# pretty-printing purposes this is acceptable.
|
|
|
|
|
else if isFloat v then builtins.toJSON v
|
2020-09-17 15:58:04 +00:00
|
|
|
|
else if isString v then
|
|
|
|
|
let
|
2024-03-06 23:49:31 +00:00
|
|
|
|
lines = filter (v: ! isList v) (split "\n" v);
|
2024-03-07 00:21:07 +00:00
|
|
|
|
escapeSingleline = escape [ "\\" "\"" "\${" ];
|
|
|
|
|
escapeMultiline = replaceStrings [ "\${" "''" ] [ "''\${" "'''" ];
|
2022-11-07 12:01:13 +00:00
|
|
|
|
singlelineResult = "\"" + concatStringsSep "\\n" (map escapeSingleline lines) + "\"";
|
|
|
|
|
multilineResult = let
|
|
|
|
|
escapedLines = map escapeMultiline lines;
|
|
|
|
|
# The last line gets a special treatment: if it's empty, '' is on its own line at the "outer"
|
|
|
|
|
# indentation level. Otherwise, '' is appended to the last line.
|
2024-03-07 00:15:07 +00:00
|
|
|
|
lastLine = last escapedLines;
|
|
|
|
|
in "''" + introSpace + concatStringsSep introSpace (init escapedLines)
|
2022-11-07 12:01:13 +00:00
|
|
|
|
+ (if lastLine == "" then outroSpace else introSpace + lastLine) + "''";
|
|
|
|
|
in
|
|
|
|
|
if multiline && length lines > 1 then multilineResult else singlelineResult
|
2018-03-26 15:26:20 +00:00
|
|
|
|
else if true == v then "true"
|
|
|
|
|
else if false == v then "false"
|
2018-04-25 13:04:30 +00:00
|
|
|
|
else if null == v then "null"
|
|
|
|
|
else if isPath v then toString v
|
2020-09-17 16:14:18 +00:00
|
|
|
|
else if isList v then
|
|
|
|
|
if v == [] then "[ ]"
|
|
|
|
|
else "[" + introSpace
|
2024-03-07 00:21:07 +00:00
|
|
|
|
+ concatMapStringsSep introSpace (go (indent + " ")) v
|
2020-09-17 16:14:18 +00:00
|
|
|
|
+ outroSpace + "]"
|
2020-09-17 16:18:50 +00:00
|
|
|
|
else if isFunction v then
|
2024-03-07 00:15:07 +00:00
|
|
|
|
let fna = functionArgs v;
|
2024-03-07 00:22:49 +00:00
|
|
|
|
showFnas = concatStringsSep ", " (mapAttrsToList
|
2020-09-17 16:18:50 +00:00
|
|
|
|
(name: hasDefVal: if hasDefVal then name + "?" else name)
|
2021-02-01 15:27:38 +00:00
|
|
|
|
fna);
|
|
|
|
|
in if fna == {} then "<function>"
|
|
|
|
|
else "<function, args: {${showFnas}}>"
|
2017-06-06 20:41:22 +00:00
|
|
|
|
else if isAttrs v then
|
|
|
|
|
# apply pretty values if allowed
|
2022-11-03 14:56:27 +00:00
|
|
|
|
if allowPrettyValues && v ? __pretty && v ? val
|
2017-06-06 20:41:22 +00:00
|
|
|
|
then v.__pretty v.val
|
2020-09-17 16:14:18 +00:00
|
|
|
|
else if v == {} then "{ }"
|
2018-04-25 13:04:30 +00:00
|
|
|
|
else if v ? type && v.type == "derivation" then
|
2022-11-04 16:31:41 +00:00
|
|
|
|
"<derivation ${v.name or "???"}>"
|
2020-09-04 15:46:12 +00:00
|
|
|
|
else "{" + introSpace
|
2024-03-07 00:22:49 +00:00
|
|
|
|
+ concatStringsSep introSpace (mapAttrsToList
|
2017-06-06 20:41:22 +00:00
|
|
|
|
(name: value:
|
2024-03-07 00:21:07 +00:00
|
|
|
|
"${escapeNixIdentifier name} = ${
|
2024-03-06 23:49:31 +00:00
|
|
|
|
addErrorContext "while evaluating an attribute `${name}`"
|
2022-12-10 22:36:46 +00:00
|
|
|
|
(go (indent + " ") value)
|
|
|
|
|
};") v)
|
2020-09-04 15:46:12 +00:00
|
|
|
|
+ outroSpace + "}"
|
2018-06-28 15:12:39 +00:00
|
|
|
|
else abort "generators.toPretty: should never happen (v = ${v})";
|
2022-12-18 11:42:43 +00:00
|
|
|
|
in go indent;
|
2017-06-06 20:41:22 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Translate a simple Nix expression to [Plist notation](https://en.wikipedia.org/wiki/Property_list).
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Options
|
|
|
|
|
: Empty set, there may be configuration options in the future
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
: The value to be converted to Plist
|
|
|
|
|
*/
|
2018-06-28 15:12:39 +00:00
|
|
|
|
toPlist = {}: v: let
|
2024-03-06 23:49:31 +00:00
|
|
|
|
expr = ind: x:
|
2019-04-24 03:48:22 +00:00
|
|
|
|
if x == null then "" else
|
2018-07-03 16:24:54 +00:00
|
|
|
|
if isBool x then bool ind x else
|
|
|
|
|
if isInt x then int ind x else
|
2018-06-28 15:12:39 +00:00
|
|
|
|
if isString x then str ind x else
|
2018-07-03 16:24:54 +00:00
|
|
|
|
if isList x then list ind x else
|
|
|
|
|
if isAttrs x then attrs ind x else
|
2023-03-27 13:46:32 +00:00
|
|
|
|
if isPath x then str ind (toString x) else
|
2018-07-03 16:24:54 +00:00
|
|
|
|
if isFloat x then float ind x else
|
2018-06-28 15:12:39 +00:00
|
|
|
|
abort "generators.toPlist: should never happen (v = ${v})";
|
2018-06-28 15:11:19 +00:00
|
|
|
|
|
2018-06-28 15:12:39 +00:00
|
|
|
|
literal = ind: x: ind + x;
|
2018-06-28 15:11:19 +00:00
|
|
|
|
|
2018-06-28 15:12:39 +00:00
|
|
|
|
bool = ind: x: literal ind (if x then "<true/>" else "<false/>");
|
|
|
|
|
int = ind: x: literal ind "<integer>${toString x}</integer>";
|
|
|
|
|
str = ind: x: literal ind "<string>${x}</string>";
|
|
|
|
|
key = ind: x: literal ind "<key>${x}</key>";
|
2018-07-03 16:24:54 +00:00
|
|
|
|
float = ind: x: literal ind "<real>${toString x}</real>";
|
2018-06-28 15:11:19 +00:00
|
|
|
|
|
2018-06-28 15:12:39 +00:00
|
|
|
|
indent = ind: expr "\t${ind}";
|
2018-06-28 15:11:19 +00:00
|
|
|
|
|
2024-03-07 00:21:07 +00:00
|
|
|
|
item = ind: concatMapStringsSep "\n" (indent ind);
|
2018-06-28 15:11:19 +00:00
|
|
|
|
|
2024-03-06 23:49:31 +00:00
|
|
|
|
list = ind: x: concatStringsSep "\n" [
|
2018-06-28 15:12:39 +00:00
|
|
|
|
(literal ind "<array>")
|
|
|
|
|
(item ind x)
|
|
|
|
|
(literal ind "</array>")
|
2018-06-28 15:11:19 +00:00
|
|
|
|
];
|
|
|
|
|
|
2024-03-06 23:49:31 +00:00
|
|
|
|
attrs = ind: x: concatStringsSep "\n" [
|
2018-06-28 15:12:39 +00:00
|
|
|
|
(literal ind "<dict>")
|
|
|
|
|
(attr ind x)
|
|
|
|
|
(literal ind "</dict>")
|
2018-06-28 15:11:19 +00:00
|
|
|
|
];
|
|
|
|
|
|
2018-06-28 15:12:39 +00:00
|
|
|
|
attr = let attrFilter = name: value: name != "_module" && value != null;
|
2024-03-07 00:15:07 +00:00
|
|
|
|
in ind: x: concatStringsSep "\n" (flatten (mapAttrsToList
|
|
|
|
|
(name: value: optionals (attrFilter name value) [
|
2018-06-28 15:12:39 +00:00
|
|
|
|
(key "\t${ind}" name)
|
|
|
|
|
(expr "\t${ind}" value)
|
2018-06-28 15:11:19 +00:00
|
|
|
|
]) x));
|
|
|
|
|
|
2018-06-28 15:12:39 +00:00
|
|
|
|
in ''<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
|
|
|
<plist version="1.0">
|
|
|
|
|
${expr "" v}
|
|
|
|
|
</plist>'';
|
2018-06-27 19:35:07 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Translate a simple Nix expression to Dhall notation.
|
|
|
|
|
|
|
|
|
|
Note that integers are translated to Integer and never
|
|
|
|
|
the Natural type.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Options
|
|
|
|
|
|
|
|
|
|
: Empty set, there may be configuration options in the future
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
|
|
|
|
|
: The value to be converted to Dhall
|
2021-03-24 10:20:36 +00:00
|
|
|
|
*/
|
|
|
|
|
toDhall = { }@args: v:
|
2024-03-06 23:49:31 +00:00
|
|
|
|
let concatItems = concatStringsSep ", ";
|
2021-03-24 10:20:36 +00:00
|
|
|
|
in if isAttrs v then
|
|
|
|
|
"{ ${
|
2024-03-07 00:15:07 +00:00
|
|
|
|
concatItems (mapAttrsToList
|
2021-03-24 10:20:36 +00:00
|
|
|
|
(key: value: "${key} = ${toDhall args value}") v)
|
|
|
|
|
} }"
|
|
|
|
|
else if isList v then
|
|
|
|
|
"[ ${concatItems (map (toDhall args) v)} ]"
|
|
|
|
|
else if isInt v then
|
|
|
|
|
"${if v < 0 then "" else "+"}${toString v}"
|
|
|
|
|
else if isBool v then
|
|
|
|
|
(if v then "True" else "False")
|
|
|
|
|
else if isFunction v then
|
|
|
|
|
abort "generators.toDhall: cannot convert a function to Dhall"
|
2023-03-05 21:08:45 +00:00
|
|
|
|
else if v == null then
|
2021-03-24 10:20:36 +00:00
|
|
|
|
abort "generators.toDhall: cannot convert a null to Dhall"
|
|
|
|
|
else
|
2024-03-07 00:34:08 +00:00
|
|
|
|
toJSON v;
|
2023-04-09 20:21:36 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Translate a simple Nix expression to Lua representation with occasional
|
|
|
|
|
Lua-inlines that can be constructed by mkLuaInline function.
|
2023-04-23 17:33:11 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
Configuration:
|
2023-04-23 17:33:11 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
* multiline - by default is true which results in indented block-like view.
|
|
|
|
|
* indent - initial indent.
|
|
|
|
|
* asBindings - by default generate single value, but with this use attrset to set global vars.
|
2023-04-23 17:33:11 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
Attention:
|
|
|
|
|
|
|
|
|
|
Regardless of multiline parameter there is no trailing newline.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Structured function argument
|
|
|
|
|
|
|
|
|
|
: multiline (optional, default: `true`)
|
|
|
|
|
: If this option is true, the output is indented with newlines for attribute sets and lists
|
|
|
|
|
: indent (optional, default: `""`)
|
|
|
|
|
: Initial indentation level
|
|
|
|
|
: asBindings (optional, default: `false`)
|
|
|
|
|
: Interpret as variable bindings
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
|
|
|
|
|
: The value to be converted to Lua
|
|
|
|
|
|
|
|
|
|
# Type
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
toLua :: AttrSet -> Any -> String
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
:::{.example}
|
|
|
|
|
## `lib.generators.toLua` usage example
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
generators.toLua {}
|
2023-04-23 17:33:11 +00:00
|
|
|
|
{
|
2024-05-21 19:54:47 +00:00
|
|
|
|
cmd = [ "typescript-language-server" "--stdio" ];
|
|
|
|
|
settings.workspace.library = mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
|
2023-04-23 17:33:11 +00:00
|
|
|
|
}
|
2024-05-21 19:54:47 +00:00
|
|
|
|
->
|
|
|
|
|
{
|
|
|
|
|
["cmd"] = {
|
|
|
|
|
"typescript-language-server",
|
|
|
|
|
"--stdio"
|
|
|
|
|
},
|
|
|
|
|
["settings"] = {
|
|
|
|
|
["workspace"] = {
|
|
|
|
|
["library"] = (vim.api.nvim_get_runtime_file("", true))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2023-04-23 17:33:11 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
:::
|
2023-04-23 17:33:11 +00:00
|
|
|
|
*/
|
2023-04-23 17:35:52 +00:00
|
|
|
|
toLua = {
|
|
|
|
|
multiline ? true,
|
2023-04-29 16:35:07 +00:00
|
|
|
|
indent ? "",
|
|
|
|
|
asBindings ? false,
|
2023-04-23 17:35:52 +00:00
|
|
|
|
}@args: v:
|
2023-04-09 20:21:36 +00:00
|
|
|
|
let
|
2023-04-23 17:35:52 +00:00
|
|
|
|
innerIndent = "${indent} ";
|
|
|
|
|
introSpace = if multiline then "\n${innerIndent}" else " ";
|
|
|
|
|
outroSpace = if multiline then "\n${indent}" else " ";
|
2023-04-29 16:35:07 +00:00
|
|
|
|
innerArgs = args // {
|
|
|
|
|
indent = if asBindings then indent else innerIndent;
|
|
|
|
|
asBindings = false;
|
|
|
|
|
};
|
2023-04-23 17:35:52 +00:00
|
|
|
|
concatItems = concatStringsSep ",${introSpace}";
|
2023-04-09 20:21:36 +00:00
|
|
|
|
isLuaInline = { _type ? null, ... }: _type == "lua-inline";
|
2023-04-29 16:35:07 +00:00
|
|
|
|
|
|
|
|
|
generatedBindings =
|
2024-03-07 00:15:07 +00:00
|
|
|
|
assert assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}";
|
2024-03-07 00:21:07 +00:00
|
|
|
|
concatStrings (
|
2024-03-07 00:15:07 +00:00
|
|
|
|
mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v
|
2023-04-29 16:35:07 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
# https://en.wikibooks.org/wiki/Lua_Programming/variable#Variable_names
|
|
|
|
|
matchVarName = match "[[:alpha:]_][[:alnum:]_]*(\\.[[:alpha:]_][[:alnum:]_]*)*";
|
|
|
|
|
badVarNames = filter (name: matchVarName name == null) (attrNames v);
|
2023-04-09 20:21:36 +00:00
|
|
|
|
in
|
2023-04-29 16:35:07 +00:00
|
|
|
|
if asBindings then
|
|
|
|
|
generatedBindings
|
|
|
|
|
else if v == null then
|
2023-04-09 20:21:36 +00:00
|
|
|
|
"nil"
|
|
|
|
|
else if isInt v || isFloat v || isString v || isBool v then
|
2024-03-07 00:34:08 +00:00
|
|
|
|
toJSON v
|
2023-04-09 20:21:36 +00:00
|
|
|
|
else if isList v then
|
|
|
|
|
(if v == [ ] then "{}" else
|
2023-04-23 17:35:52 +00:00
|
|
|
|
"{${introSpace}${concatItems (map (value: "${toLua innerArgs value}") v)}${outroSpace}}")
|
2023-04-09 20:21:36 +00:00
|
|
|
|
else if isAttrs v then
|
|
|
|
|
(
|
|
|
|
|
if isLuaInline v then
|
|
|
|
|
"(${v.expr})"
|
|
|
|
|
else if v == { } then
|
|
|
|
|
"{}"
|
2024-03-07 00:22:49 +00:00
|
|
|
|
else if isDerivation v then
|
2023-12-14 21:41:50 +00:00
|
|
|
|
''"${toString v}"''
|
2023-04-09 20:21:36 +00:00
|
|
|
|
else
|
2023-04-23 17:35:52 +00:00
|
|
|
|
"{${introSpace}${concatItems (
|
2024-03-07 00:34:08 +00:00
|
|
|
|
mapAttrsToList (key: value: "[${toJSON key}] = ${toLua innerArgs value}") v
|
2023-04-23 17:35:52 +00:00
|
|
|
|
)}${outroSpace}}"
|
2023-04-09 20:21:36 +00:00
|
|
|
|
)
|
|
|
|
|
else
|
|
|
|
|
abort "generators.toLua: type ${typeOf v} is unsupported";
|
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
Mark string as Lua expression to be inlined when processed by toLua.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
`expr`
|
|
|
|
|
|
|
|
|
|
: 1\. Function argument
|
2023-04-23 17:33:11 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
# Type
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
mkLuaInline :: String -> AttrSet
|
|
|
|
|
```
|
2023-04-23 17:33:11 +00:00
|
|
|
|
*/
|
2023-04-09 20:21:36 +00:00
|
|
|
|
mkLuaInline = expr: { _type = "lua-inline"; inherit expr; };
|
2024-05-21 19:54:47 +00:00
|
|
|
|
} // {
|
|
|
|
|
/**
|
|
|
|
|
Generates JSON from an arbitrary (non-function) value.
|
|
|
|
|
For more information see the documentation of the builtin.
|
2024-03-07 00:34:08 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Options
|
|
|
|
|
|
|
|
|
|
: Empty set, there may be configuration options in the future
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
|
|
|
|
|
: The value to be converted to JSON
|
|
|
|
|
*/
|
|
|
|
|
toJSON = {}: lib.strings.toJSON;
|
2024-03-07 00:34:08 +00:00
|
|
|
|
|
2024-05-21 19:54:47 +00:00
|
|
|
|
/**
|
|
|
|
|
YAML has been a strict superset of JSON since 1.2, so we
|
|
|
|
|
use toJSON. Before it only had a few differences referring
|
|
|
|
|
to implicit typing rules, so it should work with older
|
|
|
|
|
parsers as well.
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
|
|
|
|
|
|
Options
|
|
|
|
|
|
|
|
|
|
: Empty set, there may be configuration options in the future
|
|
|
|
|
|
|
|
|
|
Value
|
|
|
|
|
|
|
|
|
|
: The value to be converted to YAML
|
|
|
|
|
*/
|
|
|
|
|
toYAML = {}: lib.strings.toJSON;
|
2016-11-06 00:51:13 +00:00
|
|
|
|
}
|