Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ let
}:
path:
let
result = if pipef == null then { imports = [ module ]; } else pipef (leafs path);
result = if pipef == null then { imports = [ module ]; } else pipef (leaves path);

# module stays a function: callers may apply it as a module function, and
# keeping it a lambda defers the tree read (`leafs path`) until module-eval
# keeping it a lambda defers the tree read (`leaves path`) until module-eval
# rather than at `it ./dir` construction time. It no longer needs `lib` —
# the reader is pure `builtins` — so the argument is ignored.
module =
_:
let
files = leafs path;
files = leaves path;
in
{
imports = if scoped == { } then files else map scoped-import files;
Expand All @@ -34,7 +34,7 @@ let
// scoped
);

leafs =
leaves =
let
listFilesRecursive =
x:
Expand Down Expand Up @@ -250,13 +250,18 @@ let
withLib = _lib: mergeAttrs { };
initFilter = initf: mergeAttrs { inherit initf; };
pipeTo = pipef: mergeAttrs { inherit pipef; };
leafs = mergeAttrs { pipef = (i: i); };
leaves = mergeAttrs { pipef = (i: i); };
leafs =
builtins.warn "import-tree.leafs has been deprecated. Use import-tree.leaves instead."
(mergeAttrs {
pipef = (i: i);
});

# Applies empty (for already path-configured trees)
result = current [ ];

# Return a list of all filtered files.
files = current.leafs.result;
files = current.leaves.result;

# returns the original empty state
new = callable;
Expand Down
10 changes: 5 additions & 5 deletions docs/src/content/docs/guides/combinator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ Combinator syntax allows you to pass functions to `import-tree` to configure and
# Without combinators (verbose)
let
configured = import-tree.map import;
leafs = configured.leafs;
leaves = configured.leaves;
in
leafs ./modules
leaves ./modules

# With combinators (terse)
import-tree (it: it.map import) (it: it.leafs) ./modules
import-tree (it: it.map import) (it: it.leaves) ./modules
```

## How It Works
Expand Down Expand Up @@ -50,7 +50,7 @@ Get a filtered file list in one expression:
```nix
import-tree
(it: it.filter (lib.hasSuffix "mod.nix"))
(it: it.leafs)
(it: it.leaves)
./modules
```

Expand All @@ -74,7 +74,7 @@ let
in
custom
(it: it.nixFilesOnly)
(it: it.leafs)
(it: it.leaves)
./src
```

Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/guides/mapping.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ Multiple `.map` calls compose left-to-right (the first map runs first):
import-tree
(i: i.map import) # import each .nix file
(i: i.map builtins.stringLength) # get the length of each result
(i: i.leafs ./dir)
(i: i.leaves ./dir)
```

### Using map Outside Module Evaluation

When used with `.leafs` or `.pipeTo`, `.map` transforms paths into arbitrary values - not just modules:
When used with `.leaves` or `.pipeTo`, `.map` transforms paths into arbitrary values - not just modules:

```nix
# Read all .md files under a directory
import-tree
(i: i.initFilter (lib.hasSuffix ".md"))
(i: i.map builtins.readFile)
(i: i.leafs ./docs)
(i: i.leaves ./docs)

