| 20 | } |
| 21 | |
| 22 | const parseKeys = key => { |
| 23 | const sqBracketItems = new Set() |
| 24 | sqBracketItems.add(_append) |
| 25 | const parseSqBrackets = str => { |
| 26 | const index = sqBracketsMatcher(str) |
| 27 | |
| 28 | // once we find square brackets, we recursively parse all these |
| 29 | if (index) { |
| 30 | const preSqBracketPortion = index[1] |
| 31 | |
| 32 | // we want to have a `new String` wrapper here in order to differentiate between multiple occurrences of the same string, |
| 33 | // e.g: foo.bar[foo.bar] should split into { foo: { bar: { 'foo.bar': {} } } |
| 34 | /* eslint-disable-next-line no-new-wrappers */ |
| 35 | const foundKey = new String(index[2]) |
| 36 | const postSqBracketPortion = index[3] |
| 37 | |
| 38 | // we keep track of items found during this step to make sure we don't try to split-separate keys that were defined within square brackets, since the key name itself might contain dots |
| 39 | sqBracketItems.add(foundKey) |
| 40 | |
| 41 | // returns an array that contains either dot-separate items (that will be split apart during the next step OR the fully parsed keys read from square brackets |
| 42 | // e.g: foo.bar[1.0.0].a.b -> ['foo.bar', '1.0.0', 'a.b'] |
| 43 | return [ |
| 44 | ...parseSqBrackets(preSqBracketPortion), |
| 45 | foundKey, |
| 46 | ...(postSqBracketPortion ? parseSqBrackets(postSqBracketPortion) : []), |
| 47 | ] |
| 48 | } |
| 49 | |
| 50 | // at the end of parsing, any usage of the special empty-bracket syntax (e.g: foo.array[]) has not yet been parsed |
| 51 | // here we'll take care of parsing it and adding a special symbol to represent it in the resulting list of keys |
| 52 | return replaceAppendSymbols(str) |
| 53 | } |
| 54 | |
| 55 | const res = [] |
| 56 | // starts by parsing items defined as square brackets |
| 57 | // those might be representing properties that have a dot in the name or just array indexes |
| 58 | // e.g: foo[1.0.0] or list[0] |
| 59 | const sqBracketKeys = parseSqBrackets(key.trim()) |
| 60 | |
| 61 | for (const k of sqBracketKeys) { |
| 62 | // keys parsed from square brackets should just be added to list of resulting keys as they might have dots as part of the key |
| 63 | if (sqBracketItems.has(k)) { |
| 64 | res.push(k) |
| 65 | } else { |
| 66 | // splits the dot-sep property names and add them to the list of keys |
| 67 | /* eslint-disable-next-line no-new-wrappers */ |
| 68 | for (const splitKey of k.split('.')) { |
| 69 | res.push(String(splitKey)) |
| 70 | } |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | // returns an ordered list of strings in which each entry represents a key in an object defined by the previous entry |
| 75 | return res |
| 76 | } |
| 77 | |
| 78 | const getter = ({ data, key }, { unwrapSingleItemArrays = true } = {}) => { |
| 79 | // keys are a list in which each entry represents the name of a property that should be walked through the object in order to return the final found value |