One spelling per shape: reject a one-item choice, a repeated item and an inert object; reshape the data

This commit is contained in:
2026-09-02 12:38:59 +02:00
parent de8c1d13e9
commit 054f99c94f
49 changed files with 620 additions and 593 deletions
+1
View File
@@ -1,3 +1,4 @@
.claude
*.out
__pycache__/
todo.md
+14 -13
View File
@@ -219,10 +219,11 @@ within a choice:
]
```
Only template (object) nodes carry `weight` — a bare string or nested array in a
choice always counts as `1`. Weights are checked when you create the generator: a
negative, non-numeric, or all-zero set is rejected at `New`, so a typo fails
fast instead of silently skewing output.
A bare string or nested array in a choice counts as `1`; to weight a string,
write it as `{ "format": "AB", "weight": 3 }`. A repeated item is a load error
naming that spelling, and so is a `weight` of `1`. Weights are checked when you
create the generator: a negative, non-numeric, or all-zero set is rejected at
`New`, so a typo fails fast instead of silently skewing output.
**Repeat.** A template node may carry a `repeat` (default `1`) to render its
`format` that many times — each render an independent pick — joined by
@@ -232,14 +233,16 @@ fast instead of silently skewing output.
{ "format": "{word}", "repeat": 3, "separator": " ", "word": ["foo", "bar", "baz"] }
```
This yields e.g. `bar foo baz`. `repeat` must be a positive integer and
This yields e.g. `bar foo baz`. `repeat` must be an integer above `1` and
`separator` a string, both checked at `New`.
`format`, `weight`, `repeat` and `separator` are the only options; **any other key
is a field**. So write `seperator` and you get a field by that name while the
option stays unset. `New` rejects an option that cannot take effect — a
`separator` without a `repeat` above 1, a `weight` outside a choice — and a name
using a character the grammars reserve: `.` separates the segments of a path, `|`
`separator` without a `repeat`, a `weight` outside a choice, a `weight` or
`repeat` of `1` — an object holding only a `format` (that is a string; write it),
a one-item choice (that is its item; write it), and a name using a character the
grammars reserve: `.` separates the segments of a path, `|`
the arms of a token, `(` opens a function call and `{` `}` delimit the token, so a
name carrying one is a name no format could ever spell. An empty name goes the same
way — it is no path segment at all, so `List` never offers it. That holds for a
@@ -337,7 +340,7 @@ data dirs:
```
renders e.g. `Hej, Pat Smith!`. References are bound when you create the generator, so
a path that is unknown, names a folder, or steps through a multi-variant choice
a path that is unknown, names a folder, or steps through a choice
fails at `New`. A reference that leads back to its own value (directly, mutually,
or through a chain) is a cycle that would never finish rendering, so it too is
rejected at `New`.
@@ -401,7 +404,7 @@ The binding lasts for one expansion, so each `repeat` iteration draws again and
nested template keeps its own. A field no dotted token addresses is unaffected:
`{word} {word}` still draws twice.
`New` checks a path the way `Fake` resolves one: every variant of a multi-variant
`New` checks a path the way `Fake` resolves one: every variant of a
choice must carry the whole path, so a row missing a field is named at load:
```text
@@ -435,8 +438,7 @@ A lone `}` is a load error naming `}}`.
**Putting it together** (`person.json`):
```json
[
{
{
"format": "{prefix}{femalefirst|malefirst} {last}",
"femalefirst": ["Anna", "Astrid", "Elin"],
"malefirst": ["Anders", "Erik", "Gustav"],
@@ -448,8 +450,7 @@ A lone `}` is a load error naming `}}`.
"",
{ "format": "{string} ", "string": ["dr", "prof"], "weight": 0.05 }
]
}
]
}
```
This yields e.g. `Anna Eriksson`, `Erik Berg`, or rarely `dr Astrid von Flemming`.
+6 -13
View File
@@ -1,24 +1,17 @@
[
{
{
"format": "{street-number} {street}\n{locality}, {region} {postal-code}",
"street": [
{
"street": {
"format": "{name} {suffix}",
"name": ["Adams", "Ashby", "Aspen", "Bay", "Birch", "Bridge", "Cedar", "Chestnut", "Church", "Clark", "Cypress", "Dogwood", "Elm", "Forest", "Franklin", "Garden", "Grove", "Hawthorn", "Hickory", "Highland", "Jackson", "Jefferson", "Juniper", "Lake", "Laurel", "Liberty", "Lincoln", "Madison", "Magnolia", "Maple", "Market", "Meadow", "Mill", "Oak", "Park", "Pine", "Poplar", "Prospect", "Ridge", "River", "Spruce", "Sunset", "Sycamore", "Union", "Walnut", "Washington", "Willow", "Wilson"],
"suffix": ["Avenue", "Boulevard", "Circle", "Court", "Drive", "Lane", "Place", "Road", "Street", "Terrace", "Trail", "Way"]
}
],
},
"street-number": [
{ "format": "{int(10,99)}" },
"{int(10,99)}",
{ "format": "{int(100,999)}", "weight": 2 },
{ "format": "{int(1000,9999)}", "weight": 0.5 },
{ "format": "{int(10,99)}{int(100,999)}", "weight": 0.3 }
],
"locality": ["Albany", "Atlanta", "Austin", "Baltimore", "Boston", "Charlotte", "Chicago", "Cincinnati", "Cleveland", "Columbus", "Dallas", "Denver", "Detroit", "El Paso", "Fort Worth", "Fresno", "Houston", "Indianapolis", "Jacksonville", "Kansas City", "Las Vegas", "Long Beach", "Los Angeles", "Memphis", "Mesa", "Miami", "Milwaukee", "Minneapolis", "Nashville", "New Orleans", "Oakland", "Oklahoma City", "Omaha", "Orlando", "Philadelphia", "Phoenix", "Pittsburgh", "Portland", "Raleigh", "Sacramento", "San Antonio", "San Diego", "San Jose", "Seattle", "St. Louis", "Tampa", "Tucson", "Tulsa"],
"region": ["AL", "AZ", "CA", "CO", "CT", "FL", "GA", "IL", "IN", "KY", "LA", "MA", "MD", "MI", "MN", "MO", "NC", "NJ", "NV", "NY", "OH", "OK", "OR", "PA", "TN", "TX", "VA", "WA", "WI"],
"postal-code": [
{ "format": "{int(10000,99999)}" },
{ "format": "{int(10000,99999)}-{digits(4)}", "weight": 0.3 }
]
}
]
"postal-code": ["{int(10000,99999)}", { "format": "{int(10000,99999)}-{digits(4)}", "weight": 0.3 }]
}
+3 -5
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{base} {suffix}",
"base": [
{
@@ -9,6 +8,5 @@
},
["Atlas Industries", "Beacon Labs", "Cedar & Vine", "Compass Group", "Evergreen Trading", "Harbor Logistics", "Hudson Partners", "Liberty Holdings", "Meridian Capital", "Northgate Studios", "Pinnacle Systems", "Riverside", "Sequoia Foods", "Smith & Sons", "Stonebridge Ventures", "Sunrise Bakery", "Wexford Holdings"]
],
"suffix": ["Co.", "Corp.", "Group", "Inc.", "Inc.", "LLC", "LLC", "Ltd."]
}
]
"suffix": ["Co.", "Corp.", "Group", { "format": "Inc.", "weight": 2 }, { "format": "LLC", "weight": 2 }, "Ltd."]
}
+4 -6
View File
@@ -1,15 +1,13 @@
[
{
{
"format": "{month}/{day}/{year}",
"month": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
"day": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"],
"year": [
{ "format": "197{digits(1)}" },
{ "format": "198{digits(1)}" },
"197{digits(1)}",
"198{digits(1)}",
{ "format": "199{digits(1)}", "weight": 2 },
{ "format": "200{digits(1)}", "weight": 3 },
{ "format": "201{digits(1)}", "weight": 3 },
{ "format": "202{digits(1)}", "weight": 2 }
]
}
]
}
+6 -9
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{local}@{domain}",
"local": [
{
@@ -7,23 +6,21 @@
"weight": 3,
"first": ["alex", "amelia", "andrew", "anna", "ava", "benjamin", "carter", "charlotte", "chloe", "chris", "daniel", "david", "dylan", "elijah", "ella", "emily", "emma", "ethan", "evelyn", "gabriel", "grace", "hannah", "harper", "henry", "isaac", "isabella", "jack", "jacob", "james", "john", "joseph", "julia", "leah", "liam", "linda", "lily", "logan", "lucas", "luke", "mary", "mason", "matthew", "maya", "mia", "michael", "natalie", "noah", "nora", "oliver", "olivia", "owen", "patricia", "robert", "ryan", "samuel", "sarah", "sofia", "sophia", "thomas", "victoria", "william", "zoe"],
"last": ["adams", "allen", "anderson", "bailey", "baker", "bennett", "brooks", "brown", "campbell", "carter", "clark", "collins", "cook", "cooper", "davis", "edwards", "evans", "fisher", "flores", "foster", "garcia", "gonzalez", "gray", "green", "hall", "harris", "hayes", "hernandez", "hill", "howard", "hughes", "jackson", "jenkins", "johnson", "jones", "kelly", "king", "lee", "lewis", "long", "lopez", "martin", "martinez", "miller", "mitchell", "moore", "morgan", "morris", "murphy", "nelson", "parker", "perez", "perry", "phillips", "powell", "price", "reed", "reyes", "rivera", "roberts", "robinson", "rodriguez", "rogers", "ross", "russell", "sanchez", "sanders", "scott", "smith", "stewart", "sullivan", "taylor", "thomas", "thompson", "torres", "turner", "walker", "ward", "watson", "white", "williams", "wilson", "wood", "wright", "young"],
"sep": [".", ".", "_", "-", ""],
"n": ["", "", "", "1", "7", "21", "42", "88", "99", "2024"]
"sep": [{ "format": ".", "weight": 2 }, "_", "-", ""],
"n": [{ "format": "", "weight": 3 }, "1", "7", "21", "42", "88", "99", "2024"]
},
{
"format": "{adj}{noun}{n}",
"weight": 2,
"adj": ["blue", "cool", "dark", "epic", "fast", "fluffy", "frosty", "funky", "fuzzy", "golden", "grumpy", "happy", "hyper", "jazzy", "lazy", "lucky", "mega", "mighty", "neon", "ninja", "quiet", "rad", "rusty", "salty", "shiny", "silent", "sleepy", "snappy", "sneaky", "spicy", "super", "swift", "turbo", "wild", "witty", "zany"],
"noun": ["badger", "banana", "comet", "dragon", "falcon", "ferret", "goblin", "hamster", "koala", "llama", "mango", "muffin", "narwhal", "ninja", "noodle", "otter", "panda", "penguin", "pickle", "pirate", "pixel", "potato", "pretzel", "raccoon", "raptor", "robot", "taco", "toast", "trunk", "turtle", "unicorn", "viking", "waffle", "walrus", "wizard", "yeti"],
"n": ["", "", "7", "13", "14", "42", "77", "99", "123", "420", "2024"]
"n": [{ "format": "", "weight": 2 }, "7", "13", "14", "42", "77", "99", "123", "420", "2024"]
},
{
"format": "{w}{n}",
"weight": 1,
"w": ["blooper", "blupp", "boop", "byteme", "coolcat", "derpina", "doomguy", "epicgamer", "fizzbuzz", "glitchlord", "glorptron", "gronkzilla", "kapowski", "lazerwolf", "megashark", "mooncat", "narfle", "nightowl", "noodlemaster", "oofster", "pixelfox", "pixelpusher", "plonkers", "retrowave", "snork", "splatmaster", "stardust", "superdog", "voidwalker", "vroom", "wahoo", "waooooh", "wootwoot", "yeetus", "zapper", "zoomzoom"],
"n": ["", "", "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
"n": [{ "format": "", "weight": 2 }, "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
}
],
"domain": ["example.com", "example.org", "example.net", "example.io", "example.co", "example.dev", "example.app", "mail.example.com", "mail.example.org", "webmail.example.net", "inbox.example.com", "post.example.org", "demo.example.net", "test.example.org", "dev.example.io"]
}
]
}
+6 -4
View File
@@ -2,9 +2,11 @@
{
"format": "{o}.{o}.{o}.{o}",
"weight": 8,
"o": [{ "format": "{digits(1)}", "weight": 3 }, { "format": "{int(10,99)}", "weight": 4 }, { "format": "1{digits(2)}", "weight": 2 }]
"o": [
{ "format": "{digits(1)}", "weight": 3 },
{ "format": "{int(10,99)}", "weight": 4 },
{ "format": "1{digits(2)}", "weight": 2 }
]
},
{
"format": "{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}"
}
"{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}"
]
+3 -12
View File
@@ -1,16 +1,7 @@
[
{
{
"format": "{prefix}{femalefirst|malefirst} {last}",
"femalefirst": ["Abigail", "Addison", "Amelia", "Aria", "Aubrey", "Audrey", "Aurora", "Ava", "Bella", "Brooklyn", "Camila", "Caroline", "Charlotte", "Chloe", "Claire", "Eleanor", "Elizabeth", "Ella", "Ellie", "Emily", "Emma", "Evelyn", "Gianna", "Grace", "Hannah", "Harper", "Hazel", "Isabella", "Layla", "Leah", "Lillian", "Lily", "Lucy", "Luna", "Madison", "Maya", "Mia", "Mila", "Naomi", "Natalie", "Nora", "Olivia", "Paisley", "Penelope", "Riley", "Savannah", "Scarlett", "Sofia", "Sophia", "Stella", "Victoria", "Violet", "Zoe"],
"malefirst": ["Aiden", "Alexander", "Andrew", "Anthony", "Asher", "Benjamin", "Caleb", "Carter", "Charles", "Christopher", "Daniel", "David", "Dylan", "Elijah", "Ethan", "Ezra", "Gabriel", "Grayson", "Henry", "Isaac", "Jack", "Jackson", "Jacob", "James", "Jayden", "John", "Joseph", "Joshua", "Julian", "Levi", "Liam", "Lincoln", "Logan", "Lucas", "Luke", "Mason", "Mateo", "Matthew", "Michael", "Nathan", "Noah", "Oliver", "Owen", "Samuel", "Sebastian", "Theodore", "Thomas", "William", "Wyatt"],
"last": ["Adams", "Allen", "Anderson", "Bailey", "Baker", "Bell", "Bennett", "Brooks", "Brown", "Campbell", "Carter", "Clark", "Collins", "Cook", "Cooper", "Cox", "Davis", "Edwards", "Evans", "Flores", "Foster", "Garcia", "Gonzalez", "Gray", "Green", "Hall", "Harris", "Hayes", "Hernandez", "Hill", "Howard", "Hughes", "Jackson", "James", "Jenkins", "Johnson", "Jones", "Kelly", "King", "Lee", "Lewis", "Long", "Lopez", "Martin", "Martinez", "Miller", "Mitchell", "Moore", "Morgan", "Morris", "Murphy", "Nelson", "Parker", "Perez", "Perry", "Peterson", "Phillips", "Powell", "Price", "Ramirez", "Reed", "Richardson", "Rivera", "Roberts", "Robinson", "Rodriguez", "Rogers", "Ross", "Russell", "Sanchez", "Sanders", "Scott", "Smith", "Stewart", "Sullivan", "Taylor", "Thomas", "Thompson", "Torres", "Turner", "Walker", "Ward", "Watson", "White", "Williams", "Wilson", "Wood", "Wright", "Young"],
"prefix": [
"",
{
"format": "{title} ",
"title": ["Dr", "Miss", "Mr", "Mrs", "Ms", "Mx", "Prof"],
"weight": 0.1
}
]
}
]
"prefix": ["", { "format": "{title} ", "title": ["Dr", "Miss", "Mr", "Mrs", "Ms", "Mx", "Prof"], "weight": 0.1 }]
}
+4 -4
View File
@@ -3,13 +3,13 @@
"format": "({area}) {exch}-{line}",
"weight": 2,
"area": ["202", "212", "213", "305", "312", "404", "415", "469", "503", "512", "602", "617", "646", "702", "718", "720", "737", "773", "786", "808", "917"],
"exch": [{ "format": "{int(100,999)}" }],
"line": [{ "format": "{digits(4)}" }]
"exch": "{int(100,999)}",
"line": "{digits(4)}"
},
{
"format": "{area}-{exch}-{line}",
"area": ["202", "212", "213", "305", "312", "404", "415", "469", "503", "512", "602", "617", "646", "702", "718", "720", "737", "773", "786", "808", "917"],
"exch": [{ "format": "{int(100,999)}" }],
"line": [{ "format": "{digits(4)}" }]
"exch": "{int(100,999)}",
"line": "{digits(4)}"
}
]
+4 -11
View File
@@ -1,19 +1,12 @@
[
{
{
"format": "${amt}.{cents}",
"amt": [
{ "format": "{int(1,9)}", "weight": 2 },
{ "format": "{int(10,99)}", "weight": 4 },
{ "format": "{int(100,999)}", "weight": 3 },
{ "format": "{int(1,9)},{digits(3)}", "weight": 1 },
"{int(1,9)},{digits(3)}",
{ "format": "{int(10,99)},{digits(3)}", "weight": 0.4 },
{ "format": "{int(100,999)},{digits(3)}", "weight": 0.1 }
],
"cents": [
{ "format": "{digits(2)}", "weight": 3 },
"49",
"95",
"99"
]
}
]
"cents": [{ "format": "{digits(2)}", "weight": 3 }, "49", "95", "99"]
}
+2 -2
View File
@@ -7,7 +7,7 @@
"noun": ["anchor", "archer", "beacon", "bridge", "captain", "cavern", "cottage", "ember", "engine", "falcon", "ferry", "forest", "fox", "garden", "glacier", "harbor", "hermit", "hollow", "island", "lantern", "lighthouse", "mariner", "meadow", "mountain", "orchard", "otter", "pilgrim", "prairie", "quarry", "raven", "ridge", "river", "sailor", "scholar", "signal", "sparrow", "stranger", "summit", "thicket", "tower", "traveler", "valley", "voyager", "wanderer", "willow", "woodland"],
"verb": ["abandons", "anchors", "awakens", "befriends", "builds", "calms", "carries", "chases", "conceals", "crosses", "embraces", "follows", "gathers", "greets", "guards", "guides", "haunts", "heralds", "honors", "kindles", "leads", "mends", "mirrors", "outlasts", "ponders", "reveals", "salutes", "shapes", "shelters", "shields", "summons", "tends", "traces", "weathers"],
"prep": ["above", "across", "against", "alongside", "amid", "around", "beneath", "beside", "between", "beyond", "near", "over", "past", "through", "toward", "under", "within"],
"end": [".", ".", ".", ".", "!"]
"end": [{ "format": ".", "weight": 4 }, "!"]
},
{
"format": "{lead} {noun} {adv} {verb} {prep} {adj} {noun}{end}",
@@ -18,7 +18,7 @@
"verb": ["builds", "carries", "chases", "crosses", "follows", "gathers", "guards", "guides", "leads", "mirrors", "outlasts", "reveals", "shapes", "shelters", "summons", "tends", "traces", "weathers"],
"adj": ["ancient", "bright", "distant", "fierce", "fragile", "gentle", "golden", "hidden", "lonely", "quiet", "restless", "rugged", "silent", "stormy", "weary", "wild"],
"prep": ["across", "against", "alongside", "amid", "beneath", "between", "beyond", "near", "over", "past", "through", "toward", "within"],
"end": [".", ".", ".", "!"]
"end": [{ "format": ".", "weight": 3 }, "!"]
},
{
"format": "{q} {adj} {noun} {verb} {prep} {adj} {noun}?",
+1 -3
View File
@@ -1,3 +1 @@
[
{ "format": "{int(100,999)}-{digits(2)}-{digits(4)}" }
]
"{int(100,999)}-{digits(2)}-{digits(4)}"
+3 -5
View File
@@ -1,8 +1,6 @@
[
{
{
"format": "{hour}:{minute} {ampm}",
"hour": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
"minute": [{ "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] }],
"minute": { "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] },
"ampm": ["AM", "PM"]
}
]
}
+13 -8
View File
@@ -1,12 +1,17 @@
[
{
{
"format": "https://{host}{path}",
"host": ["example.com", "www.example.com", "example.org", "www.example.org", "example.net", "example.io", "example.co", "blog.example.com", "blog.example.net", "shop.example.com", "store.example.org", "app.example.io", "api.example.com", "docs.example.org", "news.example.net", "mail.example.com"],
"path": [
"",
"",
{ "format": "/{seg}", "seg": ["about", "account", "blog", "careers", "cart", "categories", "checkout", "contact", "dashboard", "downloads", "events", "faq", "features", "help", "home", "items", "login", "news", "order", "pricing", "privacy", "products", "profile", "register", "search", "settings", "signup", "support", "terms", "welcome"] },
{ "format": "/{seg}/{sub}", "weight": 0.5, "seg": ["blog", "docs", "help", "products", "category", "user"], "sub": ["getting-started", "overview", "guide", "2024", "latest", "popular", "archive", "details"] }
]
{ "format": "", "weight": 2 },
{
"format": "/{seg}",
"seg": ["about", "account", "blog", "careers", "cart", "categories", "checkout", "contact", "dashboard", "downloads", "events", "faq", "features", "help", "home", "items", "login", "news", "order", "pricing", "privacy", "products", "profile", "register", "search", "settings", "signup", "support", "terms", "welcome"]
},
{
"format": "/{seg}/{sub}",
"weight": 0.5,
"seg": ["blog", "docs", "help", "products", "category", "user"],
"sub": ["getting-started", "overview", "guide", "2024", "latest", "popular", "archive", "details"]
}
]
]
}
+5 -6
View File
@@ -4,21 +4,20 @@
"weight": 2,
"first": ["alex", "ash", "avery", "bailey", "blake", "cameron", "casey", "charlie", "chris", "dakota", "drew", "elliot", "emerson", "finley", "frankie", "harley", "hayden", "jamie", "jordan", "kai", "kendall", "lane", "logan", "morgan", "parker", "quinn", "reese", "riley", "rowan", "sam", "sawyer", "skyler", "spencer", "taylor"],
"last": ["adams", "brooks", "carter", "cole", "evans", "fisher", "fox", "grant", "gray", "hayes", "hunt", "lane", "lowe", "marsh", "mason", "morris", "north", "page", "quinn", "reed", "rhodes", "shaw", "stone", "vale", "wells", "west", "wolfe"],
"sep": ["", "", "", ".", "_"],
"n": ["", "", "", "", "1", "7", "12", "23", "42", "77", "99", "2024"]
"sep": [{ "format": "", "weight": 3 }, ".", "_"],
"n": [{ "format": "", "weight": 4 }, "1", "7", "12", "23", "42", "77", "99", "2024"]
},
{
"format": "{adj}{sep}{noun}{n}",
"weight": 2,
"adj": ["bluish", "brave", "chill", "cosmic", "cool", "dizzy", "electric", "epic", "fluffy", "frosty", "funky", "fuzzy", "golden", "groovy", "grumpy", "happy", "hyper", "jazzy", "lucky", "mega", "mighty", "neon", "nimble", "quirky", "rad", "rusty", "salty", "shiny", "silent", "sleepy", "snappy", "sneaky", "sparkly", "spicy", "sunny", "super", "swift", "turbo", "wild", "witty", "zany"],
"noun": ["badger", "biscuit", "cactus", "comet", "donut", "dragon", "falcon", "ferret", "gizmo", "goblin", "hamster", "koala", "llama", "mango", "muffin", "narwhal", "noodle", "otter", "panda", "penguin", "pickle", "pirate", "pixel", "potato", "pretzel", "raccoon", "raptor", "robot", "taco", "toast", "trunk", "turtle", "unicorn", "viking", "waffle", "walrus", "wizard", "yeti"],
"sep": ["", "", "", ".", "_"],
"n": ["", "", "7", "13", "42", "77", "99", "123", "420", "2024"]
"sep": [{ "format": "", "weight": 3 }, ".", "_"],
"n": [{ "format": "", "weight": 2 }, "7", "13", "42", "77", "99", "123", "420", "2024"]
},
{
"format": "{w}{n}",
"weight": 1,
"w": ["blooper", "blupp", "boop", "byteme", "coolcat", "derpina", "doomguy", "epicgamer", "fizzbuzz", "glitchlord", "glorptron", "gronkzilla", "kapowski", "lazerwolf", "megashark", "mooncat", "narfle", "nightowl", "noodlemaster", "oofster", "pixelfox", "pixelpusher", "plonkers", "retrowave", "snork", "splatmaster", "stardust", "superdog", "voidwalker", "vroom", "wahoo", "waooooh", "wootwoot", "yeetus", "zapper", "zoomzoom"],
"n": ["", "", "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
"n": [{ "format": "", "weight": 2 }, "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
}
]
+3 -5
View File
@@ -1,8 +1,6 @@
[
{
{
"format": "{pre}{n}.{n}.{n}{suffix}",
"n": [{ "format": "{digits(1)}", "weight": 3 }, { "format": "{int(10,99)}" }],
"n": [{ "format": "{digits(1)}", "weight": 3 }, "{int(10,99)}"],
"pre": ["", { "format": "v", "weight": 0.4 }],
"suffix": ["", { "format": "-{tag}.{m}", "tag": ["alpha", "beta", "rc"], "m": ["1", "2", "3"], "weight": 0.3 }]
}
]
}
+8 -8
View File
@@ -1,10 +1,10 @@
[
{ "format": "{maker} {model}", "maker": ["BMW"], "model": ["3 Series", "5 Series", "X3", "X5"] },
{ "format": "{maker} {model}", "maker": ["Ford"], "model": ["Fiesta", "Focus", "Mustang", "Explorer"] },
{ "format": "{maker} {model}", "maker": ["Honda"], "model": ["Civic", "Accord", "CR-V", "Jazz"] },
{ "format": "{maker} {model}", "maker": ["Mercedes-Benz"], "model": ["A-Class", "C-Class", "E-Class", "GLC"] },
{ "format": "{maker} {model}", "maker": ["Tesla"], "model": ["Model 3", "Model S", "Model X", "Model Y"] },
{ "format": "{maker} {model}", "maker": ["Toyota"], "model": ["Corolla", "Camry", "RAV4", "Yaris"] },
{ "format": "{maker} {model}", "maker": ["Volkswagen"], "model": ["Golf", "Passat", "Polo", "Tiguan"] },
{ "format": "{maker} {model}", "maker": ["Volvo"], "model": ["XC40", "XC60", "XC90", "V60"] }
{ "format": "{maker} {model}", "maker": "BMW", "model": ["3 Series", "5 Series", "X3", "X5"] },
{ "format": "{maker} {model}", "maker": "Ford", "model": ["Fiesta", "Focus", "Mustang", "Explorer"] },
{ "format": "{maker} {model}", "maker": "Honda", "model": ["Civic", "Accord", "CR-V", "Jazz"] },
{ "format": "{maker} {model}", "maker": "Mercedes-Benz", "model": ["A-Class", "C-Class", "E-Class", "GLC"] },
{ "format": "{maker} {model}", "maker": "Tesla", "model": ["Model 3", "Model S", "Model X", "Model Y"] },
{ "format": "{maker} {model}", "maker": "Toyota", "model": ["Corolla", "Camry", "RAV4", "Yaris"] },
{ "format": "{maker} {model}", "maker": "Volkswagen", "model": ["Golf", "Passat", "Polo", "Tiguan"] },
{ "format": "{maker} {model}", "maker": "Volvo", "model": ["XC40", "XC60", "XC90", "V60"] }
]
+1 -7
View File
@@ -1,7 +1 @@
[
{
"format": "{lat}, {lon}",
"lat": { "format": "{float(-90,90,6)}" },
"lon": { "format": "{float(-180,180,6)}" }
}
]
{ "format": "{lat}, {lon}", "lat": "{float(-90,90,6)}", "lon": "{float(-180,180,6)}" }
+20 -20
View File
@@ -1,22 +1,22 @@
[
{ "format": "{name}", "name": ["Australia"], "alpha2": ["AU"], "alpha3": ["AUS"] },
{ "format": "{name}", "name": ["Brazil"], "alpha2": ["BR"], "alpha3": ["BRA"] },
{ "format": "{name}", "name": ["Canada"], "alpha2": ["CA"], "alpha3": ["CAN"] },
{ "format": "{name}", "name": ["China"], "alpha2": ["CN"], "alpha3": ["CHN"] },
{ "format": "{name}", "name": ["Denmark"], "alpha2": ["DK"], "alpha3": ["DNK"] },
{ "format": "{name}", "name": ["Finland"], "alpha2": ["FI"], "alpha3": ["FIN"] },
{ "format": "{name}", "name": ["France"], "alpha2": ["FR"], "alpha3": ["FRA"] },
{ "format": "{name}", "name": ["Germany"], "alpha2": ["DE"], "alpha3": ["DEU"] },
{ "format": "{name}", "name": ["India"], "alpha2": ["IN"], "alpha3": ["IND"] },
{ "format": "{name}", "name": ["Italy"], "alpha2": ["IT"], "alpha3": ["ITA"] },
{ "format": "{name}", "name": ["Japan"], "alpha2": ["JP"], "alpha3": ["JPN"] },
{ "format": "{name}", "name": ["Mexico"], "alpha2": ["MX"], "alpha3": ["MEX"] },
{ "format": "{name}", "name": ["Netherlands"], "alpha2": ["NL"], "alpha3": ["NLD"] },
{ "format": "{name}", "name": ["Norway"], "alpha2": ["NO"], "alpha3": ["NOR"] },
{ "format": "{name}", "name": ["Poland"], "alpha2": ["PL"], "alpha3": ["POL"] },
{ "format": "{name}", "name": ["Spain"], "alpha2": ["ES"], "alpha3": ["ESP"] },
{ "format": "{name}", "name": ["Sweden"], "alpha2": ["SE"], "alpha3": ["SWE"] },
{ "format": "{name}", "name": ["Switzerland"], "alpha2": ["CH"], "alpha3": ["CHE"] },
{ "format": "{name}", "name": ["United Kingdom"], "alpha2": ["GB"], "alpha3": ["GBR"] },
{ "format": "{name}", "name": ["United States"], "alpha2": ["US"], "alpha3": ["USA"] }
{ "format": "{name}", "name": "Australia", "alpha2": "AU", "alpha3": "AUS" },
{ "format": "{name}", "name": "Brazil", "alpha2": "BR", "alpha3": "BRA" },
{ "format": "{name}", "name": "Canada", "alpha2": "CA", "alpha3": "CAN" },
{ "format": "{name}", "name": "China", "alpha2": "CN", "alpha3": "CHN" },
{ "format": "{name}", "name": "Denmark", "alpha2": "DK", "alpha3": "DNK" },
{ "format": "{name}", "name": "Finland", "alpha2": "FI", "alpha3": "FIN" },
{ "format": "{name}", "name": "France", "alpha2": "FR", "alpha3": "FRA" },
{ "format": "{name}", "name": "Germany", "alpha2": "DE", "alpha3": "DEU" },
{ "format": "{name}", "name": "India", "alpha2": "IN", "alpha3": "IND" },
{ "format": "{name}", "name": "Italy", "alpha2": "IT", "alpha3": "ITA" },
{ "format": "{name}", "name": "Japan", "alpha2": "JP", "alpha3": "JPN" },
{ "format": "{name}", "name": "Mexico", "alpha2": "MX", "alpha3": "MEX" },
{ "format": "{name}", "name": "Netherlands", "alpha2": "NL", "alpha3": "NLD" },
{ "format": "{name}", "name": "Norway", "alpha2": "NO", "alpha3": "NOR" },
{ "format": "{name}", "name": "Poland", "alpha2": "PL", "alpha3": "POL" },
{ "format": "{name}", "name": "Spain", "alpha2": "ES", "alpha3": "ESP" },
{ "format": "{name}", "name": "Sweden", "alpha2": "SE", "alpha3": "SWE" },
{ "format": "{name}", "name": "Switzerland", "alpha2": "CH", "alpha3": "CHE" },
{ "format": "{name}", "name": "United Kingdom", "alpha2": "GB", "alpha3": "GBR" },
{ "format": "{name}", "name": "United States", "alpha2": "US", "alpha3": "USA" }
]
+16 -3
View File
@@ -1,5 +1,18 @@
[
{ "format": "4{d}{luhn()}", "d": { "format": "{digits(1)}", "repeat": 14 }, "weight": 4 },
{ "format": "5{m}{d}{luhn()}", "m": ["1", "2", "3", "4", "5"], "d": { "format": "{digits(1)}", "repeat": 13 }, "weight": 3 },
{ "format": "3{m}{d}{luhn()}", "m": ["4", "7"], "d": { "format": "{digits(1)}", "repeat": 12 }, "weight": 1 }
{
"format": "4{d}{luhn()}",
"d": { "format": "{digits(1)}", "repeat": 14 },
"weight": 4
},
{
"format": "5{m}{d}{luhn()}",
"m": ["1", "2", "3", "4", "5"],
"d": { "format": "{digits(1)}", "repeat": 13 },
"weight": 3
},
{
"format": "3{m}{d}{luhn()}",
"m": ["4", "7"],
"d": { "format": "{digits(1)}", "repeat": 12 }
}
]
+16 -16
View File
@@ -1,18 +1,18 @@
[
{ "format": "{code}", "code": ["AUD"], "name": ["Australian Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["BRL"], "name": ["Brazilian Real"], "symbol": ["R$"] },
{ "format": "{code}", "code": ["CAD"], "name": ["Canadian Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["CHF"], "name": ["Swiss Franc"], "symbol": ["CHF"] },
{ "format": "{code}", "code": ["CNY"], "name": ["Chinese Yuan"], "symbol": ["¥"] },
{ "format": "{code}", "code": ["DKK"], "name": ["Danish Krone"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["EUR"], "name": ["Euro"], "symbol": ["€"] },
{ "format": "{code}", "code": ["GBP"], "name": ["Pound Sterling"], "symbol": ["£"] },
{ "format": "{code}", "code": ["INR"], "name": ["Indian Rupee"], "symbol": ["₹"] },
{ "format": "{code}", "code": ["JPY"], "name": ["Japanese Yen"], "symbol": ["¥"] },
{ "format": "{code}", "code": ["MXN"], "name": ["Mexican Peso"], "symbol": ["$"] },
{ "format": "{code}", "code": ["NOK"], "name": ["Norwegian Krone"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["PLN"], "name": ["Polish Zloty"], "symbol": ["zł"] },
{ "format": "{code}", "code": ["SEK"], "name": ["Swedish Krona"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["USD"], "name": ["US Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["ZAR"], "name": ["South African Rand"], "symbol": ["R"] }
{ "format": "{code}", "code": "AUD", "name": "Australian Dollar", "symbol": "$" },
{ "format": "{code}", "code": "BRL", "name": "Brazilian Real", "symbol": "R$" },
{ "format": "{code}", "code": "CAD", "name": "Canadian Dollar", "symbol": "$" },
{ "format": "{code}", "code": "CHF", "name": "Swiss Franc", "symbol": "CHF" },
{ "format": "{code}", "code": "CNY", "name": "Chinese Yuan", "symbol": "¥" },
{ "format": "{code}", "code": "DKK", "name": "Danish Krone", "symbol": "kr" },
{ "format": "{code}", "code": "EUR", "name": "Euro", "symbol": "€" },
{ "format": "{code}", "code": "GBP", "name": "Pound Sterling", "symbol": "£" },
{ "format": "{code}", "code": "INR", "name": "Indian Rupee", "symbol": "₹" },
{ "format": "{code}", "code": "JPY", "name": "Japanese Yen", "symbol": "¥" },
{ "format": "{code}", "code": "MXN", "name": "Mexican Peso", "symbol": "$" },
{ "format": "{code}", "code": "NOK", "name": "Norwegian Krone", "symbol": "kr" },
{ "format": "{code}", "code": "PLN", "name": "Polish Zloty", "symbol": "zł" },
{ "format": "{code}", "code": "SEK", "name": "Swedish Krona", "symbol": "kr" },
{ "format": "{code}", "code": "USD", "name": "US Dollar", "symbol": "$" },
{ "format": "{code}", "code": "ZAR", "name": "South African Rand", "symbol": "R" }
]
+1 -6
View File
@@ -1,6 +1 @@
[
"😀", "😂", "😍", "🤔", "😎", "😭", "😡", "👍", "👎", "🙏",
"👏", "🙌", "💪", "🔥", "✨", "🎉", "❤️", "💔", "💯", "👀",
"🚀", "⭐", "🌈", "☀️", "🌙", "⚡", "❄️", "🍕", "🍔", "🍺",
"☕", "🎂", "🐶", "🐱", "🦊", "🐢", "🦄", "🌸", "🌍", "💡"
]
["😀", "😂", "😍", "🤔", "😎", "😭", "😡", "👍", "👎", "🙏", "👏", "🙌", "💪", "🔥", "✨", "🎉", "❤️", "💔", "💯", "👀", "🚀", "⭐", "🌈", "☀️", "🌙", "⚡", "❄️", "🍕", "🍔", "🍺", "☕", "🎂", "🐶", "🐱", "🦊", "🐢", "🦄", "🌸", "🌍", "💡"]
+16 -16
View File
@@ -1,18 +1,18 @@
[
{ "format": "{code} {reason}", "code": ["200"], "reason": ["OK"] },
{ "format": "{code} {reason}", "code": ["201"], "reason": ["Created"] },
{ "format": "{code} {reason}", "code": ["204"], "reason": ["No Content"] },
{ "format": "{code} {reason}", "code": ["301"], "reason": ["Moved Permanently"] },
{ "format": "{code} {reason}", "code": ["302"], "reason": ["Found"] },
{ "format": "{code} {reason}", "code": ["304"], "reason": ["Not Modified"] },
{ "format": "{code} {reason}", "code": ["400"], "reason": ["Bad Request"] },
{ "format": "{code} {reason}", "code": ["401"], "reason": ["Unauthorized"] },
{ "format": "{code} {reason}", "code": ["403"], "reason": ["Forbidden"] },
{ "format": "{code} {reason}", "code": ["404"], "reason": ["Not Found"] },
{ "format": "{code} {reason}", "code": ["409"], "reason": ["Conflict"] },
{ "format": "{code} {reason}", "code": ["422"], "reason": ["Unprocessable Entity"] },
{ "format": "{code} {reason}", "code": ["429"], "reason": ["Too Many Requests"] },
{ "format": "{code} {reason}", "code": ["500"], "reason": ["Internal Server Error"] },
{ "format": "{code} {reason}", "code": ["502"], "reason": ["Bad Gateway"] },
{ "format": "{code} {reason}", "code": ["503"], "reason": ["Service Unavailable"] }
{ "format": "{code} {reason}", "code": "200", "reason": "OK" },
{ "format": "{code} {reason}", "code": "201", "reason": "Created" },
{ "format": "{code} {reason}", "code": "204", "reason": "No Content" },
{ "format": "{code} {reason}", "code": "301", "reason": "Moved Permanently" },
{ "format": "{code} {reason}", "code": "302", "reason": "Found" },
{ "format": "{code} {reason}", "code": "304", "reason": "Not Modified" },
{ "format": "{code} {reason}", "code": "400", "reason": "Bad Request" },
{ "format": "{code} {reason}", "code": "401", "reason": "Unauthorized" },
{ "format": "{code} {reason}", "code": "403", "reason": "Forbidden" },
{ "format": "{code} {reason}", "code": "404", "reason": "Not Found" },
{ "format": "{code} {reason}", "code": "409", "reason": "Conflict" },
{ "format": "{code} {reason}", "code": "422", "reason": "Unprocessable Entity" },
{ "format": "{code} {reason}", "code": "429", "reason": "Too Many Requests" },
{ "format": "{code} {reason}", "code": "500", "reason": "Internal Server Error" },
{ "format": "{code} {reason}", "code": "502", "reason": "Bad Gateway" },
{ "format": "{code} {reason}", "code": "503", "reason": "Service Unavailable" }
]
+16 -16
View File
@@ -1,18 +1,18 @@
[
{ "format": "{name}", "name": ["Arabic"], "code": ["ar"] },
{ "format": "{name}", "name": ["Chinese"], "code": ["zh"] },
{ "format": "{name}", "name": ["Danish"], "code": ["da"] },
{ "format": "{name}", "name": ["Dutch"], "code": ["nl"] },
{ "format": "{name}", "name": ["English"], "code": ["en"] },
{ "format": "{name}", "name": ["Finnish"], "code": ["fi"] },
{ "format": "{name}", "name": ["French"], "code": ["fr"] },
{ "format": "{name}", "name": ["German"], "code": ["de"] },
{ "format": "{name}", "name": ["Italian"], "code": ["it"] },
{ "format": "{name}", "name": ["Japanese"], "code": ["ja"] },
{ "format": "{name}", "name": ["Norwegian"], "code": ["no"] },
{ "format": "{name}", "name": ["Polish"], "code": ["pl"] },
{ "format": "{name}", "name": ["Portuguese"], "code": ["pt"] },
{ "format": "{name}", "name": ["Russian"], "code": ["ru"] },
{ "format": "{name}", "name": ["Spanish"], "code": ["es"] },
{ "format": "{name}", "name": ["Swedish"], "code": ["sv"] }
{ "format": "{name}", "name": "Arabic", "code": "ar" },
{ "format": "{name}", "name": "Chinese", "code": "zh" },
{ "format": "{name}", "name": "Danish", "code": "da" },
{ "format": "{name}", "name": "Dutch", "code": "nl" },
{ "format": "{name}", "name": "English", "code": "en" },
{ "format": "{name}", "name": "Finnish", "code": "fi" },
{ "format": "{name}", "name": "French", "code": "fr" },
{ "format": "{name}", "name": "German", "code": "de" },
{ "format": "{name}", "name": "Italian", "code": "it" },
{ "format": "{name}", "name": "Japanese", "code": "ja" },
{ "format": "{name}", "name": "Norwegian", "code": "no" },
{ "format": "{name}", "name": "Polish", "code": "pl" },
{ "format": "{name}", "name": "Portuguese", "code": "pt" },
{ "format": "{name}", "name": "Russian", "code": "ru" },
{ "format": "{name}", "name": "Spanish", "code": "es" },
{ "format": "{name}", "name": "Swedish", "code": "sv" }
]
+1 -3
View File
@@ -1,3 +1 @@
[
{ "format": "{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}" }
]
"{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}:{hex(2)}"
+15 -15
View File
@@ -1,17 +1,17 @@
[
{ "format": "{type}", "type": ["application/gzip"], "ext": [".gz"] },
{ "format": "{type}", "type": ["application/json"], "ext": [".json"] },
{ "format": "{type}", "type": ["application/pdf"], "ext": [".pdf"] },
{ "format": "{type}", "type": ["application/xml"], "ext": [".xml"] },
{ "format": "{type}", "type": ["application/zip"], "ext": [".zip"] },
{ "format": "{type}", "type": ["audio/mpeg"], "ext": [".mp3"] },
{ "format": "{type}", "type": ["image/gif"], "ext": [".gif"] },
{ "format": "{type}", "type": ["image/jpeg"], "ext": [".jpg"] },
{ "format": "{type}", "type": ["image/png"], "ext": [".png"] },
{ "format": "{type}", "type": ["image/svg+xml"], "ext": [".svg"] },
{ "format": "{type}", "type": ["image/webp"], "ext": [".webp"] },
{ "format": "{type}", "type": ["text/csv"], "ext": [".csv"] },
{ "format": "{type}", "type": ["text/html"], "ext": [".html"] },
{ "format": "{type}", "type": ["text/plain"], "ext": [".txt"] },
{ "format": "{type}", "type": ["video/mp4"], "ext": [".mp4"] }
{ "format": "{type}", "type": "application/gzip", "ext": ".gz" },
{ "format": "{type}", "type": "application/json", "ext": ".json" },
{ "format": "{type}", "type": "application/pdf", "ext": ".pdf" },
{ "format": "{type}", "type": "application/xml", "ext": ".xml" },
{ "format": "{type}", "type": "application/zip", "ext": ".zip" },
{ "format": "{type}", "type": "audio/mpeg", "ext": ".mp3" },
{ "format": "{type}", "type": "image/gif", "ext": ".gif" },
{ "format": "{type}", "type": "image/jpeg", "ext": ".jpg" },
{ "format": "{type}", "type": "image/png", "ext": ".png" },
{ "format": "{type}", "type": "image/svg+xml", "ext": ".svg" },
{ "format": "{type}", "type": "image/webp", "ext": ".webp" },
{ "format": "{type}", "type": "text/csv", "ext": ".csv" },
{ "format": "{type}", "type": "text/html", "ext": ".html" },
{ "format": "{type}", "type": "text/plain", "ext": ".txt" },
{ "format": "{type}", "type": "video/mp4", "ext": ".mp4" }
]
+1 -3
View File
@@ -1,3 +1 @@
[
{ "format": "{hex(24)}" }
]
"{hex(24)}"
+1 -29
View File
@@ -1,29 +1 @@
[
"UTC",
"Africa/Cairo",
"Africa/Johannesburg",
"America/Chicago",
"America/Denver",
"America/Los_Angeles",
"America/Mexico_City",
"America/New_York",
"America/Sao_Paulo",
"America/Toronto",
"Asia/Dubai",
"Asia/Hong_Kong",
"Asia/Kolkata",
"Asia/Shanghai",
"Asia/Singapore",
"Asia/Tokyo",
"Australia/Sydney",
"Europe/Amsterdam",
"Europe/Berlin",
"Europe/London",
"Europe/Madrid",
"Europe/Moscow",
"Europe/Oslo",
"Europe/Paris",
"Europe/Stockholm",
"Europe/Warsaw",
"Pacific/Auckland"
]
["UTC", "Africa/Cairo", "Africa/Johannesburg", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Mexico_City", "America/New_York", "America/Sao_Paulo", "America/Toronto", "Asia/Dubai", "Asia/Hong_Kong", "Asia/Kolkata", "Asia/Shanghai", "Asia/Singapore", "Asia/Tokyo", "Australia/Sydney", "Europe/Amsterdam", "Europe/Berlin", "Europe/London", "Europe/Madrid", "Europe/Moscow", "Europe/Oslo", "Europe/Paris", "Europe/Stockholm", "Europe/Warsaw", "Pacific/Auckland"]
+1 -10
View File
@@ -1,10 +1 @@
[
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15",
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"
]
["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"]
+1 -6
View File
@@ -1,6 +1 @@
[
{
"format": "{hex(8)}-{hex(4)}-4{hex(3)}-{variant}{hex(3)}-{hex(12)}",
"variant": ["8", "9", "a", "b"]
}
]
{ "format": "{hex(8)}-{hex(4)}-4{hex(3)}-{variant}{hex(3)}-{hex(12)}", "variant": ["8", "9", "a", "b"] }
+5 -9
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{street} {street-number}\n{postal-code} {locality}",
"street": [
{
@@ -10,16 +9,13 @@
["Avenyn", "Birger Jarlsgatan", "Promenaden", "Staby", "Sveavägen", "Vintjärn"]
],
"street-number": [
{ "format": "{int(1,9)}" },
{ "format": "{int(10,99)}" },
"{int(1,9)}",
"{int(10,99)}",
{ "format": "{int(100,999)}", "weight": 0.2 },
{ "format": "{int(1,9)}{upper(1)}", "weight": 0.2 },
{ "format": "{int(10,99)}{upper(1)}", "weight": 0.1 },
{ "format": "{int(100,999)}{upper(1)}", "weight": 0.05 }
],
"postal-code": [
{ "format": "{int(100,999)} {int(10,99)}" }
],
"postal-code": "{int(100,999)} {int(10,99)}",
"locality": ["Alingsås", "Alvesta", "Ängelholm", "Arboga", "Arvika", "Avesta", "Boden", "Bollnäs", "Borås", "Borlänge", "Enköping", "Eskilstuna", "Eslöv", "Fagersta", "Falkenberg", "Falköping", "Falun", "Finspång", "Gällivare", "Gävle", "Göteborg", "Halmstad", "Haparanda", "Härnösand", "Hässleholm", "Helsingborg", "Huddinge", "Hudiksvall", "Jönköping", "Kalmar", "Karlshamn", "Karlskoga", "Karlskrona", "Karlstad", "Katrineholm", "Kiruna", "Köping", "Kramfors", "Kristianstad", "Kristinehamn", "Landskrona", "Lidingö", "Lidköping", "Lindesberg", "Linköping", "Ljungby", "Ludvika", "Luleå", "Lund", "Lycksele", "Malmö", "Mariestad", "Mjölby", "Mölndal", "Mora", "Motala", "Nacka", "Nässjö", "Norrköping", "Norrtälje", "Nyköping", "Nynäshamn", "Örebro", "Örnsköldsvik", "Oskarshamn", "Östersund", "Piteå", "Rabbalshede", "Ronneby", "Säffle", "Sandviken", "Sävsjö", "Sigtuna", "Skara", "Skellefteå", "Skövde", "Söderhamn", "Södertälje", "Sollentuna", "Solna", "Sölvesborg", "Stockholm", "Strängnäs", "Sundbyberg", "Sundsvall", "Täby", "Tierp", "Tranås", "Trelleborg", "Trollhättan", "Uddevalla", "Ulricehamn", "Umeå", "Upplands Väsby", "Uppsala", "Vänersborg", "Varberg", "Värnamo", "Västerås", "Västervik", "Växjö", "Vetlanda", "Vimmerby", "Visby", "Ystad"]
}
]
}
+3 -5
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{base} {suffix}",
"base": [
{
@@ -9,6 +8,5 @@
},
["Aktiebolaget Vega", "Bröderna Lund", "Ekonomihuset", "Hantverkargruppen", "Lindberg", "Mälardalens Bygg", "Nordström", "Skandinaviska Handelshuset", "Sundbergs Verkstad", "Svensson & Co", "Vasa Logistik"]
],
"suffix": ["AB", "AB", "AB", "AB", "HB", "KB"]
}
]
"suffix": [{ "format": "AB", "weight": 4 }, "HB", "KB"]
}
+4 -6
View File
@@ -1,15 +1,13 @@
[
{
{
"format": "{year}-{month}-{day}",
"month": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
"day": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"],
"year": [
{ "format": "197{digits(1)}" },
{ "format": "198{digits(1)}" },
"197{digits(1)}",
"198{digits(1)}",
{ "format": "199{digits(1)}", "weight": 2 },
{ "format": "200{digits(1)}", "weight": 3 },
{ "format": "201{digits(1)}", "weight": 3 },
{ "format": "202{digits(1)}", "weight": 2 }
]
}
]
}
+6 -9
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{local}@{domain}",
"local": [
{
@@ -7,23 +6,21 @@
"weight": 3,
"first": ["agnes", "alice", "anders", "anna", "anton", "asa", "axel", "bjorn", "david", "ebba", "elin", "elsa", "emil", "emma", "erik", "ester", "frida", "fredrik", "gustav", "hampus", "hanna", "henrik", "hugo", "ida", "ingrid", "isak", "johan", "jonas", "julia", "karin", "kjell", "klara", "lars", "lena", "linus", "magnus", "maja", "mats", "mattias", "mikael", "moa", "nils", "olle", "oskar", "par", "patrik", "per", "pontus", "rasmus", "samuel", "sara", "sofia", "soren", "stina", "sven", "tobias", "tuva", "viktor", "wilma", "ylva"],
"last": ["ahlberg", "andersson", "berg", "berglund", "bergstrom", "blom", "dahlberg", "eklund", "ekstrom", "engstrom", "eriksson", "falk", "forsberg", "fredriksson", "gustafsson", "hellstrom", "holm", "holmberg", "jakobsson", "johansson", "jonsson", "karlsson", "larsson", "lind", "lindberg", "lindgren", "lindqvist", "lundberg", "lundgren", "lundqvist", "magnusson", "nilsson", "norberg", "nystrom", "olsson", "persson", "petersson", "samuelsson", "sandberg", "sjoberg", "sjogren", "strand", "strom", "sundberg", "svensson", "soderberg", "wallin", "aberg", "oberg"],
"sep": [".", ".", "_", "-", ""],
"n": ["", "", "", "1", "7", "42", "88", "99"]
"sep": [{ "format": ".", "weight": 2 }, "_", "-", ""],
"n": [{ "format": "", "weight": 3 }, "1", "7", "42", "88", "99"]
},
{
"format": "{adj}{noun}{n}",
"weight": 2,
"adj": ["blixt", "busig", "cool", "frisk", "galen", "glad", "kaxig", "kvick", "listig", "lugn", "mega", "modig", "mysig", "pigg", "rolig", "smart", "snabb", "stark", "super", "trygg", "turbo", "varm", "vild"],
"noun": ["abborren", "bamsen", "bjorn", "drake", "ekorre", "falken", "grodan", "hund", "igelkott", "kaninen", "katt", "korpen", "krabban", "musen", "nallen", "ninja", "orn", "panda", "pirat", "raven", "robot", "sillen", "sparven", "uggla", "varg", "vargen"],
"n": ["", "", "7", "13", "14", "42", "77", "99", "123", "420", "2024"]
"n": [{ "format": "", "weight": 2 }, "7", "13", "14", "42", "77", "99", "123", "420", "2024"]
},
{
"format": "{w}{n}",
"weight": 1,
"w": ["blip", "blupp", "boop", "busigekorre", "coolkatten", "doot", "fizz", "floof", "galnaalgen", "gladgrodan", "glorp", "kapow", "kazoo", "kvickharen", "listigaraven", "megaraven", "mysmoln", "nattugglan", "pew", "pigghund", "pixelfox", "plonk", "rolighund", "snabbkatten", "snork", "splat", "superhunden", "turbohund", "vildvargen", "vroom", "wahoo", "waooooh", "woot", "yeet", "zap", "zoom"],
"n": ["", "", "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
"n": [{ "format": "", "weight": 2 }, "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
}
],
"domain": ["example.com", "example.org", "example.net", "example.se", "example.nu", "example.io", "mail.example.se", "webmail.example.se", "inkorg.example.se", "post.example.se", "demo.example.se", "test.example.org", "dev.example.se"]
}
]
}
+6 -4
View File
@@ -2,9 +2,11 @@
{
"format": "{o}.{o}.{o}.{o}",
"weight": 8,
"o": [{ "format": "{digits(1)}", "weight": 3 }, { "format": "{int(10,99)}", "weight": 4 }, { "format": "1{digits(2)}", "weight": 2 }]
"o": [
{ "format": "{digits(1)}", "weight": 3 },
{ "format": "{int(10,99)}", "weight": 4 },
{ "format": "1{digits(2)}", "weight": 2 }
]
},
{
"format": "{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}"
}
"{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}:{hex(4)}"
]
+4 -13
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{prefix}{femalefirst|malefirst} {last}",
"femalefirst": ["Agnes", "Alice", "Alicia", "Alma", "Amanda", "Anna", "Astrid", "Cornelia", "Ebba", "Elin", "Ella", "Ellen", "Elsa", "Emilia", "Emma", "Ester", "Eva", "Frida", "Hanna", "Hedda", "Ida", "Ingrid", "Isabelle", "Julia", "Karin", "Klara", "Kristina", "Lena", "Linnéa", "Lova", "Maja", "Maria", "Moa", "Molly", "Märta", "Nellie", "Nora", "Olivia", "Saga", "Sara", "Selma", "Signe", "Siri", "Sofia", "Stina", "Tilde", "Tuva", "Wilma", "Ylva", "Åsa"],
"malefirst": ["Adam", "Albin", "Alexander", "Alfred", "Anders", "Anton", "Arvid", "Axel", "Bengt", "Bo", "Carl", "David", "Edvin", "Elias", "Emil", "Erik", "Filip", "Folke", "Fredrik", "Gustav", "Göran", "Hampus", "Hans", "Henrik", "Hugo", "Isak", "Johan", "Jonas", "Karl", "Kjell", "Lars", "Leo", "Linus", "Love", "Magnus", "Mats", "Mattias", "Mikael", "Nils", "Olle", "Oskar", "Otto", "Patrik", "Per", "Pontus", "Rasmus", "Samuel", "Sixten", "Stefan", "Sten", "Sven", "Theodor", "Tobias", "Viktor", "William", "Åke"],
@@ -24,18 +23,10 @@
{
"format": "{first}{last}",
"weight": 0.133,
"first": ["Norr"],
"first": "Norr",
"last": ["berg", "blad", "crona", "dahl", "ed", "fors", "gren", "holm", "in", "kvist", "löf", "lund", "man", "mark", "qvist", "stedt", "sten", "strand", "ström", "vall"]
},
["Berg", "Blom", "Eismar", "Falk", "Holm", "Lind", "Norberg", "Strand", "Ström", "von Flemming", "Åberg", "Öberg"]
],
"prefix": [
"",
{
"format": "{string} ",
"string": ["dr", "prof"],
"weight": 0.05
}
]
}
]
"prefix": ["", { "format": "{string} ", "string": ["dr", "prof"], "weight": 0.05 }]
}
+6 -6
View File
@@ -3,15 +3,15 @@
"format": "{prefix}-{a} {b} {c}",
"weight": 10,
"prefix": ["070", "072", "073", "076", "079"],
"a": [{ "format": "{digits(3)}" }],
"b": [{ "format": "{digits(2)}" }],
"c": [{ "format": "{digits(2)}" }]
"a": "{digits(3)}",
"b": "{digits(2)}",
"c": "{digits(2)}"
},
{
"format": "{prefix}-{a} {b} {c}",
"prefix": ["08", "011", "013", "018", "019", "021", "023", "026", "031", "033", "035", "036", "040", "042", "044", "046", "054", "060", "063", "090"],
"a": [{ "format": "{digits(3)}" }],
"b": [{ "format": "{digits(2)}" }],
"c": [{ "format": "{digits(2)}" }]
"a": "{digits(3)}",
"b": "{digits(2)}",
"c": "{digits(2)}"
}
]
+4 -6
View File
@@ -1,13 +1,11 @@
[
{
{
"format": "{amt}{ore} kr",
"amt": [
{ "format": "{int(1,9)}", "weight": 2 },
{ "format": "{int(10,99)}", "weight": 4 },
{ "format": "{int(100,999)}", "weight": 3 },
{ "format": "{int(1,9)} {digits(3)}", "weight": 1 },
"{int(1,9)} {digits(3)}",
{ "format": "{int(10,99)} {digits(3)}", "weight": 0.3 }
],
"ore": ["", { "format": ",{c}", "c": [{ "format": "{digits(2)}" }], "weight": 0.4 }]
}
]
"ore": ["", { "format": ",{c}", "c": "{digits(2)}", "weight": 0.4 }]
}
+1 -1
View File
@@ -7,7 +7,7 @@
"noun": ["arkivet", "berget", "bäcken", "dalen", "eken", "fjället", "floden", "fyren", "fågeln", "gården", "glaciären", "hamnen", "holmen", "klippan", "kusten", "lampan", "lyktan", "motorn", "måsen", "ravinen", "räven", "seglaren", "signalen", "sjön", "skogen", "slätten", "stigen", "stjärnan", "stranden", "tornet", "trädgården", "vandraren", "vinden", "vågen", "ängen"],
"verb": ["anar", "bevakar", "bygger", "bär", "döljer", "famnar", "följer", "formar", "gömmer", "hälsar", "korsar", "leder", "lockar", "lyser", "minns", "möter", "når", "skyddar", "speglar", "söker", "tänder", "vaktar", "väcker", "värnar", "återvänder"],
"prep": ["bakom", "bland", "bortom", "framför", "genom", "intill", "kring", "längs", "mot", "nära", "ovanför", "runt", "under", "vid", "över"],
"end": [".", ".", ".", "!"]
"end": [{ "format": ".", "weight": 3 }, "!"]
},
{
"format": "{q} {adj} {noun} {verb} {prep} {noun}?",
+3 -6
View File
@@ -1,5 +1,4 @@
[
{
{
"format": "{digits(2)}{mmdd}-{digits(3)}{luhn()}",
"mmdd": [
{
@@ -16,10 +15,8 @@
},
{
"format": "{m}{d}",
"weight": 1,
"m": ["02"],
"m": "02",
"d": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"]
}
]
}
]
}
+15 -6
View File
@@ -1,8 +1,17 @@
[
{
{
"format": "{hour}:{minute}{sec}",
"hour": [{ "format": "0{digits(1)}", "weight": 4 }, { "format": "1{digits(1)}", "weight": 4 }, { "format": "2{t}", "t": ["0", "1", "2", "3"], "weight": 2 }],
"minute": [{ "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] }],
"sec": ["", { "format": ":{s}", "s": [{ "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] }], "weight": 0.4 }]
"hour": [
{ "format": "0{digits(1)}", "weight": 4 },
{ "format": "1{digits(1)}", "weight": 4 },
{ "format": "2{t}", "t": ["0", "1", "2", "3"], "weight": 2 }
],
"minute": { "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] },
"sec": [
"",
{
"format": ":{s}",
"s": { "format": "{t}{digits(1)}", "t": ["0", "1", "2", "3", "4", "5"] },
"weight": 0.4
}
]
]
}
+13 -8
View File
@@ -1,12 +1,17 @@
[
{
{
"format": "https://{host}{path}",
"host": ["example.com", "www.example.com", "example.org", "example.se", "www.example.se", "blogg.example.net", "butik.example.com", "shop.example.se", "api.example.se", "dokument.example.org", "nyheter.example.net", "mail.example.se"],
"path": [
"",
"",
{ "format": "/{seg}", "seg": ["om", "om-oss", "produkter", "blogg", "kontakt", "hjalp", "artiklar", "logga-in", "nyheter", "start", "sok", "kundvagn", "kassa", "villkor", "integritet", "priser", "tjanster", "foretag", "karriar", "support", "konto", "installningar", "registrera"] },
{ "format": "/{seg}/{sub}", "weight": 0.5, "seg": ["blogg", "produkter", "hjalp", "dokument", "kategori"], "sub": ["oversikt", "kom-igang", "guide", "2024", "senaste", "arkiv", "detaljer"] }
]
{ "format": "", "weight": 2 },
{
"format": "/{seg}",
"seg": ["om", "om-oss", "produkter", "blogg", "kontakt", "hjalp", "artiklar", "logga-in", "nyheter", "start", "sok", "kundvagn", "kassa", "villkor", "integritet", "priser", "tjanster", "foretag", "karriar", "support", "konto", "installningar", "registrera"]
},
{
"format": "/{seg}/{sub}",
"weight": 0.5,
"seg": ["blogg", "produkter", "hjalp", "dokument", "kategori"],
"sub": ["oversikt", "kom-igang", "guide", "2024", "senaste", "arkiv", "detaljer"]
}
]
]
}
+5 -6
View File
@@ -4,21 +4,20 @@
"weight": 2,
"first": ["agnes", "alice", "anders", "anna", "asa", "axel", "bjorn", "ebba", "elin", "emil", "emma", "erik", "frida", "gustav", "hanna", "hugo", "ida", "johan", "jonas", "julia", "karin", "klara", "lars", "lena", "magnus", "maja", "moa", "nils", "oskar", "per", "sara", "sofia", "viktor", "ylva"],
"last": ["ahl", "alm", "berg", "bjork", "dahl", "ek", "falk", "gran", "hag", "hed", "holm", "lind", "lund", "mark", "nor", "ohman", "ros", "sand", "sjo", "skog", "sten", "strom", "vik"],
"sep": ["", "", ".", "_"],
"n": ["", "", "", "1", "7", "23", "99", "2024"]
"sep": [{ "format": "", "weight": 2 }, ".", "_"],
"n": [{ "format": "", "weight": 3 }, "1", "7", "23", "99", "2024"]
},
{
"format": "{adj}{sep}{noun}{n}",
"weight": 2,
"adj": ["blixt", "busig", "cool", "frisk", "galen", "glad", "kaxig", "kvick", "listig", "lugn", "mega", "modig", "mysig", "pigg", "rolig", "smart", "snabb", "stark", "super", "trygg", "turbo", "varm", "vild"],
"noun": ["abborre", "bamse", "bjorn", "drake", "ekorre", "falk", "groda", "hund", "igelkott", "kanin", "katt", "korp", "krabba", "mus", "nalle", "ninja", "orn", "panda", "pirat", "rav", "robot", "sill", "sparv", "uggla", "varg"],
"sep": ["", "", ".", "_"],
"n": ["", "", "7", "13", "42", "77", "99", "123", "420", "2024"]
"sep": [{ "format": "", "weight": 2 }, ".", "_"],
"n": [{ "format": "", "weight": 2 }, "7", "13", "42", "77", "99", "123", "420", "2024"]
},
{
"format": "{w}{n}",
"weight": 1,
"w": ["blip", "blupp", "boop", "busigekorre", "coolkatten", "fizz", "floof", "galnaalgen", "gladgrodan", "glorp", "kapow", "kazoo", "kvickharen", "listigaraven", "megaraven", "mysmoln", "nattugglan", "pigghund", "pixelfox", "plonk", "rolighund", "snabbkatten", "snork", "splat", "superhunden", "turbohund", "vildvargen", "vroom", "wahoo", "waooooh", "woot", "yeet", "zap", "zoom"],
"n": ["", "", "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
"n": [{ "format": "", "weight": 2 }, "7", "14", "42", "69", "99", "123", "420", "1337", "2000", "9000"]
}
]
+3 -5
View File
@@ -1,8 +1,6 @@
[
{
{
"format": "{pre}{n}.{n}.{n}{suffix}",
"n": [{ "format": "{digits(1)}", "weight": 3 }, { "format": "{int(10,99)}" }],
"n": [{ "format": "{digits(1)}", "weight": 3 }, "{int(10,99)}"],
"pre": ["", { "format": "v", "weight": 0.4 }],
"suffix": ["", { "format": "-{tag}.{m}", "tag": ["alpha", "beta", "rc"], "m": ["1", "2", "3"], "weight": 0.3 }]
}
]
}
+4 -8
View File
@@ -109,10 +109,9 @@ func New(opts ...Option) (*Generator, error) {
}
// List returns the sorted dotted paths Fake can render: every category, the dotted
// fields within a template, and folder segments — descending transparently through
// single-variant choices the way a reference does. A choice consumes no segment, so
// a path continues through a multi-variant one only where every variant carries it,
// which is the rule Fake applies too: List is the set of paths Fake accepts.
// fields within a template, and folder segments. A choice consumes no segment, so a
// path continues through one only where every variant carries it, which is the
// rule Fake applies too: List is the set of paths Fake accepts.
func (f *Generator) List() []string {
var out []string
for _, name := range sortedNames(f.categories) {
@@ -148,9 +147,6 @@ func paths(n node) []string {
}
return out
case *choice:
if len(n.items) == 1 {
return paths(n.items[0])
}
out := []string{""}
for p := range n.shared {
out = append(out, p)
@@ -161,7 +157,7 @@ func paths(n node) []string {
}
// sharedPaths is the sub-paths every item carries — the only ones a path may step
// through a multi-variant choice to reach. It intersects, bailing as soon as the set
// through a choice to reach. It intersects, bailing as soon as the set
// is empty, which is immediate for a choice of plain strings.
func sharedPaths(items []node) map[string]bool {
shared := subPaths(items[0])
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""Rewrite data files to the one spelling each shape has.
reshape.py data/sv_SE/person.json ...
A one-item choice becomes its item; an object holding only a format becomes that
string; weight 1 and repeat 1 are dropped; a repeated choice item becomes one
item with a weight.
"""
import json
import sys
OPTIONS = ("format", "weight", "repeat", "separator")
WIDTH = 110
def reshape(n):
if isinstance(n, list):
items = [reshape(x) for x in n]
if len(items) == 1:
return items[0]
out, at = [], {}
for x in items:
key = json.dumps(x, sort_keys=True)
if key in at:
i = at[key]
if isinstance(out[i], str):
out[i] = {"format": out[i], "weight": 2}
elif isinstance(out[i], dict):
out[i]["weight"] = out[i].get("weight", 1) + 1
else:
out.append(x)
continue
at[key] = len(out)
out.append(x)
return out
if isinstance(n, dict):
d = {k: (v if k in OPTIONS else reshape(v)) for k, v in n.items()}
if d.get("weight") == 1:
del d["weight"]
if d.get("repeat") == 1:
del d["repeat"]
if list(d) == ["format"]:
return d["format"]
return d
return n
def scalar(v):
return json.dumps(v, ensure_ascii=False)
def one_line(n):
if isinstance(n, dict):
return "{ " + ", ".join(scalar(k) + ": " + one_line(v) for k, v in n.items()) + " }"
if isinstance(n, list):
return "[" + ", ".join(one_line(x) for x in n) + "]"
return scalar(n)
def dump(n, indent=0):
pad = " " * indent
if isinstance(n, dict):
line = one_line(n)
if len(pad) + len(line) <= WIDTH and not any(isinstance(v, dict) for v in n.values()):
return line
body = ",\n".join(pad + " " + scalar(k) + ": " + dump(v, indent + 1) for k, v in n.items())
return "{\n" + body + "\n" + pad + "}"
if isinstance(n, list):
if all(isinstance(x, str) for x in n):
return one_line(n)
line = one_line(n)
if len(pad) + len(line) <= WIDTH:
return line
body = ",\n".join(pad + " " + dump(x, indent + 1) for x in n)
return "[\n" + body + "\n" + pad + "]"
return scalar(n)
if __name__ == "__main__":
for path in sys.argv[1:]:
with open(path) as fh:
before = json.load(fh)
after = dump(reshape(before)) + "\n"
with open(path, "w") as fh:
fh.write(after)
print("reshaped", path)
+38 -6
View File
@@ -1,6 +1,7 @@
package fejkdata
import (
"encoding/json"
"fmt"
"math"
"sort"
@@ -107,6 +108,12 @@ func compileChoice(items []any) (node, error) {
if len(items) == 0 {
return nil, fmt.Errorf("empty choice")
}
if len(items) == 1 {
return nil, fmt.Errorf("a one-item choice is its item; write the item")
}
if err := checkNoRepeatedItem(items); err != nil {
return nil, err
}
c := &choice{items: make([]node, len(items))}
cum := make([]float64, len(items))
var total float64
@@ -133,14 +140,33 @@ func compileChoice(items []any) (node, error) {
}
c.cum = cum
}
if len(c.items) > 1 {
// Safe to precompute: a choice's items come from one file, so no group can
// appear inside one, and neither mergeChildren nor linkRefs can reach in.
c.shared = sharedPaths(c.items)
}
return c, nil
}
// checkNoRepeatedItem rejects a choice that lists one item twice: a pick is even
// over the items, so a repeat is a second spelling of weight. The error names the
// spelling that does skew a pick.
func checkNoRepeatedItem(items []any) error {
seen := make(map[string]int, len(items))
for i, raw := range items {
key, err := json.Marshal(raw)
if err != nil {
return err
}
if j, dup := seen[string(key)]; dup {
if s, isString := raw.(string); isString {
return fmt.Errorf("choice item %q is repeated; skew the odds with a weight instead: { \"format\": %q, \"weight\": 2 }", s, s)
}
return fmt.Errorf("choice item %d repeats item %d; skew the odds with a weight on one of them instead", i, j)
}
seen[string(key)] = i
}
return nil
}
func compileTemplate(m map[string]any) (node, error) {
format, ok := m["format"].(string)
if !ok {
@@ -181,6 +207,9 @@ func compileTemplate(m map[string]any) (node, error) {
}
t.fields[k] = n
}
if _, weighted := m["weight"]; len(t.fields) == 0 && repeat == 1 && !weighted {
return nil, fmt.Errorf("an object holding only a format is a string; write %q", format)
}
if err := checkTokens(format, t.fields); err != nil {
return nil, err
}
@@ -212,7 +241,6 @@ func checkPath(n node, tail []string, level string) error {
}
return checkPath(child, tail[1:], level+"."+tail[0])
case *choice:
if len(n.items) > 1 {
if want := strings.Join(tail, "."); !n.shared[want] {
return unreachableInChoice(n, want)
}
@@ -224,15 +252,13 @@ func checkPath(n node, tail []string, level string) error {
}
}
return nil
}
return checkPath(n.items[0], tail, level)
default:
return fmt.Errorf("cannot descend into %T at %q", n, tail[0])
}
}
// repeatOf reads a template's "repeat" (default 1): how many times its format
// is rendered and concatenated. A present one must be a positive integer.
// is rendered and concatenated. A present one must be an integer above 1.
func repeatOf(m map[string]any) (int, error) {
rv, ok := m["repeat"]
if !ok {
@@ -245,6 +271,9 @@ func repeatOf(m map[string]any) (int, error) {
if math.IsNaN(r) || math.IsInf(r, 0) || r < 1 || r != math.Trunc(r) {
return 0, fmt.Errorf("repeat must be a positive integer, got %v", rv)
}
if r == 1 {
return 0, fmt.Errorf("repeat 1 is the default, so it has no effect; drop it")
}
if r > maxLen { // cap so a fat-fingered repeat can't build a multi-GB string
return 0, fmt.Errorf("repeat %v exceeds the maximum %d", rv, maxLen)
}
@@ -269,6 +298,9 @@ func weightOf(raw any) (float64, error) {
if w < 0 || math.IsNaN(w) || math.IsInf(w, 0) {
return 0, fmt.Errorf("weight must be finite and non-negative, got %v", w)
}
if w == 1 {
return 0, fmt.Errorf("weight 1 is the default, so it has no effect; drop it")
}
return w, nil
}
+6 -8
View File
@@ -9,8 +9,7 @@ import (
// refPrefix marks a {..path} token: a reference to a node elsewhere in the data
// root rather than a sibling field. The path is resolved across every loaded
// directory (see linkRefs), and is stricter than the one Fake takes: a reference
// binds one node, so it cannot step through a multi-variant choice even where Fake
// and List can.
// binds one node, so it cannot step through a choice even where Fake and List can.
const refPrefix = ".."
func isRef(name string) bool { return strings.HasPrefix(name, refPrefix) }
@@ -32,6 +31,9 @@ func linkRefs(root map[string]node) error {
if err != nil {
return fmt.Errorf("%s: reference {%s}: %w", path, name, err)
}
if t.fields == nil {
t.fields = map[string]node{}
}
t.fields[name] = target
}
return nil
@@ -231,9 +233,8 @@ func sortedNames(m map[string]node) []string {
}
// lookup finds the single node a reference path names, walking groups and
// template fields by segment and descending a single-variant choice as a
// transparent wrapper. A missing segment, a folder target, or a step through a
// multi-variant choice (which has no one value to bind) is an error.
// template fields by segment. A missing segment, a folder target, or a step
// through a choice (which has no one value to bind) is an error.
func lookup(root map[string]node, segments []string) (node, error) {
var n node = &group{children: root}
for i := 0; i < len(segments); i++ {
@@ -251,10 +252,7 @@ func lookup(root map[string]node, segments []string) (node, error) {
}
n = child
case *choice:
if len(c.items) != 1 {
return nil, fmt.Errorf("%q steps through a %d-way choice", segments[i], len(c.items))
}
n, i = c.items[0], i-1 // a choice consumes no segment; reprocess it unwrapped
default:
return nil, fmt.Errorf("cannot descend into %T at %q", n, segments[i])
}
-2
View File
@@ -53,11 +53,9 @@ func descend(s *session, n node, segments []string) (node, error) {
}
return descend(s, child, segments[1:])
case *choice:
if len(n.items) > 1 {
if want := strings.Join(segments, "."); !n.shared[want] {
return nil, unreachableInChoice(n, want)
}
}
return descend(s, pick(s, n), segments)
default:
return nil, fmt.Errorf("cannot descend into %T at %q", n, segments[0])