From 79668e4ecee9e167ee472ab6e5b4acba4fd3514e Mon Sep 17 00:00:00 2001 From: Aykhan Shahsuvarov Date: Fri, 30 May 2025 21:41:38 +0400 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20value=20generators?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- README.md | 51 ++++++ Taskfile.yaml | 2 +- config/config.go | 89 ++++++++++ go.mod | 2 +- requests/request.go | 42 +++-- utils/slice.go | 13 +- utils/templates.go | 386 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 561 insertions(+), 26 deletions(-) create mode 100644 utils/templates.go diff --git a/Dockerfile b/Dockerfile index bd26da1..28b8c13 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN go build -ldflags "-s -w" -o dodo +RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o dodo FROM gcr.io/distroless/static-debian12:latest diff --git a/README.md b/README.md index 6be4185..954f1df 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ - [2.2 YAML/YML Example](#22-yamlyml-example) - [3. CLI & Config File Combination](#3-cli--config-file-combination) - [Config Parameters Reference](#config-parameters-reference) +- [Template Functions](#template-functions) ## Installation @@ -264,3 +265,53 @@ If `Headers`, `Params`, `Cookies`, `Body`, or `Proxy` fields have multiple value | Body | body | -body | -b | String OR [String] | Request body or list of request bodies | - | | Proxy | proxies | -proxy | -x | String OR [String] | Proxy URL or list of proxy URLs | - | | Skip Verify | skip_verify | -skip-verify | | Boolean | Skip SSL/TLS certificate verification | false | + +## Template Functions + +Dodo supports template functions in `Headers`, `Params`, `Cookies`, and `Body` fields. These functions allow you to generate dynamic values for each request. + +You can use Go template syntax to include dynamic values in your requests. Here's how to use template functions: + +In CLI config: + +```sh +dodo -u https://example.com -r 1 \ + -header "User-Agent:{{ fakeit_UserAgent }}" \ # e.g. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)" + -param "username={{ fakeit_Username }}" \ # e.g. "username=John Bob" + -cookie "token={{ fakeit_Password true true true true true 10 }}" \ # e.g. token=1234567890abcdef1234567890abcdef + -body '{"email":"{{ fakeit_Email }}", "password":"{{ fakeit_Password true true true true true 10 }}"}' # e.g. {"email":"john.doe@example.com", "password":"12rw4d-78d"} +``` + +In YAML/YML config: + +```yaml +headers: + - User-Agent: "{{ fakeit_UserAgent }}" # e.g. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)" + - "Random-Header-{{fakeit_FirstName}}": "static_value" # e.g. "Random-Header-John: static_value" + +cookies: + - token: "Bearer {{ fakeit_UUID }}" # e.g. "token=Bearer 1234567890abcdef1234567890abcdef" + +params: + - id: "{{ fakeit_Uint }}" # e.g. "id=1234567890" + - username: "{{ fakeit_Username }}" # e.g. "username=John Doe" + +body: + - '{ "username": "{{ fakeit_Username }}", "password": "{{ fakeit_Password }}" }' # e.g. { "username": "john.doe", "password": "password123" } + - '{ "email": "{{ fakeit_Email }}", "phone": "{{ fakeit_Phone }}" }' # e.g. { "email": "john.doe@example.com", "phone": "+1234567890" } +``` + +In JSON config: + +```jsonc +{ + "headers": [ + { "User-Agent": "{{ fakeit_UserAgent }}" }, // e.g. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)" + ], + "body": [ + "{ \"username\": \"{{ fakeit_Username }}\", \"password\": \"{{ fakeit_Password }}\" }", // e.g. { "username": "john.doe", "password": "password123" } + ], +} +``` + +For the full list of template functions over 200 functions, refer to the `newFuncMap` function in `requests/request.go`. diff --git a/Taskfile.yaml b/Taskfile.yaml index e8e2ff8..c1730c4 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -32,7 +32,7 @@ tasks: lint: golangci-lint run - build: go build -ldflags "-s -w" -o "dodo" + build: CGO_ENABLED=0 go build -ldflags "-s -w" -o "dodo" build-all: silent: true diff --git a/config/config.go b/config/config.go index 8b9414f..322d160 100644 --- a/config/config.go +++ b/config/config.go @@ -1,12 +1,15 @@ package config import ( + "bytes" "errors" "fmt" + "math/rand" "net/url" "os" "slices" "strings" + "text/template" "time" "github.com/aykhans/dodo/types" @@ -201,6 +204,92 @@ func (config *Config) Validate() []error { } } + funcMap := utils.NewFuncMap(rand.New(rand.NewSource(time.Now().UnixNano()))) + + for _, header := range config.Headers { + t, err := template.New("default").Funcs(funcMap).Parse(header.Key) + if err != nil { + errs = append(errs, fmt.Errorf("header key (%s) parse error: %v", header.Key, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("header key (%s) parse error: %v", header.Key, err)) + } + } + + for _, value := range header.Value { + t, err := template.New("default").Funcs(funcMap).Parse(value) + if err != nil { + errs = append(errs, fmt.Errorf("header value (%s) parse error: %v", value, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("header value (%s) parse error: %v", value, err)) + } + } + } + } + + for _, cookie := range config.Cookies { + t, err := template.New("default").Funcs(funcMap).Parse(cookie.Key) + if err != nil { + errs = append(errs, fmt.Errorf("cookie key (%s) parse error: %v", cookie.Key, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("cookie key (%s) parse error: %v", cookie.Key, err)) + } + } + + for _, value := range cookie.Value { + t, err := template.New("default").Funcs(funcMap).Parse(value) + if err != nil { + errs = append(errs, fmt.Errorf("cookie value (%s) parse error: %v", value, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("cookie value (%s) parse error: %v", value, err)) + } + } + } + } + + for _, param := range config.Params { + t, err := template.New("default").Funcs(funcMap).Parse(param.Key) + if err != nil { + errs = append(errs, fmt.Errorf("param key (%s) parse error: %v", param.Key, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("param key (%s) parse error: %v", param.Key, err)) + } + } + + for _, value := range param.Value { + t, err := template.New("default").Funcs(funcMap).Parse(value) + if err != nil { + errs = append(errs, fmt.Errorf("param value (%s) parse error: %v", value, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("param value (%s) parse error: %v", value, err)) + } + } + } + } + + for _, body := range config.Body { + t, err := template.New("default").Funcs(funcMap).Parse(body) + if err != nil { + errs = append(errs, fmt.Errorf("body (%s) parse error: %v", body, err)) + } else { + var buf bytes.Buffer + if err = t.Execute(&buf, nil); err != nil { + errs = append(errs, fmt.Errorf("body (%s) parse error: %v", body, err)) + } + } + } + return errs } diff --git a/go.mod b/go.mod index 29b3897..d972a38 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/aykhans/dodo go 1.24.2 require ( + github.com/brianvoe/gofakeit/v7 v7.2.1 github.com/jedib0t/go-pretty/v6 v6.6.7 github.com/valyala/fasthttp v1.62.0 - github.com/brianvoe/gofakeit/v7 v7.2.1 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/requests/request.go b/requests/request.go index c255a26..0e32e49 100644 --- a/requests/request.go +++ b/requests/request.go @@ -5,14 +5,12 @@ import ( "context" "math/rand" "net/url" - "strings" "text/template" "time" "github.com/aykhans/dodo/config" "github.com/aykhans/dodo/types" "github.com/aykhans/dodo/utils" - "github.com/brianvoe/gofakeit/v7" "github.com/valyala/fasthttp" ) @@ -113,7 +111,7 @@ func getRequestGeneratorFunc( getParams := getKeyValueGeneratorFunc(params, localRand) getHeaders := getKeyValueGeneratorFunc(headers, localRand) getCookies := getKeyValueGeneratorFunc(cookies, localRand) - getBody := getValueFunc(bodies, newFuncMap(localRand), localRand) + getBody := getValueFunc(bodies, utils.NewFuncMap(localRand), localRand) return func() *fasthttp.Request { return newFasthttpRequest( @@ -203,7 +201,7 @@ func getKeyValueGeneratorFunc[ ) func() T { keyValueGenerators := make([]keyValueGenerator, len(keyValueSlice)) - funcMap := newFuncMap(localRand) + funcMap := utils.NewFuncMap(localRand) for i, kv := range keyValueSlice { keyValueGenerators[i] = keyValueGenerator{ @@ -224,10 +222,18 @@ func getKeyValueGeneratorFunc[ } } +// getKeyFunc creates a function that processes a key string through Go's template engine. +// It takes a key string and a template.FuncMap containing the available template functions. +// +// The returned function, when called, will execute the template with the given key and return +// the processed string result. If template parsing fails, the returned function will always +// return an empty string. +// +// This enables dynamic generation of keys that can include template directives and functions. func getKeyFunc(key string, funcMap template.FuncMap) func() string { t, err := template.New("default").Funcs(funcMap).Parse(key) if err != nil { - panic(err) + return func() string { return "" } } return func() string { @@ -237,6 +243,21 @@ func getKeyFunc(key string, funcMap template.FuncMap) func() string { } } +// getValueFunc creates a function that randomly selects and processes a value from a slice of strings +// through Go's template engine. +// +// Parameters: +// - values: A slice of string templates that can contain template directives +// - funcMap: A template.FuncMap containing all available template functions +// - localRand: A random number generator for consistent randomization +// +// The returned function, when called, will: +// 1. Select a random template from the values slice +// 2. Execute the selected template +// 3. Return the processed string result +// +// If a selected template is nil (due to earlier parsing failure), the function will return an empty string. +// This enables dynamic generation of values with randomized selection from multiple templates. func getValueFunc( values []string, funcMap template.FuncMap, @@ -247,7 +268,7 @@ func getValueFunc( for i, value := range values { t, err := template.New("default").Funcs(funcMap).Parse(value) if err != nil { - panic(err) + templates[i] = nil } templates[i] = t } @@ -264,12 +285,3 @@ func getValueFunc( } } } - -func newFuncMap(localRand *rand.Rand) template.FuncMap { - localFaker := gofakeit.NewFaker(localRand, false) - - return template.FuncMap{ - "upper": strings.ToUpper, - "fakeit_Name": localFaker.Name, - } -} diff --git a/utils/slice.go b/utils/slice.go index 0edeac9..1f56656 100644 --- a/utils/slice.go +++ b/utils/slice.go @@ -10,14 +10,11 @@ func Flatten[T any](nested [][]*T) []*T { return flattened } -// RandomValueCycle returns a function that cycles through the provided slice of values -// in a random order. Each call to the returned function will yield a value from the slice. -// The order of values is determined by the provided random number generator. -// -// The returned function will cycle through the values in a random order until all values -// have been returned at least once. After all values have been returned, the function will -// reset and start cycling through the values in a random order again. -// The returned function isn't thread-safe and should be used in a single-threaded context. +// RandomValueCycle returns a function that cycles through the provided values in a pseudo-random order. +// Each value in the input slice will be returned before any value is repeated. +// If the input slice is empty, the returned function will always return the zero value of type T. +// If the input slice contains only one element, that element is always returned. +// This function is not thread-safe and should not be called concurrently. func RandomValueCycle[T any](values []T, localRand *rand.Rand) func() T { switch valuesLen := len(values); valuesLen { case 0: diff --git a/utils/templates.go b/utils/templates.go new file mode 100644 index 0000000..d9fe610 --- /dev/null +++ b/utils/templates.go @@ -0,0 +1,386 @@ +package utils + +import ( + "math/rand" + "strings" + "text/template" + "time" + + "github.com/brianvoe/gofakeit/v7" +) + +// NewFuncMap creates a template.FuncMap populated with string manipulation functions +// and data generation functions from gofakeit. +// +// It takes a random number generator that is used to initialize a localized faker +// instance, ensuring that random data generation is deterministic within a request context. +// +// All functions are prefixed to avoid naming conflicts: +// - String functions: "strings_*" +// - Data generation functions: "fakeit_*" +func NewFuncMap(localRand *rand.Rand) template.FuncMap { + localFaker := gofakeit.NewFaker(localRand, false) + + return template.FuncMap{ + // Strings + "strings_ToUpper": strings.ToUpper, + "strings_ToLower": strings.ToLower, + "strings_RemoveSpaces": func(s string) string { return strings.ReplaceAll(s, " ", "") }, + "strings_Replace": strings.Replace, + "strings_ToDate": func(dateString string) time.Time { + date, err := time.Parse("2006-01-02", dateString) + if err != nil { + return time.Now() + } + return date + }, + + // FakeIt / Product + "fakeit_ProductName": localFaker.ProductName, + "fakeit_ProductDescription": localFaker.ProductDescription, + "fakeit_ProductCategory": localFaker.ProductCategory, + "fakeit_ProductFeature": localFaker.ProductFeature, + "fakeit_ProductMaterial": localFaker.ProductMaterial, + "fakeit_ProductUPC": localFaker.ProductUPC, + "fakeit_ProductAudience": localFaker.ProductAudience, + "fakeit_ProductDimension": localFaker.ProductDimension, + "fakeit_ProductUseCase": localFaker.ProductUseCase, + "fakeit_ProductBenefit": localFaker.ProductBenefit, + "fakeit_ProductSuffix": localFaker.ProductSuffix, + + // FakeIt / Person + "fakeit_Name": localFaker.Name, + "fakeit_NamePrefix": localFaker.NamePrefix, + "fakeit_NameSuffix": localFaker.NameSuffix, + "fakeit_FirstName": localFaker.FirstName, + "fakeit_MiddleName": localFaker.MiddleName, + "fakeit_LastName": localFaker.LastName, + "fakeit_Gender": localFaker.Gender, + "fakeit_SSN": localFaker.SSN, + "fakeit_Hobby": localFaker.Hobby, + "fakeit_Email": localFaker.Email, + "fakeit_Phone": localFaker.Phone, + "fakeit_PhoneFormatted": localFaker.PhoneFormatted, + + // FakeIt / Auth + "fakeit_Username": localFaker.Username, + "fakeit_Password": localFaker.Password, + + // FakeIt / Address + "fakeit_City": localFaker.City, + "fakeit_Country": localFaker.Country, + "fakeit_CountryAbr": localFaker.CountryAbr, + "fakeit_State": localFaker.State, + "fakeit_StateAbr": localFaker.StateAbr, + "fakeit_Street": localFaker.Street, + "fakeit_StreetName": localFaker.StreetName, + "fakeit_StreetNumber": localFaker.StreetNumber, + "fakeit_StreetPrefix": localFaker.StreetPrefix, + "fakeit_StreetSuffix": localFaker.StreetSuffix, + "fakeit_Zip": localFaker.Zip, + "fakeit_Latitude": localFaker.Latitude, + "fakeit_LatitudeInRange": func(min, max float64) float64 { + value, err := localFaker.LatitudeInRange(min, max) + if err != nil { + var zero float64 + return zero + } + return value + }, + "fakeit_Longitude": localFaker.Longitude, + "fakeit_LongitudeInRange": func(min, max float64) float64 { + value, err := localFaker.LongitudeInRange(min, max) + if err != nil { + var zero float64 + return zero + } + return value + }, + + // FakeIt / Game + "fakeit_Gamertag": localFaker.Gamertag, + + // FakeIt / Beer + "fakeit_BeerAlcohol": localFaker.BeerAlcohol, + "fakeit_BeerBlg": localFaker.BeerBlg, + "fakeit_BeerHop": localFaker.BeerHop, + "fakeit_BeerIbu": localFaker.BeerIbu, + "fakeit_BeerMalt": localFaker.BeerMalt, + "fakeit_BeerName": localFaker.BeerName, + "fakeit_BeerStyle": localFaker.BeerStyle, + "fakeit_BeerYeast": localFaker.BeerYeast, + + // FakeIt / Car + "fakeit_CarMaker": localFaker.CarMaker, + "fakeit_CarModel": localFaker.CarModel, + "fakeit_CarType": localFaker.CarType, + "fakeit_CarFuelType": localFaker.CarFuelType, + "fakeit_CarTransmissionType": localFaker.CarTransmissionType, + + // FakeIt / Words + "fakeit_Noun": localFaker.Noun, + "fakeit_NounCommon": localFaker.NounCommon, + "fakeit_NounConcrete": localFaker.NounConcrete, + "fakeit_NounAbstract": localFaker.NounAbstract, + "fakeit_NounCollectivePeople": localFaker.NounCollectivePeople, + "fakeit_NounCollectiveAnimal": localFaker.NounCollectiveAnimal, + "fakeit_NounCollectiveThing": localFaker.NounCollectiveThing, + "fakeit_NounCountable": localFaker.NounCountable, + "fakeit_NounUncountable": localFaker.NounUncountable, + "fakeit_Verb": localFaker.Verb, + "fakeit_VerbAction": localFaker.VerbAction, + "fakeit_VerbLinking": localFaker.VerbLinking, + "fakeit_VerbHelping": localFaker.VerbHelping, + "fakeit_Adverb": localFaker.Adverb, + "fakeit_AdverbManner": localFaker.AdverbManner, + "fakeit_AdverbDegree": localFaker.AdverbDegree, + "fakeit_AdverbPlace": localFaker.AdverbPlace, + "fakeit_AdverbTimeDefinite": localFaker.AdverbTimeDefinite, + "fakeit_AdverbTimeIndefinite": localFaker.AdverbTimeIndefinite, + "fakeit_AdverbFrequencyDefinite": localFaker.AdverbFrequencyDefinite, + "fakeit_AdverbFrequencyIndefinite": localFaker.AdverbFrequencyIndefinite, + "fakeit_Preposition": localFaker.Preposition, + "fakeit_PrepositionSimple": localFaker.PrepositionSimple, + "fakeit_PrepositionDouble": localFaker.PrepositionDouble, + "fakeit_PrepositionCompound": localFaker.PrepositionCompound, + "fakeit_Adjective": localFaker.Adjective, + "fakeit_AdjectiveDescriptive": localFaker.AdjectiveDescriptive, + "fakeit_AdjectiveQuantitative": localFaker.AdjectiveQuantitative, + "fakeit_AdjectiveProper": localFaker.AdjectiveProper, + "fakeit_AdjectiveDemonstrative": localFaker.AdjectiveDemonstrative, + "fakeit_AdjectivePossessive": localFaker.AdjectivePossessive, + "fakeit_AdjectiveInterrogative": localFaker.AdjectiveInterrogative, + "fakeit_AdjectiveIndefinite": localFaker.AdjectiveIndefinite, + "fakeit_Pronoun": localFaker.Pronoun, + "fakeit_PronounPersonal": localFaker.PronounPersonal, + "fakeit_PronounObject": localFaker.PronounObject, + "fakeit_PronounPossessive": localFaker.PronounPossessive, + "fakeit_PronounReflective": localFaker.PronounReflective, + "fakeit_PronounDemonstrative": localFaker.PronounDemonstrative, + "fakeit_PronounInterrogative": localFaker.PronounInterrogative, + "fakeit_PronounRelative": localFaker.PronounRelative, + "fakeit_Connective": localFaker.Connective, + "fakeit_ConnectiveTime": localFaker.ConnectiveTime, + "fakeit_ConnectiveComparative": localFaker.ConnectiveComparative, + "fakeit_ConnectiveComplaint": localFaker.ConnectiveComplaint, + "fakeit_ConnectiveListing": localFaker.ConnectiveListing, + "fakeit_ConnectiveCasual": localFaker.ConnectiveCasual, + "fakeit_ConnectiveExamplify": localFaker.ConnectiveExamplify, + "fakeit_Word": localFaker.Word, + "fakeit_Sentence": localFaker.Sentence, + "fakeit_Paragraph": localFaker.Paragraph, + "fakeit_LoremIpsumWord": localFaker.LoremIpsumWord, + "fakeit_LoremIpsumSentence": localFaker.LoremIpsumSentence, + "fakeit_LoremIpsumParagraph": localFaker.LoremIpsumParagraph, + "fakeit_Question": localFaker.Question, + "fakeit_Quote": localFaker.Quote, + "fakeit_Phrase": localFaker.Phrase, + + // FakeIt / Foods + "fakeit_Fruit": localFaker.Fruit, + "fakeit_Vegetable": localFaker.Vegetable, + "fakeit_Breakfast": localFaker.Breakfast, + "fakeit_Lunch": localFaker.Lunch, + "fakeit_Dinner": localFaker.Dinner, + "fakeit_Snack": localFaker.Snack, + "fakeit_Dessert": localFaker.Dessert, + + // FakeIt / Misc + "fakeit_Bool": localFaker.Bool, + "fakeit_UUID": localFaker.UUID, + "fakeit_FlipACoin": localFaker.FlipACoin, + + // FakeIt / Colors + "fakeit_Color": localFaker.Color, + "fakeit_HexColor": localFaker.HexColor, + "fakeit_RGBColor": localFaker.RGBColor, + "fakeit_SafeColor": localFaker.SafeColor, + "fakeit_NiceColors": localFaker.NiceColors, + + // FakeIt / Internet + "fakeit_URL": localFaker.URL, + "fakeit_DomainName": localFaker.DomainName, + "fakeit_DomainSuffix": localFaker.DomainSuffix, + "fakeit_IPv4Address": localFaker.IPv4Address, + "fakeit_IPv6Address": localFaker.IPv6Address, + "fakeit_MacAddress": localFaker.MacAddress, + "fakeit_HTTPStatusCode": localFaker.HTTPStatusCode, + "fakeit_HTTPStatusCodeSimple": localFaker.HTTPStatusCodeSimple, + "fakeit_LogLevel": localFaker.LogLevel, + "fakeit_HTTPMethod": localFaker.HTTPMethod, + "fakeit_HTTPVersion": localFaker.HTTPVersion, + "fakeit_UserAgent": localFaker.UserAgent, + "fakeit_ChromeUserAgent": localFaker.ChromeUserAgent, + "fakeit_FirefoxUserAgent": localFaker.FirefoxUserAgent, + "fakeit_OperaUserAgent": localFaker.OperaUserAgent, + "fakeit_SafariUserAgent": localFaker.SafariUserAgent, + + // FakeIt / HTML + "fakeit_InputName": localFaker.InputName, + + // FakeIt / Date/Time + "fakeit_Date": localFaker.Date, + "fakeit_PastDate": localFaker.PastDate, + "fakeit_FutureDate": localFaker.FutureDate, + "fakeit_DateRange": localFaker.DateRange, + "fakeit_NanoSecond": localFaker.NanoSecond, + "fakeit_Second": localFaker.Second, + "fakeit_Minute": localFaker.Minute, + "fakeit_Hour": localFaker.Hour, + "fakeit_Month": localFaker.Month, + "fakeit_MonthString": localFaker.MonthString, + "fakeit_Day": localFaker.Day, + "fakeit_WeekDay": localFaker.WeekDay, + "fakeit_Year": localFaker.Year, + "fakeit_TimeZone": localFaker.TimeZone, + "fakeit_TimeZoneAbv": localFaker.TimeZoneAbv, + "fakeit_TimeZoneFull": localFaker.TimeZoneFull, + "fakeit_TimeZoneOffset": localFaker.TimeZoneOffset, + "fakeit_TimeZoneRegion": localFaker.TimeZoneRegion, + + // FakeIt / Payment + "fakeit_Price": localFaker.Price, + "fakeit_CreditCardCvv": localFaker.CreditCardCvv, + "fakeit_CreditCardExp": localFaker.CreditCardExp, + "fakeit_CreditCardNumber": localFaker.CreditCardNumber, + "fakeit_CreditCardType": localFaker.CreditCardType, + "fakeit_CurrencyLong": localFaker.CurrencyLong, + "fakeit_CurrencyShort": localFaker.CurrencyShort, + "fakeit_AchRouting": localFaker.AchRouting, + "fakeit_AchAccount": localFaker.AchAccount, + "fakeit_BitcoinAddress": localFaker.BitcoinAddress, + "fakeit_BitcoinPrivateKey": localFaker.BitcoinPrivateKey, + + // FakeIt / Finance + "fakeit_Cusip": localFaker.Cusip, + "fakeit_Isin": localFaker.Isin, + + // FakeIt / Company + "fakeit_BS": localFaker.BS, + "fakeit_Blurb": localFaker.Blurb, + "fakeit_BuzzWord": localFaker.BuzzWord, + "fakeit_Company": localFaker.Company, + "fakeit_CompanySuffix": localFaker.CompanySuffix, + "fakeit_JobDescriptor": localFaker.JobDescriptor, + "fakeit_JobLevel": localFaker.JobLevel, + "fakeit_JobTitle": localFaker.JobTitle, + "fakeit_Slogan": localFaker.Slogan, + + // FakeIt / Hacker + "fakeit_HackerAbbreviation": localFaker.HackerAbbreviation, + "fakeit_HackerAdjective": localFaker.HackerAdjective, + "fakeit_HackerNoun": localFaker.HackerNoun, + "fakeit_HackerPhrase": localFaker.HackerPhrase, + "fakeit_HackerVerb": localFaker.HackerVerb, + + // FakeIt / Hipster + "fakeit_HipsterWord": localFaker.HipsterWord, + "fakeit_HipsterSentence": localFaker.HipsterSentence, + "fakeit_HipsterParagraph": localFaker.HipsterParagraph, + + // FakeIt / App + "fakeit_AppName": localFaker.AppName, + "fakeit_AppVersion": localFaker.AppVersion, + "fakeit_AppAuthor": localFaker.AppAuthor, + + // FakeIt / Animal + "fakeit_PetName": localFaker.PetName, + "fakeit_Animal": localFaker.Animal, + "fakeit_AnimalType": localFaker.AnimalType, + "fakeit_FarmAnimal": localFaker.FarmAnimal, + "fakeit_Cat": localFaker.Cat, + "fakeit_Dog": localFaker.Dog, + "fakeit_Bird": localFaker.Bird, + + // FakeIt / Emoji + "fakeit_Emoji": localFaker.Emoji, + "fakeit_EmojiDescription": localFaker.EmojiDescription, + "fakeit_EmojiCategory": localFaker.EmojiCategory, + "fakeit_EmojiAlias": localFaker.EmojiAlias, + "fakeit_EmojiTag": localFaker.EmojiTag, + + // FakeIt / Language + "fakeit_Language": localFaker.Language, + "fakeit_LanguageAbbreviation": localFaker.LanguageAbbreviation, + "fakeit_ProgrammingLanguage": localFaker.ProgrammingLanguage, + + // FakeIt / Number + "fakeit_Number": localFaker.Number, + "fakeit_Int": localFaker.Int, + "fakeit_IntN": localFaker.IntN, + "fakeit_Int8": localFaker.Int8, + "fakeit_Int16": localFaker.Int16, + "fakeit_Int32": localFaker.Int32, + "fakeit_Int64": localFaker.Int64, + "fakeit_Uint": localFaker.Uint, + "fakeit_UintN": localFaker.UintN, + "fakeit_Uint8": localFaker.Uint8, + "fakeit_Uint16": localFaker.Uint16, + "fakeit_Uint32": localFaker.Uint32, + "fakeit_Uint64": localFaker.Uint64, + "fakeit_Float32": localFaker.Float32, + "fakeit_Float32Range": localFaker.Float32Range, + "fakeit_Float64": localFaker.Float64, + "fakeit_Float64Range": localFaker.Float64Range, + "fakeit_HexUint": localFaker.HexUint, + + // FakeIt / String + "fakeit_Digit": localFaker.Digit, + "fakeit_DigitN": localFaker.DigitN, + "fakeit_Letter": localFaker.Letter, + "fakeit_LetterN": localFaker.LetterN, + "fakeit_Lexify": localFaker.Lexify, + "fakeit_Numerify": localFaker.Numerify, + + // FakeIt / Celebrity + "fakeit_CelebrityActor": localFaker.CelebrityActor, + "fakeit_CelebrityBusiness": localFaker.CelebrityBusiness, + "fakeit_CelebritySport": localFaker.CelebritySport, + + // FakeIt / Minecraft + "fakeit_MinecraftOre": localFaker.MinecraftOre, + "fakeit_MinecraftWood": localFaker.MinecraftWood, + "fakeit_MinecraftArmorTier": localFaker.MinecraftArmorTier, + "fakeit_MinecraftArmorPart": localFaker.MinecraftArmorPart, + "fakeit_MinecraftWeapon": localFaker.MinecraftWeapon, + "fakeit_MinecraftTool": localFaker.MinecraftTool, + "fakeit_MinecraftDye": localFaker.MinecraftDye, + "fakeit_MinecraftFood": localFaker.MinecraftFood, + "fakeit_MinecraftAnimal": localFaker.MinecraftAnimal, + "fakeit_MinecraftVillagerJob": localFaker.MinecraftVillagerJob, + "fakeit_MinecraftVillagerStation": localFaker.MinecraftVillagerStation, + "fakeit_MinecraftVillagerLevel": localFaker.MinecraftVillagerLevel, + "fakeit_MinecraftMobPassive": localFaker.MinecraftMobPassive, + "fakeit_MinecraftMobNeutral": localFaker.MinecraftMobNeutral, + "fakeit_MinecraftMobHostile": localFaker.MinecraftMobHostile, + "fakeit_MinecraftMobBoss": localFaker.MinecraftMobBoss, + "fakeit_MinecraftBiome": localFaker.MinecraftBiome, + "fakeit_MinecraftWeather": localFaker.MinecraftWeather, + + // FakeIt / Book + "fakeit_BookTitle": localFaker.BookTitle, + "fakeit_BookAuthor": localFaker.BookAuthor, + "fakeit_BookGenre": localFaker.BookGenre, + + // FakeIt / Movie + "fakeit_MovieName": localFaker.MovieName, + "fakeit_MovieGenre": localFaker.MovieGenre, + + // FakeIt / Error + "fakeit_Error": localFaker.Error, + "fakeit_ErrorDatabase": localFaker.ErrorDatabase, + "fakeit_ErrorGRPC": localFaker.ErrorGRPC, + "fakeit_ErrorHTTP": localFaker.ErrorHTTP, + "fakeit_ErrorHTTPClient": localFaker.ErrorHTTPClient, + "fakeit_ErrorHTTPServer": localFaker.ErrorHTTPServer, + "fakeit_ErrorRuntime": localFaker.ErrorRuntime, + + // FakeIt / School + "fakeit_School": localFaker.School, + + // FakeIt / Song + "fakeit_SongName": localFaker.SongName, + "fakeit_SongArtist": localFaker.SongArtist, + "fakeit_SongGenre": localFaker.SongGenre, + } +}