diff --git a/src/test/dart_class_parser.test.ts b/src/test/dart_class_parser.test.ts index 9079014..9745a0c 100644 --- a/src/test/dart_class_parser.test.ts +++ b/src/test/dart_class_parser.test.ts @@ -726,6 +726,39 @@ describe("parseLinesToConstructors", () => { ), ]); }); + + test("with complicated expressions in initializer list", () => { + const lines = [ + " Loader.small(", + " this.active, {", + " super.key,", + " bool big = false,", + " required bool animated,", + " }) : semanticsLabel = List.filled(40, '*').join()", + ]; + const classFields = [ + new DartClassField("active", "bool"), + new DartClassField("semanticsLabel", "String"), + new DartClassField("text", "String"), + new DartClassField("icon", "IconData"), + ]; + + expect(parseLinesToConstructors(lines, "Loader", classFields)).toEqual([ + new DartClassConstructor( + true, + [ + new DartClassConstructorField( + "active", + "bool", + DartClassConstructorFieldPositionType.positional + ), + new DartClassConstructorField("big", "bool"), + new DartClassConstructorField("animated", "bool"), + ], + "small" + ), + ]); + }); }); describe("factory constructor", () => { diff --git a/src/util/dart_class_parser.ts b/src/util/dart_class_parser.ts index 4f4c7dc..b66d6c7 100644 --- a/src/util/dart_class_parser.ts +++ b/src/util/dart_class_parser.ts @@ -128,7 +128,11 @@ function parseLinesToConstructors( for (let j = i; j < lines.length; j++) { for (const char of lines[j]) { if (char === "(") openParenthesisCount++; - else if (char === ")") openParenthesisCount--; + else if (char === ")") { + openParenthesisCount--; + // Exit as soon as the initial parenthesis block is closed. + if (openParenthesisCount == 0) break; + } } if (openParenthesisCount > 0 && !lines[j].includes("assert(")) { continue; @@ -165,8 +169,22 @@ function parseLinesToConstructor( ): DartClassConstructor | null { if (!lines.length) return null; const classFieldReference = "this."; + let namedParametersStartIndex = lines.findIndex((line) => line.includes("{")); + if (namedParametersStartIndex === -1) { + // No named params. Set to infinity for the check for positionType below. + namedParametersStartIndex = Infinity; + } else { + // Index will change after we pop name line below. + namedParametersStartIndex--; + } + const nameLine = lines.shift() as string; + if (lines.length > 0) { + // Remove constructor ending. No field would be defined in this line. + lines.pop(); + } + const named = nameLine.includes(`${className}.`); const constructorName = named ? nameLine.substring(nameLine.indexOf(".") + 1, nameLine.indexOf("(")) @@ -177,14 +195,16 @@ function parseLinesToConstructor( .split(",") // TODO Modify the line below when adding support for one-line constructors .filter((line) => line !== "" && !line.includes("})")); - const namedParametersStartIndex = fieldsLines.findIndex((line) => - line.includes("{") - ); const fields = fieldsLines .map((line) => { // Check some possible cases that would discard this line as one representing a field. - if (line.includes("super.") || line.includes(") {")) return null; + if ( + line.includes("super.") || + line.includes(") {") || + line.includes("})") + ) + return null; const positionType = fieldsLines.indexOf(line) > namedParametersStartIndex @@ -193,27 +213,7 @@ function parseLinesToConstructor( const custom = !line.includes(classFieldReference); if (custom) { - const lineParts = line.trim().split(" "); - let name: string; - let type: string; - if (lineParts[0] === "required") { - name = lineParts[2]; - type = lineParts[1]; - } else { - name = lineParts[1]; - type = lineParts[0]; - } - - if (type.endsWith("?")) { - return new DartClassConstructorField( - name, - type.removeTrailing(1), - positionType, - true - ); - } - - return new DartClassConstructorField(name, type, positionType, false); + return getCustomConstructorField(line, positionType); } else { const fieldName = getClassFieldName(line, classFieldReference); const classField = allClassFields.find( @@ -236,6 +236,33 @@ function parseLinesToConstructor( ); } +function getCustomConstructorField( + line: string, + positionType: DartClassConstructorFieldPositionType +): DartClassConstructorField { + const lineParts = line.trim().split(" "); + let name: string; + let type: string; + if (lineParts[0] === "required") { + name = lineParts[2]; + type = lineParts[1]; + } else { + name = lineParts[1]; + type = lineParts[0]; + } + + if (type.endsWith("?")) { + return new DartClassConstructorField( + name, + type.removeTrailing(1), + positionType, + true + ); + } + + return new DartClassConstructorField(name, type, positionType, false); +} + function classFieldToConstructorField( classField: DartClassField, positionType: DartClassConstructorFieldPositionType