MCPcopy
hub / github.com/remeda/remeda / stringToPath

Function stringToPath

packages/remeda/src/stringToPath.ts:90–140  ·  view source on GitHub ↗
(
  path: Path,
)

Source from the content-addressed store, hash-verified

88 * @category Utility
89 */
90export function stringToPath<const Path extends string>(
91 path: Path,
92): StringToPath<Path> {
93 const result: (string | number)[] = [];
94
95 // There are four possible ways to define a path segment::
96 // - `propName`: is used to parse dot-notation paths, e.g. 'foo.bar.baz', we
97 // allow multiple sequential dots because our type allows them, but they are
98 // semantically meaningless. Note that this would also allow strings starting
99 // with a dot, e.g. `.foo`, this is fine because the dot itself is just used
100 // as a separator and is ignored in the final path.
101 // - `quoted`, `doubleQuoted`: used within square bracket notation to prevent
102 // any recursive parsing of their contents. As for the type itself, we only
103 // allow quote symbols to appear immediately after the opening square bracket
104 // and immediately before the closing square bracket, this allows us to handle
105 // more gracefully cases where a quote symbol might appear within the quoted
106 // part.
107 // - `unquoted`: If the contents of the square brackets are not quoted they
108 // will match this group (this is why the order is important here!). Contents
109 // of this group get parsed *recursively*.
110 //
111 // NOTE: We limit all repeats to 4096 characters to avoid a possible attack
112 // vector when the input to this function is controlled by the user. This is
113 // due to a DoS timing attack because regex backtracking is non-linear.
114 // @see: https://codeql.github.com/codeql-query-help/javascript/js-polynomial-redos/
115 const pathSegmentRe =
116 /\.{0,4096}(?<propName>[^.[\]]+)|\['(?<quoted>.{0,4096}?)'\]|\["(?<doubleQuoted>.{0,4096}?)"\]|\[(?<unquoted>.{0,4096}?)\]/uy;
117
118 let match: RegExpExecArray | null;
119 while ((match = pathSegmentRe.exec(path)) !== null) {
120 const { propName, quoted, doubleQuoted, unquoted } = match.groups!;
121
122 if (unquoted !== undefined) {
123 result.push(...stringToPath(unquoted));
124 continue;
125 }
126
127 result.push(
128 propName === undefined
129 ? (quoted ?? doubleQuoted!)
130 : // The only way to differentiate between array indices and properties
131 // is to check if the property is a non-negative integer. In those
132 // cases we perform the conversion (unlike Lodash).
133 NON_NEGATIVE_INTEGER_RE.test(propName)
134 ? Number(propName)
135 : propName,
136 );
137 }
138
139 return result;
140}

Callers 5

pathOr.test-d.tsFile · 0.90
setPath.test.tsFile · 0.90
prop.test-d.tsFile · 0.90

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…