Skip to content

Commit

Permalink
Add leaves
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Mar 13, 2022
1 parent 02e1ebd commit c09047c
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 9 deletions.
3 changes: 2 additions & 1 deletion src/config/normalize/lib/wild_wild_path/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import { iterate } from './iterate/main.js'
export const list = function (
target,
query,
{ childFirst, roots, sort, missing, classes, inherited } = {},
{ childFirst, roots, leaves, sort, missing, classes, inherited } = {},
) {
return [
...iterate(target, query, {
childFirst,
roots,
leaves,
sort,
missing,
classes,
Expand Down
70 changes: 62 additions & 8 deletions src/config/normalize/lib/wild_wild_path/iterate/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@ export const iterate = function* (
{
childFirst = false,
roots = false,
leaves = false,
sort = false,
missing = false,
classes = false,
inherited = false,
} = {},
) {
const opts = { childFirst, roots, sort, missing, classes, inherited }
const opts = {
childFirst: childFirst || leaves,
roots,
leaves,
sort,
missing,
classes,
inherited,
}
validateInherited(opts)
const parents = new Set([])
const queryArrays = parseQuery(query)
Expand Down Expand Up @@ -59,22 +68,27 @@ const iterateLevel = function* ({
parents.delete(value)
}

// The `roots` option can be used to only include the highest ancestors
// eslint-disable-next-line complexity
// The `roots` option can be used to only include the highest ancestors.
// The `leaves` option can be used to only include the lowest descendants.
// Neither option includes the values in-between.
const iterateToken = function* ({ entries, index, parents, opts }) {
const entriesA = expandRecursiveTokens(entries, index)
const entriesB = removeDuplicates(entriesA)
const parentEntry = getParentEntry(entriesB, index)

if (parentEntry !== undefined && !opts.childFirst) {
if (shouldYieldParentFirst(parentEntry, opts)) {
yield normalizeEntry(parentEntry)
}

if (parentEntry === undefined || (entriesB.length !== 1 && !opts.roots)) {
yield* iterateChildren({ entries: entriesB, index, parents, opts })
}
const hasChildren = yield* iterateChildEntries({
entries: entriesB,
parentEntry,
index,
parents,
opts,
})

if (parentEntry !== undefined && opts.childFirst) {
if (shouldYieldParentLast(parentEntry, hasChildren, opts)) {
yield normalizeEntry(parentEntry)
}
}
Expand All @@ -83,11 +97,51 @@ const getParentEntry = function (entries, index) {
return entries.find(({ queryArray }) => queryArray.length === index)
}

const shouldYieldParentFirst = function (parentEntry, { childFirst }) {
return parentEntry !== undefined && !childFirst
}

const shouldYieldParentLast = function (
parentEntry,
hasChildren,
{ childFirst, leaves },
) {
return parentEntry !== undefined && childFirst && !(leaves && hasChildren)
}

const normalizeEntry = function ({ value, path, missing }) {
const query = serializePath(path)
return { value, path, query, missing }
}

const iterateChildEntries = function* ({
entries,
parentEntry,
index,
parents,
opts,
}) {
if (!shouldIterateChildren(entries, parentEntry, opts)) {
return false
}

// eslint-disable-next-line fp/no-let
let hasChildren = false

// eslint-disable-next-line fp/no-loops
for (const childEntry of iterateChildren({ entries, index, parents, opts })) {
// eslint-disable-next-line fp/no-mutation
hasChildren = true
yield childEntry
}

return hasChildren
}

const shouldIterateChildren = function (entries, parentEntry, { roots }) {
return parentEntry === undefined || (entries.length !== 1 && !roots)
}

const iterateChildren = function* ({ entries, index, parents, opts }) {
const childEntries = expandTokens(entries, index, opts)

Expand Down

0 comments on commit c09047c

Please sign in to comment.