# => [ "# Title\n..." "# Other\n..." ]
```
12 changes: 6 additions & 6 deletions docs/src/content/docs/guides/outside-modules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ description: Use import-tree to list files programmatically, without importing t
`import-tree` doesn't have to produce module imports. You can use it to get a plain list of files:

```nix
import-tree.leafs ./modules
import-tree.leaves ./modules
# => [ /path/to/modules/a.nix /path/to/modules/b.nix ]
```

The tree reader is implemented with pure `builtins`, so `.leafs`, `.files` and `.pipeTo` work everywhere — including outside module evaluation — with no setup.
The tree reader is implemented with pure `builtins`, so `.leaves`, `.files` and `.pipeTo` work everywhere — including outside module evaluation — with no setup.

### leafs
### leaves

`.leafs` returns a configured import-tree that, when given a path, produces a flat list of discovered files:
`.leaves` returns a configured import-tree that, when given a path, produces a flat list of discovered files:

```nix
import-tree.leafs ./src
import-tree.leaves ./src
# => [ ./src/main.nix ./src/utils.nix ]
```

### files

`.files` is a shortcut for `.leafs.result`: returns the list directly when paths have already been added via `.addPath`:
`.files` is a shortcut for `.leaves.result`: returns the list directly when paths have already been added via `.addPath`:

```nix
import-tree
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The `_helpers/` directory is skipped because paths containing `/_` are ignored b
<LinkButton href="/guides/custom-api" variant="minimal" icon="right-arrow">Custom API Guide</LinkButton>
</Card>
<Card title="Non-Module Usage" icon="seti:folder">
Use `.leafs` and `.files` outside module evaluation to get raw file lists for any purpose.
Use `.leaves` and `.files` outside module evaluation to get raw file lists for any purpose.
<LinkButton href="/guides/outside-modules" variant="minimal" icon="right-arrow">Outside Modules</LinkButton>
</Card>
<Card title="Dendritic Pattern" icon="star">
Expand Down
8 changes: 4 additions & 4 deletions docs/src/content/docs/reference/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -177,26 +177,26 @@ import-tree (it: it.addScoped { foo = 42 }) (it: it.addScoped { bar = 99 })

## Output

### `.leafs`
### `.leaves`

Returns a configured import-tree that produces file lists instead of modules:

```nix
import-tree.leafs ./modules
import-tree.leaves ./modules
# => [ ./modules/a.nix ./modules/b.nix ]
```

### `.files`

Shorthand for `.leafs.result`:
Shorthand for `.leaves.result`:

```nix
(import-tree.addPath ./modules).files
```

### `.pipeTo <fn>`

Like `.leafs` but pipes the result list through `fn`:
Like `.leaves` but pipes the result list through `fn`:

```nix
import-tree.pipeTo builtins.length ./modules
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import-tree
(i: i.initFilter (lib.hasSuffix ".json"))
(i: i.map builtins.readFile)
(i: i.map builtins.fromJSON)
(i: i.leafs ./config)
(i: i.leaves ./config)
# => list of parsed JSON objects
```

