nix-community / nixpkgs-fmt Goto Github PK
View Code? Open in Web Editor NEWNix code formatter for nixpkgs [maintainer=@zimbatm]
Home Page: https://nix-community.github.io/nixpkgs-fmt/
License: Apache License 2.0
Nix code formatter for nixpkgs [maintainer=@zimbatm]
Home Page: https://nix-community.github.io/nixpkgs-fmt/
License: Apache License 2.0
This sample takes two tries to stabilize
{
buildInputs = [
] ++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
;
}
{
buildInputs = []
++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
;
}
After feeding the output back as an input:
{
buildInputs = []
++ stdenv.lib.optionals enableGui (with qt5; [ qtbase qtwebkit ])
++ stdenv.lib.optionals enableJupyter [ boost jsoncpp openssl zmqpp ]
;
}
let
id =
x:
# comment
x;
in
id 1
let
id =
x:
# comment
x;
in
id 1
let
id =
x:
# comment
x;
in
id 1
I currently have added it to my namespace:
$ nix-shell -p nur.repos.mic92.nixpkgs-fmt
$ nixpkgs-fmt --help
nixpkgs-fmt 0.1
Format Nix code
USAGE:
nixpkgs-fmt [FLAGS] [OPTIONS] [FILE]
FLAGS:
-h, --help Prints help information
-i, --in-place Overwrite FILE in place
--parse Show syntax tree instead of reformatting
-V, --version Prints version information
OPTIONS:
-o, --output <file> Place the output into <file>
ARGS:
<FILE> File to reformat
However it might be useful to have it might useful to have it a namespace
managed by one of the maintainers. Otherwise you can always make a pull request to my repository ...
It would better if the body was balanced with the set entries when the let block is not on the root of the file:
{
myAttr = foo:
let
hello = 3; in hello;
}
{
myAttr = foo:
let
hello = 3;
in
hello;
}
{
myAttr = foo:
let
hello = 3;
in
hello;
}
When a parenthesis is multi-line it should indent the inner bits.
{
xxx = listToAttrs (
concatMap (name:
let a = 4; in 5
));
}
{
xxx = listToAttrs (
concatMap (name:
let a = 4; in 5
));
}
{
xxx = listToAttrs (
concatMap (name:
let a = 4; in 5
)
);
}
(let
a = ''
foo
'';
in a)
results in
(
let
a = ''
foo
'';
in
a
)
instead of
(
let
a = ''
foo
'';
in
a
)
a more practical example would be:
wpa_supplicant.overrideAttrs(old: {
postBuild = ''
echo foo
'';
})
->
wpa_supplicant.overrideAttrs (
old: {
postBuild = ''
echo foo
'';
}
)
let
pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz)) {});
in
pkgs.buildEnv {
name = "innovu-httpd";
paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
postBuild = ''
# no tabs
# tabs
'';
}
let
pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz)) {});
in
pkgs.buildEnv {
name = "innovu-httpd";
paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
postBuild = ''
# no tabs
# tabs
'';
}
Ideally the output should confirm to whatever the nix language specifies or the conventions of nixpkgs. I don't really care whether it is tabs or spaces. The below uses spaces just to show the indentation consistency in GitHub's markdown code block:
let
pkgs = ((import (fetchTarball https://github.com/NixOS/nixpkgs/archive/staging.tar.gz)) {});
in
pkgs.buildEnv {
name = "innovu-httpd";
paths = [ pkgs.apacheHttpd pkgs.modsecurity_standalone ];
postBuild = ''
# no tabs
# tabs
'';
}
if
foo
then
bar
else
baz
if
foo
then
bar
else
baz
if
foo
then
bar
else
baz
# One line, everyone's happy
let self = { }; in self
#65 (comment) suggests that we could consider let ... in
just as an assert ...;
or a with ... ;
statement that does not indent the following body. In that case example 2 is inconsistent.
# input
# This should be okay if `let` is considered like a `with` or `assert`
let self = { }; in
self
# nix-fmt output
# But it is expanded :-(
let
self = {};
in
self
Overall, it seems that the let ... in body
is expanded (split across multiple lines as long as it is not written on one line. I think that expanding the let ... in
part should be independent from expanding the body itself and from decoupling the in
from the body.
The above example is made even worse by the fact that we do not indent toplevel let bodies (#108). The self
really looks weird and could be on the same line as the in
.
May I propose the following patterns ?
let foo = bar; in foo
let foo = bar; in
foo
let
foo = bar;
in {
bar = foo;
}
The implicit rule is that when the let+in construct is one one line, it behaves like a with
or assert
, and when it is on several lines (expanded form), no line break is enforced after the in
(which means that line breaks are only enforced for a multi-line body after a single line let+in).
{config,pkgs, lib =wfp}: {}
{ config, pkgs, lib =wfp }: {}
{ config, pkgs, lib = wfp }: {}
Looking at the diff produced by @zimbatm on discourse, the main differences that I see are on using compact forms to avoid extra lines.
For example:
diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
index 7ff22fb61fa..87d2ca3aa43 100644
--- a/maintainers/maintainer-list.nix
+++ b/maintainers/maintainer-list.nix
@@ -51,10 +51,12 @@
name = "Joachim Ernst";
github = "0x4A6F";
githubId = 9675338;
- keys = [{
- longkeyid = "rsa8192/0x87027528B006D66D";
- fingerprint = "F466 A548 AD3F C1F1 8C88 4576 8702 7528 B006 D66D";
- }];
+ keys = [
+ {
+ longkeyid = "rsa8192/0x87027528B006D66D";
+ fingerprint = "F466 A548 AD3F C1F1 8C88 4576 8702 7528 B006 D66D";
+ }
+ ];
};
"1000101" = {
email = "[email protected]";
and this occurs in many places, like for fetch*
calls
diff --git a/pkgs/development/python-modules/pyscard/default.nix b/pkgs/development/python-modules/pyscard/default.nix
index bab8e502b9c..e601f23ada9 100644
--- a/pkgs/development/python-modules/pyscard/default.nix
+++ b/pkgs/development/python-modules/pyscard/default.nix
@@ -19,10 +19,12 @@ buildPythonPackage rec {
patches = [
# Fixes darwin tests
# See: https://github.com/LudovicRousseau/pyscard/issues/77
- (fetchpatch {
- url = "https://github.com/LudovicRousseau/pyscard/commit/62e675028086c75656444cc21d563d9f08ebf8e7.patch";
- sha256 = "1lr55npcpc8j750vf7vaisqyk18d5f00l7nii2lvawg4sssjaaf7";
- })
+ (
+ fetchpatch {
+ url = "https://github.com/LudovicRousseau/pyscard/commit/62e675028086c75656444cc21d563d9f08ebf8e7.patch";
+ sha256 = "1lr55npcpc8j750vf7vaisqyk18d5f00l7nii2lvawg4sssjaaf7";
+ }
+ )
];
There seems to be an implicit rule that collapsing delimiters (parentheses, square brackets and such) is desirable if there is only one expression inside. Furthermore, the collapsing results in a single indent, instead of two (or more).
In short:
{
testA= [(fetchurl {
url = "bla";
})];
testB = [( fetchurl{url="bla";} )];
}
{
testA = [
(
fetchurl {
url = "bla";
}
)
];
testB = [ (fetchurl { url = "bla"; }) ];
}
{
testA = [
(fetchurl {
url = "bla";
})
];
testB = [ (fetchurl { url = "bla"; }) ];
}
or
{
testA = [ (fetchurl {
url = "bla";
}) ];
testB = [ (fetchurl { url = "bla"; }) ];
}
or (mind the space changes)
{
testA = [(fetchurl {
url = "bla";
})];
testB = [ (fetchurl { url = "bla"; }) ];
}
Of course, when the list constains mutiple elements, we should switch to a safer form.
{
testA= [(fetchurl {
url = "bla";
})(fetchurl {
url = "foo";
})];
testB = [( fetchurl{url="bla";} )( fetchurl{url="foo";} )];
}
{
testA = [
(
fetchurl {
url = "bla";
}
)
(
fetchurl {
url = "foo";
}
)
];
testB = [ (fetchurl { url = "bla"; }) (fetchurl { url = "foo"; }) ];
}
{
testA = [
(fetchurl {
url = "bla";
})
(fetchurl {
url = "foo";
})
];
testB = [ (fetchurl { url = "bla"; }) (fetchurl { url = "foo"; }) ];
}
The simplest way to achieve this would be to make parentheses special. When they are expanded (split on several lines) do not force a line break after them. that would still keep the following desired output impossible, but get all the other options above right.
{
testA = [(fetchurl {
url = "bla";
})];
testB = [ (fetchurl { url = "bla"; }) ];
}
Coming form https://discourse.nixos.org/t/nixpkgs-fmt-beta-0-3-1/3812/2?u=zimbatm
/cc @lilyball
{
meta = (oldAttrs.meta or {}) // {
platforms = pkgs.rustc.meta.platforms;
};
}
{
meta = (oldAttrs.meta or {})
// {
platforms = pkgs.rustc.meta.platforms;
}
;
}
see input?
src/rules.rs apply_arg
should probably also look if the node is a comment:
{
foo =
# describe bar
bar:
# describe baz
baz:
fnbody;
}
{
foo =
# describe bar
bar:
# describe baz
baz:
fnbody;
}
See input
whenever a let..in block is being added, it re-indents the whole body, creating a lot of noise in the diff.
Maybe it's worth special-casing at least for the top-level to not indent the body?
{ stdenv, fetchFromGitHub }:
let
pname = "hello";
version = "1.2.3";
in
stdenv.mkDerivation {
inherit pname version;
src = fetchFromGitHub {
owner = "xxx";
repo = pname;
rev = version;
sha256 = "...";
};
}
{ stdenv, fetchFromGitHub }:
let
pname = "hello";
version = "1.2.3";
in
stdenv.mkDerivation {
inherit pname version;
src = fetchFromGitHub {
owner = "xxx";
repo = pname;
rev = version;
sha256 = "...";
};
}
{ stdenv, fetchFromGitHub }:
let
pname = "hello";
version = "1.2.3";
in
stdenv.mkDerivation {
inherit pname version;
src = fetchFromGitHub {
owner = "xxx";
repo = pname;
rev = version;
sha256 = "...";
};
}
There are essentially two modes of operation for the CLI:
.git
{
inherit (import ./pep425.nix {
inherit lib python;
inherit (pkgs) stdenv;
}) selectWheel;
}
{
inherit (import ./pep425.nix {
inherit lib python;
inherit (pkgs) stdenv;
}) selectWheel
;
}
{
inherit (import ./pep425.nix {
inherit lib python;
inherit (pkgs) stdenv;
}) selectWheel;
}
The ;
should not be on a separate line.
Describe the bug
nix-env -f https://github.com/nix-community/nixpkgs-fmt/archive/master.tar.gz -i
trace: assert failed: hash mismatch for file '/nix/store/7jaw5xi1f5nbhbyfhzasvkzgaws03f9q-master.tar.gz/Cargo.lock':
wanted: sha256:d6e3edd1c5e96ea40c8ffe5fedf110ad7e903a478d4ae999186023819388f8cb
got: sha256:36f58d1ddf4d56bc75aa1d18bb7c4e894eb56c2a0f4a81d83c3f24aec2e98926
System information
"x86_64-linux"
Linux 4.19.66, NixOS, 19.09.git.4557b9f (Loris)
yes
yes
nix-env (Nix) 2.2.2
"nixos-19.09pre188498.4557b9f1f50"
"home-manager"
/nix/var/nix/profiles/per-user/root/channels/nixos
{foo,
bar}:
foo+bar
{
foo
, bar
}:
foo + bar
This seems more canonical in nixpkgs:
{ foo
, bar
}:
foo + bar
I'd love to use it if I can nix-build
:)
pkgs.example rec {
buildInputs = [ pkgs.foo ] ++
pkgs.stdenv.lib.optionals pkgs.stdenv.isDarwin [
pkgs.bar
];
}
pkgs.example rec {
buildInputs = [ pkgs.foo ]
++ pkgs.stdenv.lib.optionals pkgs.stdenv.isDarwin [ # <- I'm surprised this isn't indentend two spaces
pkgs.bar
]
;
}
Not so sure about this one, though.
if true==1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234 then foo else bar
if true == 1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234 then foo else bar
if
true == 1231234123412341234123412341234123412341234132412341234123412341234123412341234123412341234
then foo
else bar
if statements that are too long should be wrapped
I am so excited for this. I tried out the existing version on master at https://nix-community.github.io/nixpkgs-fmt/ and it fails to load a javascript file.
The script from โhttps://nix-community.github.io/nixpkgs-fmt/pkg/nixpkgs_fmt_wasm.jsโ was loaded even though its MIME type (โtext/htmlโ) is not a valid JavaScript MIME type.[Learn More] nixpkgs-fmt
Loading failed for the module with source โhttps://nix-community.github.io/nixpkgs-fmt/pkg/nixpkgs_fmt_wasm.jsโ. nixpkgs-fmt:54:1
โ
at this time the file 404s.
Way to go on the WASM idea. This is incredible.
It would be cool if the engine could should all the matching rules with the diff. The more rule we add, the harder it becomes to understand how they interact with each-other.
Example output:
<rule name> matched <element>
<diff>
What do you think @matklad ?
On Darwin "cargo build" fails with the following error message:
= note: ld: framework not found Security
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)
I think that darwin.apple_sdk.frameworks.Security
should be added to the buildInputs
.
{
userHome = if home != null
then home
else config.users.extraUsers.${user}.home;
}
{
userHome = if home != null
then home
else config.users.extraUsers.${user}.home;
}
{
userHome = if home != null
then home
else config.users.extraUsers.${user}.home;
}
or maybe
{
userHome =
if home != null
then home
else config.users.extraUsers.${user}.home;
}
https://github.com/nrwl/precise-commits#why-precise-commits looks interesting for a gradual transition
I think the function body shouldn't be indented if the arguments are on the same level.
let
aaa =
{foo,bar}:
foo+bar
;
bbb = {foo,bar}:
foo+bar
;
in
null
let
aaa =
{ foo, bar }:
foo + bar
;
bbb = { foo, bar }:
foo + bar
;
in
null
let
aaa =
{ foo, bar }:
foo + bar
;
bbb = { foo, bar }:
foo + bar
;
in
null
Note there is a
before pkgs
:
pkgs
RuntimeError: unreachable executed
{
pkgs ? import ./nix/nixpkgs.nix { },
src ? builtins.fetchGit {
url = ./.;
ref = "HEAD";
}
}:
pkgs.example rec {
}
{ pkgs ? import ./nix/nixpkgs.nix {}
, src ? builtins.fetchGit {
url = ./.;
ref = "HEAD";
} # <- it seems this } and the two prior lines should be indented
}:
pkgs.example rec {
}
I see two different patterns which are used to format function arguments:
{ pkgs ? import ./nix/nixpkgs.nix {}
, src ? builtins.fetchGit {
url = ./.;
ref = "HEAD";
}
}:
pkgs.example rec {}
toINI = {
mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
mkKeyValue ? mkKeyValueDefault {} "="
}: attrsOfAttrs:
let ...
which one we should use?
Additionally, is it a good idea to to keep first parameter on the same line, as in { pkgs ? import ./nix/nixpkgs.nix {}
?
We should rewrite URLs like http://example.com
to string "http://example.com"
Should we do the same for paths like ./some/dir
? Or are paths and urls are completely different things? rnix
uses TOKEN_PATH
for both of these, and I wonder if that should be fixed.
Not sure what the proper way to do this would be, but the nested indentation is not right.
{ mkDerivation }:
mkDerivation rec {
buildInputs = [
alsaLib
] ++ lib.optionals stdenv.isLinux [
utillinux
] ++ (with gst_all_1; [
gstreamer
]);
}
{ mkDerivation }:
mkDerivation rec {
buildInputs = [
alsaLib
]
++ lib.optionals stdenv.isLinux [
utillinux
]
++ (
with gst_all_1; [
gstreamer
]
)
;
}
{ mkDerivation }:
mkDerivation rec {
buildInputs = [
alsaLib
]
++ lib.optionals stdenv.isLinux [
utillinux
]
++ (with gst_all_1; [
gstreamer
])
;
}
Just played around in the WASM example a little.
[ one /*two*/ three four five six seven eight nine
]
[
one /*two*/ three
four
five
six
seven
eight
nine
]
[
one /*two*/
three
four
five
six
seven
eight
nine
]
or maybe even the comment should be on its own line, not sure.
{
inherit (builtins)
# comment
toString
;
}
{
inherit (builtins) # comment toString;
}
{
inherit (builtins)
# comment
toString
;
}
Right now it looks like this:
It would be more readable when using the usual colors red and green for the changed lines.
See for example GitHub: https://github.com/nix-community/nixpkgs-fmt/pull/110/files
green: #e6ffed
red: #ffeef0
Describe the bug
Formatting this code produces a runtime error:
{ } =
To Reproduce
Steps to reproduce the behavior:
echo "{} =" > sample.nix
thread 'main' panicked at 'assertion failed: prev.is_none()', src/engine/fmt_model.rs:267:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Expected behavior
No runtime error
System information
nixpkgs-fmt version: master 81e2341
# NixOS module handling.
let lib = import ./default.nix; in
with { inherit (builtins) head tail; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
with import ./properties.nix;
rec {
# Unfortunately this can also be a string.
isPath = x: !(
builtins.isFunction x
|| builtins.isAttrs x
|| builtins.isInt x
|| builtins.isBool x
|| builtins.isList x
);
importIfPath = path:
if isPath path then
import path
else
path;
applyIfFunction = f: arg:
if builtins.isFunction f then
f arg
else
f;
moduleClosure = initModules: args:
let
moduleImport = m:
(applyIfFunction (importIfPath m) args) // {
# used by generic closure to avoid duplicated imports.
key = m;
};
removeKeys = list: map (m: removeAttrs m ["key"]) list;
getImports = m:
if m ? config || m ? options then
attrByPath ["imports"] [] m
else
toList (rmProperties (attrByPath ["require"] [] (delayProperties m)));
getImportedPaths = m: filter isPath (getImports m);
getImportedSets = m: filter (x: !isPath x) (getImports m);
inlineImportedSets = list:
lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list;
in
removeKeys (inlineImportedSets (lazyGenericClosure {
startSet = map moduleImport initModules;
operator = m: map moduleImport (getImportedPaths m);
}));
selectDeclsAndDefs = modules:
lib.concatMap (m:
if m ? config || m ? options then
attrByPath ["options"] [] m
++ attrByPath ["config"] [] m
else
[ m ]
) modules;
}
# NixOS module handling.
let
lib = import ./default.nix;
in
with { inherit (builtins) head tail; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
with import ./properties.nix;
rec {
# Unfortunately this can also be a string.
isPath = x: !(
builtins.isFunction x
|| builtins.isAttrs x
|| builtins.isInt x
|| builtins.isBool x
|| builtins.isList x
);
importIfPath = path:
if isPath path then
import path
else
path;
applyIfFunction = f: arg:
if builtins.isFunction f then
f arg
else
f;
moduleClosure = initModules: args:
let
moduleImport = m:
(applyIfFunction (importIfPath m) args)
// {
# used by generic closure to avoid duplicated imports.
key = m;
};
removeKeys = list: map (m: removeAttrs m [ "key" ]) list;
getImports = m:
if m ? config || m ? options then
attrByPath [ "imports" ] [] m
else
toList (rmProperties (attrByPath [ "require" ] [] (delayProperties m)));
getImportedPaths = m: filter isPath (getImports m);
getImportedSets = m: filter (x: !isPath x) (getImports m);
inlineImportedSets = list:
lib.concatMap (m:[ m ] ++ map moduleImport (getImportedSets m)) list;
in
removeKeys (
inlineImportedSets (
lazyGenericClosure {
startSet = map moduleImport initModules;
operator = m: map moduleImport (getImportedPaths m);
}
)
);
selectDeclsAndDefs = modules:
lib.concatMap (
m:
if m ? config || m ? options then
attrByPath [ "options" ] [] m
++ attrByPath [ "config" ] [] m
else
[ m ]
) modules;
}
{
traceIf =
# predicate to check
pred:
RuntimeError: unreachable executed
nixpkgs-fmt should respect \n
and never fold lines back into one
foo ++
bar
foo ++ bar
foo
++ bar
Describe the bug
Fuzzing crash: fuzz/artifacts/fmt/crash-654e6ed06597b86f23483b793664777da9b24c04
To Reproduce
Steps to reproduce the behavior:
echo ".." > foo.nix
thread 'main' panicked at 'assertion failed: prev.is_none()', src/engine/fmt_model.rs:269:9
Describe the bug
nixpkgs-fmt
changes the meaning of scientific notation.
To Reproduce
Format the following expression:
3.9e-3
It will format this as
3.9 e-3
which is not the same expression.
Expected behavior
The file is unchanged
System information
nixpkgs-fmt --version
nixpkgs-fmt 0.6.0
Additional context
Add any other context about the problem here.
The multi-line string should behave more like the list [
and ]
{
string = ''
hello
'';
list = [
hello
];
}
{
string = ''
hello
'';
list = [
hello
];
}
{
string = ''
hello
'';
list = [
hello
];
}
{ lib, ... }:
with lib;
{
nix.extraOptions = ''
builders-use-substitutes = true
'';
}
{ lib, ... }:
with lib;
{
nix.extraOptions = ''
builders-use-substitutes = true
'';
}
Expected
nix.extraOptions = ''
builders-use-substitutes = true
'';
nixpkgs-fmt is already available as a WASM module, and you can use WASM in VSCode extensions as described at microsoft/vscode#65559 (comment), so it looks like it would be possible to make a formatter extension for VSCode.
It would be nice to run the code through more extensive tests.
From #70 (comment)
We use libfuzzer-sys in rust-analyzer:
https://github.com/rust-analyzer/rust-analyzer/tree/master/crates/ra_syntax/fuzz
https://github.com/rust-fuzz/libfuzzer-sys
Another approach is to use property-based testing + randomized text edits.
As a user I want an easy way to report formatting issues.
A possible implementation would be:
I tested it with a package i created, but see no diff. So maybe my code is perfect (i hope :D), but i might not see the diff. So it would be helpful to highlight the diff.
Another variation of #20. This is the diff I am getting on a correctly-formatted code:
catAttrs = builtins.catAttrs or
- (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
+ (attr: l: concatLists (map (s: if s ? ${attr} then [ s.${attr} ] else []) l));
Still fighting the same conflict we have with keeping the balanced trees.
Is your feature request related to a problem? Please describe.
I usually use formaters / linters in pre-commit hooks to prevent mal-formatted commits but I dislike for the formatter to manipulate the git index by formatting changed files. Instead, I prefer running in linter mode that can fail the hook with exit code != 0 in case of formatting issues. The point of this is that I prefer to review the change before committing it. nixpkgs-fmt
lacks such a mode.
Describe the solution you'd like
A command option nixpkgs-fmt --validate [srcs]
that takes a list of files and fails if one or more files are not properly formatted.
Describe alternatives you've considered
I suppose you can achieve this using bash scripting, eg (pseudo-code)
for file in $(find . -name "*.nix"); do
cat "$file" | nixpkgs-fmt --explain > "$file.explain"
if diff "$file" "$file.explain"; then
exit 1
fi
done
exit 0
This does feel like a hack though.
(
builtins.foldl' (
acc: v: let
isOperator = builtins.typeOf v == "list";
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
in
if isOperator then (acc // { inherit operator; }) else {
inherit operator;
state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
}
)
{
operator = ",";
state = true;
}
tokens
).state;
(
builtins.foldl' (
acc: v: let
isOperator = builtins.typeOf v == "list";
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
in
if isOperator then (acc // { inherit operator; }) else {
inherit operator;
state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
}
)
{
operator = ",";
state = true;
}
tokens
).state;
(
builtins.foldl'
(
acc: v: let
isOperator = builtins.typeOf v == "list";
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
in
if isOperator then (acc // { inherit operator; }) else {
inherit operator;
state = operators."${operator}" acc.state (satisfiesSemver pythonVersion v);
}
)
{
operator = ",";
state = true;
}
tokens
).state;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.