(funcString: string)
| 134 | } |
| 135 | |
| 136 | function parseFunctionCode(funcString: string): [string, ParsedFunctionCode] { |
| 137 | if (funcString.startsWith('[Function:')) { |
| 138 | return [`the function form was not understood.`, undefined as any]; |
| 139 | } |
| 140 | |
| 141 | // Split this constant out so that if this function *itself* is closure serialized, |
| 142 | // it will not be thought to be native code itself. |
| 143 | const nativeCodeString = '[native ' + 'code]'; |
| 144 | if (funcString.indexOf(nativeCodeString) !== -1) { |
| 145 | return ['Native code functions cannot be inspected.', undefined as any]; |
| 146 | } |
| 147 | |
| 148 | // There are three general forms of node toString'ed Functions we're trying to find out here. |
| 149 | // |
| 150 | // 1. `[mods] (...) => ... |
| 151 | // |
| 152 | // i.e. an arrow function. We need to ensure that arrow-functions stay arrow-functions, |
| 153 | // and non-arrow-functions end up looking like normal `function` functions. This will make |
| 154 | // it so that we can correctly handle 'this' properly depending on if that should be |
| 155 | // treated as the lexical capture of 'this' or the non-lexical 'this'. |
| 156 | // |
| 157 | // 2. `class Foo { ... }` |
| 158 | // |
| 159 | // i.e. node uses the entire string of a class when toString'ing the constructor function |
| 160 | // for it. |
| 161 | // |
| 162 | // 3. `[mods] function ... |
| 163 | // |
| 164 | // i.e. a normal function (maybe async, maybe a get/set function, but def not an arrow |
| 165 | // function) |
| 166 | |
| 167 | if (tryParseAsArrowFunction(funcString)) { |
| 168 | return ['', { funcExprWithoutName: funcString, isArrowFunction: true }]; |
| 169 | } |
| 170 | |
| 171 | // First check to see if this startsWith 'class'. If so, this is definitely a class. This |
| 172 | // works as Node does not place preceding comments on a class/function, allowing us to just |
| 173 | // directly see if we've started with the right text. |
| 174 | if (funcString.startsWith('class ')) { |
| 175 | // class constructor function. We want to get the actual constructor |
| 176 | // in the class definition (synthesizing an empty one if one does not) |
| 177 | // exist. |
| 178 | const [file, firstDiagnostic] = tryCreateSourceFile(funcString); |
| 179 | if (firstDiagnostic) { |
| 180 | return [`the class could not be parsed: ${firstDiagnostic}`, undefined as any]; |
| 181 | } |
| 182 | |
| 183 | const classDecl = file!.statements.find((x) => ts.isClassDeclaration(x)) as ts.ClassDeclaration; |
| 184 | if (!classDecl) { |
| 185 | return [`the class form was not understood:\n${funcString}`, undefined as any]; |
| 186 | } |
| 187 | |
| 188 | const constructor = classDecl.members.find((m) => |
| 189 | ts.isConstructorDeclaration(m) |
| 190 | ) as ts.ConstructorDeclaration; |
| 191 | if (!constructor) { |
| 192 | // class without explicit constructor. |
| 193 | const isSubClass = classDecl.heritageClauses?.some( |
no test coverage detected