diff --git a/internal/files/search.go b/internal/files/search.go index 27b6a7f..2487182 100644 --- a/internal/files/search.go +++ b/internal/files/search.go @@ -19,7 +19,7 @@ func GetFlagType(defaultValue string) (string, string) { var flagType string = "string" var flagTypeInterface interface{} - r, _ := regexp.Compile(`[^\w#]`) + r, _ := regexp.Compile(`[\{\}\[\]]`) json.Unmarshal([]byte(defaultValue), &flagTypeInterface) @@ -27,8 +27,7 @@ func GetFlagType(defaultValue string) (string, string) { flagType = "unknown" } - if defaultValue[0:1] == "\"" { - defaultValue = strings.Trim(defaultValue, "\"") + if (defaultValue[0:1] == "\"" || defaultValue[0:1] == "'") && (defaultValue[len(defaultValue)-1:] == "\"" || defaultValue[len(defaultValue)-1:] == "'") { flagType = "string" } @@ -86,30 +85,34 @@ func SearchFiles(cfg *config.Config, path string, resultChannel chan model.FileS // Add default regex for flags in commentaries flagRegexes = append(flagRegexes, model.FlagRegex{ - FunctionRegex: `(?s)fs:flag:(\w+)`, - FieldRegex: `fs:flag:(.+)`, + FieldRegex: `fs:flag:(.+)`, }) results := []model.SearchResult{} flagIndexes := [][]int{} for _, flagRegex := range flagRegexes { - regxp := regexp.MustCompile(flagRegex.FunctionRegex) + regxp := regexp.MustCompile(flagRegex.FieldRegex) flagLineIndexes := regxp.FindAllStringIndex(fileContentStr, -1) for _, flagLineIndex := range flagLineIndexes { submatch := fileContentStr[flagLineIndex[0]:flagLineIndex[1]] - regxp := regexp.MustCompile(flagRegex.FieldRegex) submatchIndexes := regxp.FindAllStringSubmatchIndex(submatch, -1) - for k, submatchIndex := range submatchIndexes { - if len(submatchIndex) < 6 { + for _, submatchIndex := range submatchIndexes { + if len(submatchIndex) < 3 { log.Printf("Did not find the flag key in file %s. Code : %s", path, submatch) continue } - if !flagRegex.HasMultipleKeys && k > 0 { - break + + if len(submatchIndex) < 6 { + log.Printf("Did not find the flag default value in file %s. Code : %s", path, submatch) + flagIndexes = append(flagIndexes, []int{ + flagLineIndex[0] + submatchIndex[2], + flagLineIndex[0] + submatchIndex[3], + }) + continue } flagIndexes = append(flagIndexes, []int{ @@ -124,11 +127,18 @@ func SearchFiles(cfg *config.Config, path string, resultChannel chan model.FileS for _, flagIndex := range flagIndexes { // Extract the code with a certain number of lines + defaultValue_ := "" + flagType := "unknown" firstLineIndex := getSurroundingLineIndex(fileContentStr, flagIndex[0], true, cfg.NbLineCodeEdges) lastLineIndex := getSurroundingLineIndex(fileContentStr, flagIndex[1], false, cfg.NbLineCodeEdges) code := fileContentStr[firstLineIndex:lastLineIndex] key := fileContentStr[flagIndex[0]:flagIndex[1]] - defaultValue := fileContentStr[flagIndex[2]:flagIndex[3]] + + if len(flagIndex) >= 3 { + defaultValue := fileContentStr[flagIndex[2]:flagIndex[3]] + flagType, defaultValue_ = GetFlagType(defaultValue) + } + // Better value wrapper for code highlighting (5 chars wrapping) keyWrapper := key nbCharsWrapping := 5 @@ -139,8 +149,6 @@ func SearchFiles(cfg *config.Config, path string, resultChannel chan model.FileS lineNumber := getLineFromPos(fileContentStr, flagIndex[0]) codeLineHighlight := getLineFromPos(code, strings.Index(code, keyWrapper)) - flagType, defaultValue_ := GetFlagType(defaultValue) - results = append(results, model.SearchResult{ FlagKey: key, FlagDefaultValue: defaultValue_, diff --git a/internal/files/search_test.go b/internal/files/search_test.go index 79c3581..d488f73 100644 --- a/internal/files/search_test.go +++ b/internal/files/search_test.go @@ -65,14 +65,14 @@ func TestSearchFiles(t *testing.T) { {name: "btnSizeInt", lineNumber: 25, codeLineHighlight: 6}, }, }, - /* { + { filePath: "../../example/src/ios/SDK_V3/sample.swift", flags: []flag{ - {name: "btnColor", lineNumber: 9, codeLineHighlight: 5}, - {name: "displayVipFeature", lineNumber: 10, codeLineHighlight: 5}, - {name: "vipFeature", lineNumber: 11, codeLineHighlight: 5}, + {name: "btnColor", lineNumber: 9, codeLineHighlight: 6}, + {name: "displayVipFeature", lineNumber: 10, codeLineHighlight: 6}, + {name: "vipFeature", lineNumber: 11, codeLineHighlight: 6}, }, - }, */ + }, { filePath: "../../example/src/java/SDK_V2/sample.java", flags: []flag{ diff --git a/internal/model/language_regexes.go b/internal/model/language_regexes.go index 29c810f..7d34d70 100644 --- a/internal/model/language_regexes.go +++ b/internal/model/language_regexes.go @@ -11,9 +11,7 @@ type LanguageRegex struct { } type FlagRegex struct { - FunctionRegex string `json:"function_regex"` - FieldRegex string `json:"field_regex"` - HasMultipleKeys bool `json:"has_multiple_keys"` + FieldRegex string `json:"field_regex"` } var LanguageRegexes = []LanguageRegex{ @@ -21,24 +19,13 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.[jt]sx?$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)useFsModifications\(.+?\)`, // SDK React V2 - FieldRegex: `['"]?key['"]?\s*\:\s*['"](.+?)['"](?:.*\s*)['"]?defaultValue['"]?\s*\:\s*['"]?(.+?)['"]?\s*[\"\,]`, - HasMultipleKeys: true, + FieldRegex: `useFsFlag[(](?:\s*['"](.*)['"]\s*,\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK React V3 }, { - FunctionRegex: `(?s)useFsFlag\(.+?\)`, // SDK React V3 - FieldRegex: `useFsFlag\(['"]?\s*(.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)]`, - HasMultipleKeys: true, + FieldRegex: `['"]?key['"]?\s*\:\s*['"](.+?)['"](?:.*\s*)['"]?defaultValue['"]?\s*\:\s*(['"].*['"]|[^\r\n\t\f\v,}]+).*[},]?`, // SDK JS V2 && SDK React V2 }, { - FunctionRegex: `(?s)\.getModifications\(.+?\].+?\)`, // SDK JS V2 - FieldRegex: `['"]?key['"]?\s*\:\s*['"](.+?)['"](?:.*\s*)['"]?defaultValue['"]?\s*\:\s*['"]?(.+?)['"]?\s*[\"\,]`, - HasMultipleKeys: true, - }, - { - FunctionRegex: `(?s)getFlag\(.+?\)`, // SDK JS V3 - FieldRegex: `getFlag\(['"]?\s*(.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)\,]`, - HasMultipleKeys: true, + FieldRegex: `getFlag[(](?:\s*["'](.*)["']\s*,\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK JS V3 }, }, }, @@ -46,8 +33,7 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.go$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.GetModification(String|Number|Bool|Object|Array)\(.+?\)`, // SDK GO V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\,]`, + FieldRegex: `\.GetModification(?:String|Number|Bool|Object|Array)\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK GO V2 }, }, }, @@ -55,8 +41,7 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.py$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.get_modification\(.+?\)`, // SDK PYTHON V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.get_modification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|True|False|\d+|"[^"]*"))?\s*\)`, // SDK PYTHON V2 }, }, }, @@ -64,12 +49,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.java$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.getModification\(.+?\)`, // SDK JAVA V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.getModification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK JAVA V2 }, { - FunctionRegex: `(?s)\.getFlag\(.+?\)`, // SDK JAVA V3 - FieldRegex: `(?s)\.getFlag\(['"](.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)\,]`, + FieldRegex: `\.getFlag[(](?:\s*["'](.*)["']\s*,\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK JAVA V3 }, }, }, @@ -77,12 +60,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.php$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\-\>getModification\(.+?\)`, // SDK PHP V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\-\>getModification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK PHP V1 && SDK PHP V2 }, { - FunctionRegex: `(?s)\-\>getFlag\(.+?\)`, // SDK PHP V3 - FieldRegex: `(?s)\-\>getFlag\(['"](.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)\,]`, + FieldRegex: `\-\>getFlag[(](?:\s*["'](.*)["']\s*,\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK PHP V3 }, }, }, @@ -90,12 +71,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.kt$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.getModification\(.+?\)`, // SDK ANDROID V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.getModification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK ANDROID V2 }, { - FunctionRegex: `(?s)\.getFlag\(.+?\)`, // SDK ANDROID V3 - FieldRegex: `(?s)\.getFlag\(['"](.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)\,]`, + FieldRegex: `\.getFlag[(](?:\s*["'](.*)["']\s*,\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK ANDROID V3 }, }, }, @@ -103,12 +82,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.swift$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.getModification\(.+?\)`, // SDK iOS V2 - FieldRegex: `\s*['"](.+?)['"](?:,\s*)['"]?default(?:String|Double|Bool|Float|Int|Json|Array)['"]?\s*\:\s*['"]?(.+?)['"]?\s*[\"\,]`, + FieldRegex: `\.getModification\(\s*["'](\w+)['"]\s*,\s*default(?:String|Double|Float|Int|Bool|Json|Array)\s*:\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)\s*(?:,\s*activate\s*:\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK iOS V2 }, { - FunctionRegex: `(?s)\.getFlag\(key: ['"](.+?)['"]`, // SDK iOS V3 - FieldRegex: `['"]?key['"]?\s*\:\s*['"](.+?)['"](?:.*\s*)['"]?defaultValue['"]?\s*\:\s*['"]?(.+?)['"]?\s*[\)]`, + FieldRegex: `\.getFlag[(]\s*key\s*:\s*(?:\s*["'](.*)["']\s*,\s*defaultValue\s*:\s*(["'].*\s*[^"]*["']|[^)]*))\s*[)]`, // SDK iOS V3 }, }, }, @@ -116,12 +93,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.m$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\]\s*getModification:@.+?\]`, // SDK iOS V2 - FieldRegex: `\s*['"](.+?)['"](?:\s*)default(?:String|Double|Bool|Float|Int|Json|Array):\@?\s*(['"](.+?)['"]|YES|NO|TRUE|FALSE|true|false|\d*\.?\d+)?`, + FieldRegex: `getModification\s*:\s*@\s*['"](.+?)['"](?:\s*)default(?:String|Double|Bool|Float|Int|Json|Array):\@?\s*(['"].+?['"]|YES|NO|TRUE|FALSE|true|false|[+-]?(?:\d*[.])?\d+)?`, // SDK iOS V2 }, { - FunctionRegex: `(?s)\s*getFlagWithKey:@.+?\]`, // SDK iOS V3 - FieldRegex: `\s*getFlagWithKey:@['"](.+?)['"](?:\s*)['"]?defaultValue['"]?\s*\:\@?\s*['"]?(.+?)['"]?\s*[\]]`, + FieldRegex: `getFlagWithKey\s*:\s*\@['"](.+?)['"](?:\s*)['"]?defaultValue['"]?\s*\:\s*\@?\s*(.+?)\s*[\]]`, // SDK iOS V3 }, }, }, @@ -129,12 +104,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.[fc]s$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.GetModification\(.+?\)`, // SDK .NET V1 - FieldRegex: `(?s)\.GetModification\(['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.GetModification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK .NET V1 }, { - FunctionRegex: `(?s)\.GetFlag\(.+?\)`, // SDK .NET V3 - FieldRegex: `(?s)\.GetFlag\(['"](.+?)['"](?:.\s*)['"]?(.+?)['"]?\s*[\"\)\,]`, + FieldRegex: `\.GetFlag\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK .NET V3 }, }, }, @@ -142,12 +115,10 @@ var LanguageRegexes = []LanguageRegex{ ExtensionRegex: `\.vb$`, FlagRegexes: []FlagRegex{ { - FunctionRegex: `(?s)\.GetModification\(.+?\)`, // SDK .NET V1 - FieldRegex: `(?s)\.GetModification\(['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.GetModification\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|True|false|False|\d+|"[^"]*"))?\s*\)`, // SDK .NET V1 }, { - FunctionRegex: `(?s)\.GetFlag\(.+?\)`, // SDK .NET V3 - FieldRegex: `(?s)\.GetFlag\(['"](.+?)['"](?:,\s*)['"]?(.+?)['"]?\s*[\)\,]`, + FieldRegex: `\.GetFlag\(\s*["']([\w\-]+)['"]\s*,\s*(["'][^"]*['"]|[+-]?(?:\d*[.])?\d+|true|false|False|True)(?:\s*,\s*(?:true|false|\d+|"[^"]*"))?\s*\)`, // SDK .NET V3 }, }, }, diff --git a/internal/model/language_regexes_test.go b/internal/model/language_regexes_test.go index 7c3ded4..d96ae06 100644 --- a/internal/model/language_regexes_test.go +++ b/internal/model/language_regexes_test.go @@ -8,7 +8,7 @@ import ( ) func TestCustomRegex(t *testing.T) { - AddCustomRegexes(`[{"extension_regex":".tsx?","flag_regexes":[{"function_regex":"(?s)useFlagShipActivation\\(.+?\\)","field_regex":"\\s*['\"](.+?)['\"]","has_multiple_keys":true}]}]`) + AddCustomRegexes(`[{"extension_regex":".tsx?","flag_regexes":[{"field_regex":"\\s*['\"](.+?)['\"]"}]}]`) found := funk.Find(LanguageRegexes, func(languageRegex LanguageRegex) bool { return languageRegex.ExtensionRegex == ".tsx?" @@ -22,7 +22,5 @@ func TestCustomRegex(t *testing.T) { assert.Equal(t, ".tsx?", foundLanguageRegex.ExtensionRegex) assert.Equal(t, 1, len(foundLanguageRegex.FlagRegexes)) - assert.Equal(t, "(?s)useFlagShipActivation\\(.+?\\)", foundLanguageRegex.FlagRegexes[0].FunctionRegex) assert.Equal(t, "\\s*['\"](.+?)['\"]", foundLanguageRegex.FlagRegexes[0].FieldRegex) - assert.Equal(t, true, foundLanguageRegex.FlagRegexes[0].HasMultipleKeys) }