[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Jeremy Wohl\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "flatten\n=======\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/jeremywohl/flatten.svg)](https://pkg.go.dev/github.com/jeremywohl/flatten)\n\n**Note: development continues in [v2](/v2)**\n\nFlatten makes flat, one-dimensional maps from arbitrarily nested ones.\n\nIt turns map keys into compound\nnames, in four default styles: dotted (`a.b.1.c`), path-like (`a/b/1/c`), Rails (`a[b][1][c]`), or with underscores (`a_b_1_c`).  Alternatively, you can pass a custom style.\n\nIt takes input as either JSON strings or\nGo structures.  It knows how to traverse these JSON types: objects/maps, arrays and scalars.\n\nYou can flatten JSON strings.\n\n```go\nnested := `{\n  \"one\": {\n    \"two\": [\n      \"2a\",\n      \"2b\"\n    ]\n  },\n  \"side\": \"value\"\n}`\n\nflat, err := flatten.FlattenString(nested, \"\", flatten.DotStyle)\n\n// output: `{ \"one.two.0\": \"2a\", \"one.two.1\": \"2b\", \"side\": \"value\" }`\n```\n\nOr Go maps directly.\n\n```go\nnested := map[string]interface{}{\n   \"a\": \"b\",\n   \"c\": map[string]interface{}{\n       \"d\": \"e\",\n       \"f\": \"g\",\n   },\n   \"z\": 1.4567,\n}\n\nflat, err := flatten.Flatten(nested, \"\", flatten.RailsStyle)\n\n// output:\n// map[string]interface{}{\n//  \"a\":    \"b\",\n//  \"c[d]\": \"e\",\n//  \"c[f]\": \"g\",\n//  \"z\":    1.4567,\n// }\n```\n\nLet's try a custom style, with the first example above.\n\n```go\nemdash := flatten.SeparatorStyle{Middle: \"--\"}\nflat, err := flatten.FlattenString(nested, \"\", emdash)\n\n// output: `{ \"one--two--0\": \"2a\", \"one--two--1\": \"2b\", \"side\": \"value\" }`\n```\n\nSee [godoc](https://godoc.org/github.com/jeremywohl/flatten) for API.\n"
  },
  {
    "path": "TODO",
    "content": "test: all Go scalar types\ntodo: initial list vs map\ntodo: fail properly with alternate types\ntodo: support structs and pointers?\n"
  },
  {
    "path": "doc.go",
    "content": "// Flatten makes flat, one-dimensional maps from arbitrarily nested ones.\n//\n// It turns map keys into compound\n// names, in four default styles: dotted (`a.b.1.c`), path-like (`a/b/1/c`), Rails (`a[b][1][c]`),\n// or with underscores (`a_b_1_c`).  Alternatively, you can pass a custom style.\n//\n// It takes input as either JSON strings or\n// Go structures.  It knows how to traverse these JSON types: objects/maps, arrays and scalars.\n//\n// You can flatten JSON strings.\n//\n//\tnested := `{\n//\t  \"one\": {\n//\t    \"two\": [\n//\t      \"2a\",\n//\t      \"2b\"\n//\t    ]\n//\t  },\n//\t  \"side\": \"value\"\n//\t}`\n//\n//\tflat, err := flatten.FlattenString(nested, \"\", flatten.DotStyle)\n//\n//\t// output: `{ \"one.two.0\": \"2a\", \"one.two.1\": \"2b\", \"side\": \"value\" }`\n//\n// Or Go maps directly.\n//\n//\tnested := map[string]interface{}{\n//\t\t\"a\": \"b\",\n//\t\t\"c\": map[string]interface{}{\n//\t\t\t\"d\": \"e\",\n//\t\t\t\"f\": \"g\",\n//\t\t},\n//\t\t\"z\": 1.4567,\n//\t}\n//\n//\tflat, err := flatten.Flatten(nested, \"\", flatten.RailsStyle)\n//\n//\t// output:\n//\t// map[string]interface{}{\n//\t//\t\"a\":    \"b\",\n//\t//\t\"c[d]\": \"e\",\n//\t//\t\"c[f]\": \"g\",\n//\t//\t\"z\":    1.4567,\n//\t// }\n//\n// Let's try a custom style, with the first example above.\n//\n//\temdash := flatten.SeparatorStyle{Middle: \"--\"}\n//\tflat, err := flatten.FlattenString(nested, \"\", emdash)\n//\n//\t// output: `{ \"one--two--0\": \"2a\", \"one--two--1\": \"2b\", \"side\": \"value\" }`\n//\npackage flatten\n"
  },
  {
    "path": "flatten.go",
    "content": "package flatten\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"regexp\"\n\t\"strconv\"\n)\n\n// The style of keys.  If there is an input with two\n// nested keys \"f\" and \"g\", with \"f\" at the root,\n//    { \"f\": { \"g\": ... } }\n// the output will be the concatenation\n//    f{Middle}{Before}g{After}...\n// Any struct element may be blank.\n// If you use Middle, you will probably leave Before & After blank, and vice-versa.\n// See examples in flatten_test.go and the \"Default styles\" here.\ntype SeparatorStyle struct {\n\tBefore string // Prepend to key\n\tMiddle string // Add between keys\n\tAfter  string // Append to key\n}\n\n// Default styles\nvar (\n\t// Separate nested key components with dots, e.g. \"a.b.1.c.d\"\n\tDotStyle = SeparatorStyle{Middle: \".\"}\n\n\t// Separate with path-like slashes, e.g. a/b/1/c/d\n\tPathStyle = SeparatorStyle{Middle: \"/\"}\n\n\t// Separate ala Rails, e.g. \"a[b][c][1][d]\"\n\tRailsStyle = SeparatorStyle{Before: \"[\", After: \"]\"}\n\n\t// Separate with underscores, e.g. \"a_b_1_c_d\"\n\tUnderscoreStyle = SeparatorStyle{Middle: \"_\"}\n)\n\n// Nested input must be a map or slice\nvar NotValidInputError = errors.New(\"Not a valid input: map or slice\")\n\n// Flatten generates a flat map from a nested one.  The original may include values of type map, slice and scalar,\n// but not struct.  Keys in the flat map will be a compound of descending map keys and slice iterations.\n// The presentation of keys is set by style.  A prefix is joined to each key.\nfunc Flatten(nested map[string]interface{}, prefix string, style SeparatorStyle) (map[string]interface{}, error) {\n\tflatmap := make(map[string]interface{})\n\n\terr := flatten(true, flatmap, nested, prefix, style)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn flatmap, nil\n}\n\n// JSON nested input must be a map\nvar NotValidJsonInputError = errors.New(\"Not a valid input, must be a map\")\n\nvar isJsonMap = regexp.MustCompile(`^\\s*\\{`)\n\n// FlattenString generates a flat JSON map from a nested one.  Keys in the flat map will be a compound of\n// descending map keys and slice iterations.  The presentation of keys is set by style.  A prefix is joined\n// to each key.\nfunc FlattenString(nestedstr, prefix string, style SeparatorStyle) (string, error) {\n\tif !isJsonMap.MatchString(nestedstr) {\n\t\treturn \"\", NotValidJsonInputError\n\t}\n\n\tvar nested map[string]interface{}\n\terr := json.Unmarshal([]byte(nestedstr), &nested)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tflatmap, err := Flatten(nested, prefix, style)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tflatb, err := json.Marshal(&flatmap)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn string(flatb), nil\n}\n\nfunc flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefix string, style SeparatorStyle) error {\n\tassign := func(newKey string, v interface{}) error {\n\t\tswitch v.(type) {\n\t\tcase map[string]interface{}, []interface{}:\n\t\t\tif err := flatten(false, flatMap, v, newKey, style); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tflatMap[newKey] = v\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tswitch nested.(type) {\n\tcase map[string]interface{}:\n\t\tfor k, v := range nested.(map[string]interface{}) {\n\t\t\tnewKey := enkey(top, prefix, k, style)\n\t\t\tassign(newKey, v)\n\t\t}\n\tcase []interface{}:\n\t\tfor i, v := range nested.([]interface{}) {\n\t\t\tnewKey := enkey(top, prefix, strconv.Itoa(i), style)\n\t\t\tassign(newKey, v)\n\t\t}\n\tdefault:\n\t\treturn NotValidInputError\n\t}\n\n\treturn nil\n}\n\nfunc enkey(top bool, prefix, subkey string, style SeparatorStyle) string {\n\tkey := prefix\n\n\tif top {\n\t\tkey += subkey\n\t} else {\n\t\tkey += style.Before + style.Middle + subkey + style.After\n\t}\n\n\treturn key\n}\n"
  },
  {
    "path": "flatten_test.go",
    "content": "package flatten\n\nimport (\n\t\"encoding/json\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"unicode\"\n)\n\nfunc TestFlatten(t *testing.T) {\n\tcases := []struct {\n\t\ttest   string\n\t\twant   map[string]interface{}\n\t\tprefix string\n\t\tstyle  SeparatorStyle\n\t}{\n\t\t// 1\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo.jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1.alist.0\":   \"a\",\n\t\t\t\t\"n1.alist.1\":   \"b\",\n\t\t\t\t\"n1.alist.2\":   \"c\",\n\t\t\t\t\"n1.alist.3.d\": \"other\",\n\t\t\t\t\"n1.alist.3.e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t},\n\t\t// 2\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\"a\",\n\t\t\t\t\t\"b\",\n\t\t\t\t\t\"c\",\n\t\t\t\t\t{\n\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo[jim]\":        \"bean\",\n\t\t\t\t\"fee\":             \"bar\",\n\t\t\t\t\"n1[alist][0]\":    \"a\",\n\t\t\t\t\"n1[alist][1]\":    \"b\",\n\t\t\t\t\"n1[alist][2]\":    \"c\",\n\t\t\t\t\"n1[alist][3][d]\": \"other\",\n\t\t\t\t\"n1[alist][3][e]\": \"another\",\n\t\t\t},\n\t\t\t\"\",\n\t\t\tRailsStyle,\n\t\t},\n\t\t// 3\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo/jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1/alist/0\":   \"a\",\n\t\t\t\t\"n1/alist/1\":   \"b\",\n\t\t\t\t\"n1/alist/2\":   \"c\",\n\t\t\t\t\"n1/alist/3/d\": \"other\",\n\t\t\t\t\"n1/alist/3/e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t},\n\t\t// 4\n\t\t{\n\t\t\t`{ \"a\": { \"b\": \"c\" }, \"e\": \"f\" }`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"p:a.b\": \"c\",\n\t\t\t\t\"p:e\":   \"f\",\n\t\t\t},\n\t\t\t\"p:\",\n\t\t\tDotStyle,\n\t\t},\n\t\t// 5\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo_jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1_alist_0\":   \"a\",\n\t\t\t\t\"n1_alist_1\":   \"b\",\n\t\t\t\t\"n1_alist_2\":   \"c\",\n\t\t\t\t\"n1_alist_3_d\": \"other\",\n\t\t\t\t\"n1_alist_3_e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tUnderscoreStyle,\n\t\t},\n\t\t// 6 -- try a prefix\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"flag-foo_jim\":      \"bean\",\n\t\t\t\t\"flag-fee\":          \"bar\",\n\t\t\t\t\"flag-n1_alist_0\":   \"a\",\n\t\t\t\t\"flag-n1_alist_1\":   \"b\",\n\t\t\t\t\"flag-n1_alist_2\":   \"c\",\n\t\t\t\t\"flag-n1_alist_3_d\": \"other\",\n\t\t\t\t\"flag-n1_alist_3_e\": \"another\",\n\t\t\t\t\"flag-number\":       1.4567,\n\t\t\t\t\"flag-bool\":         true,\n\t\t\t},\n\t\t\t\"flag-\",\n\t\t\tUnderscoreStyle,\n\t\t},\n\t}\n\n\tfor i, test := range cases {\n\t\tvar m interface{}\n\t\terr := json.Unmarshal([]byte(test.test), &m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"%d: failed to unmarshal test: %v\", i+1, err)\n\t\t\tcontinue\n\t\t}\n\t\tgot, err := Flatten(m.(map[string]interface{}), test.prefix, test.style)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"%d: failed to flatten: %v\", i+1, err)\n\t\t\tcontinue\n\t\t}\n\t\tif !reflect.DeepEqual(got, test.want) {\n\t\t\tt.Errorf(\"%d: mismatch, got: %v wanted: %v\", i+1, got, test.want)\n\t\t}\n\t}\n}\n\nfunc TestFlattenString(t *testing.T) {\n\tcases := []struct {\n\t\ttest   string\n\t\twant   string\n\t\tprefix string\n\t\tstyle  SeparatorStyle\n\t\terr    error\n\t}{\n\t\t// 1\n\t\t{\n\t\t\t`{ \"a\": \"b\" }`,\n\t\t\t`{ \"a\": \"b\" }`,\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 2\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"a.b.c.d\": \"e\", \"bool\": true, \"number\": 1.4567 }`,\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 3\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"a/b/c/d\": \"e\", \"bool\": true, \"number\": 1.4567 }`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 4\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a--b--c--d\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Middle: \"--\"}, // emdash\n\t\t\tnil,\n\t\t},\n\t\t// 5\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a(b)(c)(d)\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Before: \"(\", After: \")\"}, // paren groupings\n\t\t\tnil,\n\t\t},\n\t\t// 6 -- with leading whitespace\n\t\t{\n\t\t\t`\n\t\t\t  \t{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a(b)(c)(d)\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Before: \"(\", After: \")\"}, // paren groupings\n\t\t\tnil,\n\t\t},\n\n\t\t//\n\t\t// Valid JSON text, but invalid for FlattenString\n\t\t//\n\n\t\t// 7\n\t\t{\n\t\t\t`[ \"a\": { \"b\": \"c\" }, \"d\" ]`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 8\n\t\t{\n\t\t\t``,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 9\n\t\t{\n\t\t\t`astring`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 10\n\t\t{\n\t\t\t`false`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 11\n\t\t{\n\t\t\t`42`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 12 -- prior to version 1.0.1, this was accepted & unmarshalled as an empty map, finally returning `{}`.\n\t\t{\n\t\t\t`null`,\n\t\t\t`{}`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 13 -- try a prefix\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"flag-a.b.c.d\": \"e\", \"flag-bool\": true, \"flag-number\": 1.4567 }`,\n\t\t\t\"flag-\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t}\n\n\tfor i, test := range cases {\n\t\tgot, err := FlattenString(test.test, test.prefix, test.style)\n\t\tif err != test.err {\n\t\t\tt.Errorf(\"%d: error mismatch, got: [%v], wanted: [%v]\", i+1, err, test.err)\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tnixws := func(r rune) rune {\n\t\t\tif unicode.IsSpace(r) {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\treturn r\n\t\t}\n\n\t\tif got != strings.Map(nixws, test.want) {\n\t\t\tt.Errorf(\"%d: mismatch, got: %v wanted: %v\", i+1, got, test.want)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/jeremywohl/flatten\n"
  },
  {
    "path": "v2/README.md",
    "content": "flatten\n=======\n\n[![Go Reference](https://pkg.go.dev/badge/pkg.go.dev/github.com/jeremywohl/flatten/v2.svg)](https://pkg.go.dev/pkg.go.dev/github.com/jeremywohl/flatten/v2)\n\nFlatten makes flat, one-dimensional maps from arbitrarily nested ones.\n\nIt turns map keys into compound\nnames, in four default styles: dotted (`a.b.1.c`), path-like (`a/b/1/c`), Rails (`a[b][1][c]`), or with underscores (`a_b_1_c`).  Alternatively, you can pass a custom style.\n\nIt takes input as either JSON strings or\nGo structures.  It knows how to traverse these JSON types: objects/maps, arrays and scalars.\n\nYou can flatten JSON strings.\n\n```go\nnested := `{\n  \"one\": {\n    \"two\": [\n      \"2a\",\n      \"2b\"\n    ]\n  },\n  \"side\": \"value\"\n}`\n\nflat, err := flatten.FlattenString(nested, \"\", flatten.DotStyle)\n\n// output: `{ \"one.two.0\": \"2a\", \"one.two.1\": \"2b\", \"side\": \"value\" }`\n```\n\nOr Go maps directly.\n\n```go\nnested := map[string]interface{}{\n   \"a\": \"b\",\n   \"c\": map[string]interface{}{\n       \"d\": \"e\",\n       \"f\": \"g\",\n   },\n   \"z\": 1.4567,\n}\n\nflat, err := flatten.Flatten(nested, \"\", flatten.RailsStyle)\n\n// output:\n// map[string]interface{}{\n//  \"a\":    \"b\",\n//  \"c[d]\": \"e\",\n//  \"c[f]\": \"g\",\n//  \"z\":    1.4567,\n// }\n```\n\nLet's try a custom style, with the first example above.\n\n```go\nemdash := flatten.SeparatorStyle{Middle: \"--\"}\nflat, err := flatten.FlattenString(nested, \"\", emdash)\n\n// output: `{ \"one--two--0\": \"2a\", \"one--two--1\": \"2b\", \"side\": \"value\" }`\n```\n\nSee [godoc](https://godoc.org/github.com/jeremywohl/flatten) for API.\n"
  },
  {
    "path": "v2/doc.go",
    "content": "// Flatten makes flat, one-dimensional maps from arbitrarily nested ones.\n//\n// It turns map keys into compound\n// names, in four default styles: dotted (`a.b.1.c`), path-like (`a/b/1/c`), Rails (`a[b][1][c]`),\n// or with underscores (`a_b_1_c`).  Alternatively, you can pass a custom style.\n//\n// It takes input as either JSON strings or\n// Go structures.  It knows how to traverse these JSON types: objects/maps, arrays and scalars.\n//\n// You can flatten JSON strings.\n//\n//\tnested := `{\n//\t  \"one\": {\n//\t    \"two\": [\n//\t      \"2a\",\n//\t      \"2b\"\n//\t    ]\n//\t  },\n//\t  \"side\": \"value\"\n//\t}`\n//\n//\tflat, err := flatten.FlattenString(nested, \"\", flatten.DotStyle)\n//\n//\t// output: `{ \"one.two.0\": \"2a\", \"one.two.1\": \"2b\", \"side\": \"value\" }`\n//\n// Or Go maps directly.\n//\n//\tnested := map[string]interface{}{\n//\t\t\"a\": \"b\",\n//\t\t\"c\": map[string]interface{}{\n//\t\t\t\"d\": \"e\",\n//\t\t\t\"f\": \"g\",\n//\t\t},\n//\t\t\"z\": 1.4567,\n//\t}\n//\n//\tflat, err := flatten.Flatten(nested, \"\", flatten.RailsStyle)\n//\n//\t// output:\n//\t// map[string]interface{}{\n//\t//\t\"a\":    \"b\",\n//\t//\t\"c[d]\": \"e\",\n//\t//\t\"c[f]\": \"g\",\n//\t//\t\"z\":    1.4567,\n//\t// }\n//\n// Let's try a custom style, with the first example above.\n//\n//\temdash := flatten.SeparatorStyle{Middle: \"--\"}\n//\tflat, err := flatten.FlattenString(nested, \"\", emdash)\n//\n//\t// output: `{ \"one--two--0\": \"2a\", \"one--two--1\": \"2b\", \"side\": \"value\" }`\n//\npackage flatten\n"
  },
  {
    "path": "v2/flatten.go",
    "content": "package flatten\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"regexp\"\n\t\"strconv\"\n)\n\n// The style of keys.  If there is an input with two\n// nested keys \"f\" and \"g\", with \"f\" at the root,\n//    { \"f\": { \"g\": ... } }\n// the output will be the concatenation\n//    f{Middle}{Before}g{After}...\n// Any struct element may be blank.\n// If you use Middle, you will probably leave Before & After blank, and vice-versa.\n// See examples in flatten_test.go and the \"Default styles\" here.\ntype SeparatorStyle struct {\n\tBefore string // Prepend to key\n\tMiddle string // Add between keys\n\tAfter  string // Append to key\n}\n\n// Default styles\nvar (\n\t// Separate nested key components with dots, e.g. \"a.b.1.c.d\"\n\tDotStyle = SeparatorStyle{Middle: \".\"}\n\n\t// Separate with path-like slashes, e.g. a/b/1/c/d\n\tPathStyle = SeparatorStyle{Middle: \"/\"}\n\n\t// Separate ala Rails, e.g. \"a[b][c][1][d]\"\n\tRailsStyle = SeparatorStyle{Before: \"[\", After: \"]\"}\n\n\t// Separate with underscores, e.g. \"a_b_1_c_d\"\n\tUnderscoreStyle = SeparatorStyle{Middle: \"_\"}\n)\n\n// Nested input must be a map or slice\nvar NotValidInputError = errors.New(\"Not a valid input: map or slice\")\n\n// Flatten generates a flat map from a nested one.  The original may include values of type map, slice and scalar,\n// but not struct.  Keys in the flat map will be a compound of descending map keys and slice iterations.\n// The presentation of keys is set by style.  A prefix is joined to each key.\nfunc Flatten(nested map[string]interface{}, prefix string, style SeparatorStyle) (map[string]interface{}, error) {\n\tflatmap := make(map[string]interface{})\n\n\terr := flatten(true, flatmap, nested, prefix, style)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn flatmap, nil\n}\n\n// JSON nested input must be a map\nvar NotValidJsonInputError = errors.New(\"Not a valid input, must be a map\")\n\nvar isJsonMap = regexp.MustCompile(`^\\s*\\{`)\n\n// FlattenString generates a flat JSON map from a nested one.  Keys in the flat map will be a compound of\n// descending map keys and slice iterations.  The presentation of keys is set by style.  A prefix is joined\n// to each key.\nfunc FlattenString(nestedstr, prefix string, style SeparatorStyle) (string, error) {\n\tif !isJsonMap.MatchString(nestedstr) {\n\t\treturn \"\", NotValidJsonInputError\n\t}\n\n\tvar nested map[string]interface{}\n\terr := json.Unmarshal([]byte(nestedstr), &nested)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tflatmap, err := Flatten(nested, prefix, style)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tflatb, err := json.Marshal(&flatmap)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn string(flatb), nil\n}\n\nfunc flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefix string, style SeparatorStyle) error {\n\tassign := func(newKey string, v interface{}) error {\n\t\tswitch v.(type) {\n\t\tcase map[string]interface{}, []interface{}:\n\t\t\tif err := flatten(false, flatMap, v, newKey, style); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tflatMap[newKey] = v\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tswitch nested.(type) {\n\tcase map[string]interface{}:\n\t\tfor k, v := range nested.(map[string]interface{}) {\n\t\t\tnewKey := enkey(top, prefix, k, style)\n\t\t\tassign(newKey, v)\n\t\t}\n\tcase []interface{}:\n\t\tfor i, v := range nested.([]interface{}) {\n\t\t\tnewKey := enkey(top, prefix, strconv.Itoa(i), style)\n\t\t\tassign(newKey, v)\n\t\t}\n\tdefault:\n\t\treturn NotValidInputError\n\t}\n\n\treturn nil\n}\n\nfunc enkey(top bool, prefix, subkey string, style SeparatorStyle) string {\n\tkey := prefix\n\n\tif top {\n\t\tkey += subkey\n\t} else {\n\t\tkey += style.Before + style.Middle + subkey + style.After\n\t}\n\n\treturn key\n}\n"
  },
  {
    "path": "v2/flatten_test.go",
    "content": "package flatten\n\nimport (\n\t\"encoding/json\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"unicode\"\n)\n\nfunc TestFlatten(t *testing.T) {\n\tcases := []struct {\n\t\ttest   string\n\t\twant   map[string]interface{}\n\t\tprefix string\n\t\tstyle  SeparatorStyle\n\t}{\n\t\t// 1\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo.jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1.alist.0\":   \"a\",\n\t\t\t\t\"n1.alist.1\":   \"b\",\n\t\t\t\t\"n1.alist.2\":   \"c\",\n\t\t\t\t\"n1.alist.3.d\": \"other\",\n\t\t\t\t\"n1.alist.3.e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t},\n\t\t// 2\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\"a\",\n\t\t\t\t\t\"b\",\n\t\t\t\t\t\"c\",\n\t\t\t\t\t{\n\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo[jim]\":        \"bean\",\n\t\t\t\t\"fee\":             \"bar\",\n\t\t\t\t\"n1[alist][0]\":    \"a\",\n\t\t\t\t\"n1[alist][1]\":    \"b\",\n\t\t\t\t\"n1[alist][2]\":    \"c\",\n\t\t\t\t\"n1[alist][3][d]\": \"other\",\n\t\t\t\t\"n1[alist][3][e]\": \"another\",\n\t\t\t},\n\t\t\t\"\",\n\t\t\tRailsStyle,\n\t\t},\n\t\t// 3\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo/jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1/alist/0\":   \"a\",\n\t\t\t\t\"n1/alist/1\":   \"b\",\n\t\t\t\t\"n1/alist/2\":   \"c\",\n\t\t\t\t\"n1/alist/3/d\": \"other\",\n\t\t\t\t\"n1/alist/3/e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t},\n\t\t// 4\n\t\t{\n\t\t\t`{ \"a\": { \"b\": \"c\" }, \"e\": \"f\" }`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"p:a.b\": \"c\",\n\t\t\t\t\"p:e\":   \"f\",\n\t\t\t},\n\t\t\t\"p:\",\n\t\t\tDotStyle,\n\t\t},\n\t\t// 5\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"foo_jim\":      \"bean\",\n\t\t\t\t\"fee\":          \"bar\",\n\t\t\t\t\"n1_alist_0\":   \"a\",\n\t\t\t\t\"n1_alist_1\":   \"b\",\n\t\t\t\t\"n1_alist_2\":   \"c\",\n\t\t\t\t\"n1_alist_3_d\": \"other\",\n\t\t\t\t\"n1_alist_3_e\": \"another\",\n\t\t\t\t\"number\":       1.4567,\n\t\t\t\t\"bool\":         true,\n\t\t\t},\n\t\t\t\"\",\n\t\t\tUnderscoreStyle,\n\t\t},\n\t\t// 6 -- try a prefix\n\t\t{\n\t\t\t`{\n\t\t\t\t\"foo\": {\n\t\t\t\t\t\"jim\":\"bean\"\n\t\t\t\t},\n\t\t\t\t\"fee\": \"bar\",\n\t\t\t\t\"n1\": {\n\t\t\t\t\t\"alist\": [\n\t\t\t\t\t\t\"a\",\n\t\t\t\t\t\t\"b\",\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"d\": \"other\",\n\t\t\t\t\t\t\t\"e\": \"another\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"number\": 1.4567,\n\t\t\t\t\"bool\":   true\n\t\t\t}`,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"flag-foo_jim\":      \"bean\",\n\t\t\t\t\"flag-fee\":          \"bar\",\n\t\t\t\t\"flag-n1_alist_0\":   \"a\",\n\t\t\t\t\"flag-n1_alist_1\":   \"b\",\n\t\t\t\t\"flag-n1_alist_2\":   \"c\",\n\t\t\t\t\"flag-n1_alist_3_d\": \"other\",\n\t\t\t\t\"flag-n1_alist_3_e\": \"another\",\n\t\t\t\t\"flag-number\":       1.4567,\n\t\t\t\t\"flag-bool\":         true,\n\t\t\t},\n\t\t\t\"flag-\",\n\t\t\tUnderscoreStyle,\n\t\t},\n\t}\n\n\tfor i, test := range cases {\n\t\tvar m interface{}\n\t\terr := json.Unmarshal([]byte(test.test), &m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"%d: failed to unmarshal test: %v\", i+1, err)\n\t\t\tcontinue\n\t\t}\n\t\tgot, err := Flatten(m.(map[string]interface{}), test.prefix, test.style)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"%d: failed to flatten: %v\", i+1, err)\n\t\t\tcontinue\n\t\t}\n\t\tif !reflect.DeepEqual(got, test.want) {\n\t\t\tt.Errorf(\"%d: mismatch, got: %v wanted: %v\", i+1, got, test.want)\n\t\t}\n\t}\n}\n\nfunc TestFlattenString(t *testing.T) {\n\tcases := []struct {\n\t\ttest   string\n\t\twant   string\n\t\tprefix string\n\t\tstyle  SeparatorStyle\n\t\terr    error\n\t}{\n\t\t// 1\n\t\t{\n\t\t\t`{ \"a\": \"b\" }`,\n\t\t\t`{ \"a\": \"b\" }`,\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 2\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"a.b.c.d\": \"e\", \"bool\": true, \"number\": 1.4567 }`,\n\t\t\t\"\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 3\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"a/b/c/d\": \"e\", \"bool\": true, \"number\": 1.4567 }`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tnil,\n\t\t},\n\t\t// 4\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a--b--c--d\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Middle: \"--\"}, // emdash\n\t\t\tnil,\n\t\t},\n\t\t// 5\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a(b)(c)(d)\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Before: \"(\", After: \")\"}, // paren groupings\n\t\t\tnil,\n\t\t},\n\t\t// 6 -- with leading whitespace\n\t\t{\n\t\t\t`\n\t\t\t  \t{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } } }`,\n\t\t\t`{ \"a(b)(c)(d)\": \"e\" }`,\n\t\t\t\"\",\n\t\t\tSeparatorStyle{Before: \"(\", After: \")\"}, // paren groupings\n\t\t\tnil,\n\t\t},\n\n\t\t//\n\t\t// Valid JSON text, but invalid for FlattenString\n\t\t//\n\n\t\t// 7\n\t\t{\n\t\t\t`[ \"a\": { \"b\": \"c\" }, \"d\" ]`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 8\n\t\t{\n\t\t\t``,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 9\n\t\t{\n\t\t\t`astring`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 10\n\t\t{\n\t\t\t`false`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 11\n\t\t{\n\t\t\t`42`,\n\t\t\t`bogus`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 12 -- prior to version 1.0.1, this was accepted & unmarshalled as an empty map, finally returning `{}`.\n\t\t{\n\t\t\t`null`,\n\t\t\t`{}`,\n\t\t\t\"\",\n\t\t\tPathStyle,\n\t\t\tNotValidJsonInputError,\n\t\t},\n\t\t// 13 -- try a prefix\n\t\t{\n\t\t\t`{ \"a\": { \"b\" : { \"c\" : { \"d\" : \"e\" } } }, \"number\": 1.4567, \"bool\": true }`,\n\t\t\t`{ \"flag-a.b.c.d\": \"e\", \"flag-bool\": true, \"flag-number\": 1.4567 }`,\n\t\t\t\"flag-\",\n\t\t\tDotStyle,\n\t\t\tnil,\n\t\t},\n\t}\n\n\tfor i, test := range cases {\n\t\tgot, err := FlattenString(test.test, test.prefix, test.style)\n\t\tif err != test.err {\n\t\t\tt.Errorf(\"%d: error mismatch, got: [%v], wanted: [%v]\", i+1, err, test.err)\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tnixws := func(r rune) rune {\n\t\t\tif unicode.IsSpace(r) {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\treturn r\n\t\t}\n\n\t\tif got != strings.Map(nixws, test.want) {\n\t\t\tt.Errorf(\"%d: mismatch, got: %v wanted: %v\", i+1, got, test.want)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "v2/go.mod",
    "content": "module github.com/jeremywohl/flatten/v2\n"
  }
]