Expand Down
52 changes: 26 additions & 26 deletions tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ let
in
{
import-tree = {
leafs."test works without withLib (lib no longer required)" = {
expr = it.leafs ./tree/a;
leaves."test works without withLib (lib no longer required)" = {
expr = it.leaves ./tree/a;
expected = [
./tree/a/a_b.nix
./tree/a/b/b_a.nix
./tree/a/b/m.nix
];
};

leafs."test withLib is a no-op kept for backward compatibility" = {
expr = (it.withLib lib).leafs ./tree/hello;
leaves."test withLib is a no-op kept for backward compatibility" = {
expr = (it.withLib lib).leaves ./tree/hello;
expected = [ ];
};

leafs."test only returns nix non-ignored files" = {
expr = lit.leafs ./tree/a;
leaves."test only returns nix non-ignored files" = {
expr = lit.leaves ./tree/a;
expected = [
./tree/a/a_b.nix
./tree/a/b/b_a.nix
Expand All @@ -31,62 +31,62 @@ in
};

filter."test returns empty if no nix files with true predicate" = {
expr = (lit.filter (_: false)).leafs ./tree;
expr = (lit.filter (_: false)).leaves ./tree;
expected = [ ];
};

filter."test only returns nix files with true predicate" = {
expr = (lit.filter (lib.hasSuffix "m.nix")).leafs ./tree;
expr = (lit.filter (lib.hasSuffix "m.nix")).leaves ./tree;
expected = [ ./tree/a/b/m.nix ];
};

filter."test multiple `filter`s compose" = {
expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leafs ./tree;
expr = ((lit.filter (lib.hasInfix "b/")).filter (lib.hasInfix "_")).leaves ./tree;
expected = [ ./tree/a/b/b_a.nix ];
};

match."test returns empty if no files match regex" = {
expr = (lit.match "badregex").leafs ./tree;
expr = (lit.match "badregex").leaves ./tree;
expected = [ ];
};

match."test returns files matching regex" = {
expr = (lit.match ".*/[^/]+_[^/]+\.nix").leafs ./tree;
expr = (lit.match ".*/[^/]+_[^/]+\.nix").leaves ./tree;
expected = [
./tree/a/a_b.nix
./tree/a/b/b_a.nix
];
};

matchNot."test returns files not matching regex" = {
expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leafs ./tree/a/b;
expr = (lit.matchNot ".*/[^/]+_[^/]+\.nix").leaves ./tree/a/b;
expected = [
./tree/a/b/m.nix
];
};

match."test `match` composes with `filter`" = {
expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leafs ./tree;
expr = ((lit.match ".*a_b.nix").filter (lib.hasInfix "/a/")).leaves ./tree;
expected = [ ./tree/a/a_b.nix ];
};

match."test multiple `match`s compose" = {
expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leafs ./tree;
expr = ((lit.match ".*/[^/]+_[^/]+\.nix").match ".*b\.nix").leaves ./tree;
expected = [ ./tree/a/a_b.nix ];
};

map."test transforms each matching file with function" = {
expr = (lit.map import).leafs ./tree/x;
expr = (lit.map import).leaves ./tree/x;
expected = [ "z" ];
};

map."test `map` composes with `filter`" = {
expr = ((lit.filter (lib.hasInfix "/x")).map import).leafs ./tree;
expr = ((lit.filter (lib.hasInfix "/x")).map import).leaves ./tree;
expected = [ "z" ];
};

map."test multiple `map`s compose" = {
expr = ((lit.map import).map builtins.stringLength).leafs ./tree/x;
expr = ((lit.map import).map builtins.stringLength).leaves ./tree/x;
expected = [ 1 ];
};

Expand All @@ -106,7 +106,7 @@ in

addPath."test `addPath` identity" = {
expr = ((lit.addPath ./tree/x).addPath ./tree/a/b).files;
expected = lit.leafs [
expected = lit.leaves [
./tree/x
./tree/a/b
];
Expand All @@ -125,7 +125,7 @@ in
};

initFilter."test can change the initial filter to look for other file types" = {
expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leafs [ ./tree/a ];
expr = (lit.initFilter (p: lib.hasSuffix ".txt" p)).leaves [ ./tree/a ];
expected = [ ./tree/a/a.txt ];
};

Expand Down Expand Up @@ -185,11 +185,11 @@ in
};

import-tree."test does not break if given a path to a file instead of a directory." = {
expr = lit.leafs ./tree/x/y.nix;
expr = lit.leaves ./tree/x/y.nix;
expected = [ ./tree/x/y.nix ];
};

import-tree."test returns a module with a single imported nested module having leafs" = {
import-tree."test returns a module with a single imported nested module having leaves" = {
expr =
let
oneElement = arr: if lib.length arr == 1 then lib.elemAt arr 0 else throw "Expected one element";
Expand Down Expand Up @@ -219,7 +219,7 @@ in
};

import-tree."test take as arg anything path convertible" = {
expr = lit.leafs [
expr = lit.leaves [
{
outPath = ./tree/modules/hello-world;
}
Expand All @@ -245,7 +245,7 @@ in
};

import-tree."test can take other import-trees as if they were paths" = {
expr = (lit.filter (lib.hasInfix "mod")).leafs [
expr = (lit.filter (lib.hasInfix "mod")).leaves [
(it.addPath ./tree/modules/hello-option)
./tree/modules/hello-world
];
Expand All @@ -255,8 +255,8 @@ in
];
};

leafs."test loads from hidden directory but excludes sub-hidden" = {
expr = lit.leafs ./tree/a/b/_c;
leaves."test loads from hidden directory but excludes sub-hidden" = {
expr = lit.leaves ./tree/a/b/_c;
expected = [ ./tree/a/b/_c/d/e.nix ];
};

Expand All @@ -271,7 +271,7 @@ in
};

combinator."test combinator syntax to compose import-tree" = {
expr = it (it: it.withLib lib) (it: it.leafs) ./tree/_scoped;
expr = it (it: it.withLib lib) (it: it.leaves) ./tree/_scoped;
expected = [ ./tree/_scoped/foo.nix ];
};
};
Expand Down
Loading