Skip to content

Commit

Permalink
Prevent infinite recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Mar 13, 2022
1 parent d053c1e commit adf3913
Showing 1 changed file with 42 additions and 8 deletions.
50 changes: 42 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 @@ -15,6 +15,7 @@ export const iterate = function* (
query,
{ childFirst = false, sort = false, classes = false } = {},
) {
const parents = new Set([])
const opts = { childFirst, sort, classes }
const queryArrays = parseQuery(query)
const entries = queryArrays.map((queryArray) => ({
Expand All @@ -23,10 +24,24 @@ export const iterate = function* (
path: [],
missing: false,
}))
yield* iterateLevel(entries, 0, opts)
yield* iterateLevel({ entries, index: 0, parents, opts })
}

const iterateLevel = function* (entries, index, opts) {
// `parents` is used to prevent infinite recursions when using ** together with
// a value that includes references to itself
const iterateLevel = function* ({
entries,
entries: [{ value }],
index,
parents,
opts,
}) {
if (parents.has(value)) {
return
}

parents.add(value)

const entriesA = expandRecursiveTokens(entries, index)
const entriesB = removeDuplicates(entriesA)
const parentEntry = getParentEntry(entriesB, index)
Expand All @@ -35,11 +50,19 @@ const iterateLevel = function* (entries, index, opts) {
yield parentEntry
}

yield* iterateChildEntries({ entries: entriesB, parentEntry, index, opts })
yield* iterateChildEntries({
entries: entriesB,
parentEntry,
index,
parents,
opts,
})

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

parents.delete(value)
}

const getParentEntry = function (entries, index) {
Expand All @@ -54,7 +77,13 @@ const normalizeEntry = function ({ value, path, missing }) {
return { value, path, query, missing }
}

const iterateChildEntries = function* ({ entries, parentEntry, index, opts }) {
const iterateChildEntries = function* ({
entries,
parentEntry,
index,
parents,
opts,
}) {
if (parentEntry !== undefined && entries.length === 1) {
return
}
Expand All @@ -65,21 +94,26 @@ const iterateChildEntries = function* ({ entries, parentEntry, index, opts }) {
return
}

yield* iterateChildren(childEntries, index, opts)
yield* iterateChildren({ childEntries, index, parents, opts })
}

const iterateChildren = function* (childEntries, index, opts) {
const iterateChildren = function* ({ childEntries, index, parents, opts }) {
const nextIndex = index + 1

if (childEntries.length === 1) {
yield* iterateLevel(childEntries, nextIndex, opts)
yield* iterateLevel({
entries: childEntries,
index: nextIndex,
parents,
opts,
})
return
}

const childEntriesGroups = groupSortChildEntries(childEntries, opts.sort)

// eslint-disable-next-line fp/no-loops
for (const entries of childEntriesGroups) {
yield* iterateLevel(entries, nextIndex, opts)
yield* iterateLevel({ entries, index: nextIndex, parents, opts })
}
}

0 comments on commit adf3913

Please sign in to comment.