synthra 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +40 -0
  4. data/.yardopts +18 -0
  5. data/ACCESS_DOCS.md +116 -0
  6. data/ADVANCED_FEATURES_SUMMARY.md +245 -0
  7. data/CHANGELOG.md +498 -0
  8. data/CODE_OF_CONDUCT.md +122 -0
  9. data/CONTRIBUTING.md +307 -0
  10. data/DOCUMENTATION.md +204 -0
  11. data/DOCUMENTATION_GUIDE.md +194 -0
  12. data/LICENSE +22 -0
  13. data/README.md +1458 -0
  14. data/Rakefile +128 -0
  15. data/benchmark/README.md +591 -0
  16. data/benchmark/batch_generation.rb +63 -0
  17. data/benchmark/engine_comparison.rb +295 -0
  18. data/benchmark/single_record.rb +108 -0
  19. data/benchmark/streaming.rb +74 -0
  20. data/docs/ACTIVERECORD_INFERENCE.md +524 -0
  21. data/docs/API_SERVER.md +278 -0
  22. data/docs/CONFIG_FILE.md +315 -0
  23. data/docs/DATA_CONTRACTS.md +312 -0
  24. data/docs/ENHANCED_REPL.md +304 -0
  25. data/docs/FACTORY_BOT.md +271 -0
  26. data/docs/GITHUB_ACTION.md +420 -0
  27. data/docs/GRAPHQL_EXPORT.md +303 -0
  28. data/docs/GRAPHQL_FEDERATION.md +651 -0
  29. data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
  30. data/docs/LSP.md +189 -0
  31. data/docs/MIGRATION_GENERATOR.md +547 -0
  32. data/docs/MOCK_SERVER.md +280 -0
  33. data/docs/NATIVE_ENGINE.md +298 -0
  34. data/docs/OPENAPI_EXPORT.md +252 -0
  35. data/docs/PERFORMANCE_MODE.md +228 -0
  36. data/docs/PERSONAS.md +547 -0
  37. data/docs/PROPERTY_TESTING.md +284 -0
  38. data/docs/PROTOBUF_EXPORT.md +276 -0
  39. data/docs/QUALITY_METRICS.md +555 -0
  40. data/docs/QUICK_REFERENCE.md +88 -0
  41. data/docs/RAILS_ENGINE.md +404 -0
  42. data/docs/RAILS_INTEGRATION.md +454 -0
  43. data/docs/README.md +175 -0
  44. data/docs/REPL_QUICK_REFERENCE.md +149 -0
  45. data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
  46. data/docs/SCENARIOS.md +576 -0
  47. data/docs/SECURITY_TESTING.md +318 -0
  48. data/docs/SNAPSHOT_TESTING.md +308 -0
  49. data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
  50. data/docs/TERRAFORM_EXPORT.md +447 -0
  51. data/docs/TIME_TRAVEL.md +507 -0
  52. data/docs/USAGE_GUIDE.md +980 -0
  53. data/docs/WEBHOOK_SIMULATOR.md +579 -0
  54. data/docs/advanced_features.md +183 -0
  55. data/docs/api_reference.md +153 -0
  56. data/docs/behaviors.md +138 -0
  57. data/docs/best_practices.md +191 -0
  58. data/docs/dsl_reference.md +172 -0
  59. data/docs/examples.md +162 -0
  60. data/docs/generation_modes.md +125 -0
  61. data/docs/getting_started.md +92 -0
  62. data/docs/index.html +177 -0
  63. data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
  64. data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
  65. data/docs/troubleshooting.md +215 -0
  66. data/docs/type_reference.md +224 -0
  67. data/examples/hostile_mode_demo.rb +64 -0
  68. data/exe/synthra +6 -0
  69. data/ext/synthra_native/Cargo.lock +972 -0
  70. data/ext/synthra_native/Cargo.toml +46 -0
  71. data/ext/synthra_native/extconf.rb +41 -0
  72. data/ext/synthra_native/src/generator.rs +397 -0
  73. data/ext/synthra_native/src/lib.rs +229 -0
  74. data/ext/synthra_native/src/types.rs +1485 -0
  75. data/lib/generators/synthra/install_generator.rb +86 -0
  76. data/lib/generators/synthra/templates/api_response.dsl +15 -0
  77. data/lib/generators/synthra/templates/fake_data.rake +116 -0
  78. data/lib/generators/synthra/templates/synthra.yml +31 -0
  79. data/lib/generators/synthra/templates/synthra_support.rb +19 -0
  80. data/lib/generators/synthra/templates/user.dsl +11 -0
  81. data/lib/synthra/activerecord_inference.rb +394 -0
  82. data/lib/synthra/api.rb +381 -0
  83. data/lib/synthra/api_server.rb +718 -0
  84. data/lib/synthra/behaviors/applicator.rb +165 -0
  85. data/lib/synthra/behaviors/base.rb +155 -0
  86. data/lib/synthra/behaviors/close_connection.rb +60 -0
  87. data/lib/synthra/behaviors/deprecated.rb +100 -0
  88. data/lib/synthra/behaviors/failure.rb +69 -0
  89. data/lib/synthra/behaviors/latency.rb +103 -0
  90. data/lib/synthra/behaviors/partial_data.rb +83 -0
  91. data/lib/synthra/behaviors/randomize_order.rb +74 -0
  92. data/lib/synthra/behaviors/registry.rb +238 -0
  93. data/lib/synthra/behaviors/simulate_error.rb +79 -0
  94. data/lib/synthra/cli/commands/base.rb +105 -0
  95. data/lib/synthra/cli/commands/diff.rb +227 -0
  96. data/lib/synthra/cli/commands/docs.rb +67 -0
  97. data/lib/synthra/cli/commands/export.rb +150 -0
  98. data/lib/synthra/cli/commands/generate.rb +72 -0
  99. data/lib/synthra/cli/commands/import.rb +80 -0
  100. data/lib/synthra/cli/commands/lint.rb +53 -0
  101. data/lib/synthra/cli/commands/live.rb +57 -0
  102. data/lib/synthra/cli/commands/seed.rb +99 -0
  103. data/lib/synthra/cli/commands/validate.rb +28 -0
  104. data/lib/synthra/cli.rb +2471 -0
  105. data/lib/synthra/config_file.rb +129 -0
  106. data/lib/synthra/configuration.rb +281 -0
  107. data/lib/synthra/contracts_registry.rb +408 -0
  108. data/lib/synthra/database_seeder.rb +268 -0
  109. data/lib/synthra/deterministic_ids.rb +218 -0
  110. data/lib/synthra/documentation_generator.rb +414 -0
  111. data/lib/synthra/engine.rb +251 -0
  112. data/lib/synthra/errors.rb +1169 -0
  113. data/lib/synthra/export/base.rb +85 -0
  114. data/lib/synthra/export/csv.rb +101 -0
  115. data/lib/synthra/export/graphql.rb +266 -0
  116. data/lib/synthra/export/graphql_federation.rb +377 -0
  117. data/lib/synthra/export/graphviz.rb +258 -0
  118. data/lib/synthra/export/javascript.rb +327 -0
  119. data/lib/synthra/export/json_data.rb +61 -0
  120. data/lib/synthra/export/json_schema.rb +290 -0
  121. data/lib/synthra/export/openapi.rb +514 -0
  122. data/lib/synthra/export/protobuf.rb +483 -0
  123. data/lib/synthra/export/python.rb +560 -0
  124. data/lib/synthra/export/sql.rb +381 -0
  125. data/lib/synthra/export/sql_insert.rb +152 -0
  126. data/lib/synthra/export/terraform.rb +501 -0
  127. data/lib/synthra/export/type_mapping.rb +389 -0
  128. data/lib/synthra/export/typescript.rb +300 -0
  129. data/lib/synthra/export/xml_data.rb +104 -0
  130. data/lib/synthra/export/yaml_data.rb +56 -0
  131. data/lib/synthra/export.rb +404 -0
  132. data/lib/synthra/factory_bot_integration.rb +157 -0
  133. data/lib/synthra/field.rb +440 -0
  134. data/lib/synthra/functions/registry.rb +104 -0
  135. data/lib/synthra/generator/context.rb +372 -0
  136. data/lib/synthra/generator/engine.rb +336 -0
  137. data/lib/synthra/generator/faker_adapter.rb +425 -0
  138. data/lib/synthra/generator/modes.rb +444 -0
  139. data/lib/synthra/generator/resolver.rb +256 -0
  140. data/lib/synthra/generator/rng.rb +273 -0
  141. data/lib/synthra/generator/streamer.rb +63 -0
  142. data/lib/synthra/generator/uniqueness.rb +118 -0
  143. data/lib/synthra/initializer.rb +97 -0
  144. data/lib/synthra/limits.rb +279 -0
  145. data/lib/synthra/live_preview.rb +518 -0
  146. data/lib/synthra/loader_config.rb +78 -0
  147. data/lib/synthra/lsp/server.rb +689 -0
  148. data/lib/synthra/migration_generator.rb +301 -0
  149. data/lib/synthra/mixin.rb +174 -0
  150. data/lib/synthra/mock_server.rb +458 -0
  151. data/lib/synthra/native_engine.rb +304 -0
  152. data/lib/synthra/openapi_importer.rb +228 -0
  153. data/lib/synthra/output/json_formatter.rb +40 -0
  154. data/lib/synthra/output/ndjson_formatter.rb +55 -0
  155. data/lib/synthra/parser/ast.rb +1287 -0
  156. data/lib/synthra/parser/lexer.rb +1152 -0
  157. data/lib/synthra/parser/parser.rb +1664 -0
  158. data/lib/synthra/parser/tokens.rb +461 -0
  159. data/lib/synthra/performance_mode.rb +364 -0
  160. data/lib/synthra/personas.rb +397 -0
  161. data/lib/synthra/property_testing.rb +172 -0
  162. data/lib/synthra/quality_metrics.rb +405 -0
  163. data/lib/synthra/rails_test_helper.rb +248 -0
  164. data/lib/synthra/registry.rb +533 -0
  165. data/lib/synthra/relationships.rb +193 -0
  166. data/lib/synthra/repl/enhanced_repl.rb +607 -0
  167. data/lib/synthra/repl/formatter.rb +191 -0
  168. data/lib/synthra/scenarios.rb +423 -0
  169. data/lib/synthra/schema.rb +605 -0
  170. data/lib/synthra/schema_inheritance.rb +104 -0
  171. data/lib/synthra/schema_versioning.rb +212 -0
  172. data/lib/synthra/snapshot_testing.rb +199 -0
  173. data/lib/synthra/time_travel.rb +338 -0
  174. data/lib/synthra/type_definitions.rb +274 -0
  175. data/lib/synthra/types/address_location/addresses.rb +125 -0
  176. data/lib/synthra/types/address_location/airports.rb +200 -0
  177. data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
  178. data/lib/synthra/types/address_location/locations.rb +406 -0
  179. data/lib/synthra/types/base.rb +48 -0
  180. data/lib/synthra/types/commerce_products/commerce.rb +119 -0
  181. data/lib/synthra/types/commerce_products/companies.rb +71 -0
  182. data/lib/synthra/types/commerce_products/construction.rb +126 -0
  183. data/lib/synthra/types/commerce_products/products.rb +205 -0
  184. data/lib/synthra/types/core/collections.rb +513 -0
  185. data/lib/synthra/types/core/defaults.rb +76 -0
  186. data/lib/synthra/types/core/enums.rb +102 -0
  187. data/lib/synthra/types/core/identifiers.rb +445 -0
  188. data/lib/synthra/types/core/primitives.rb +586 -0
  189. data/lib/synthra/types/core/references.rb +466 -0
  190. data/lib/synthra/types/core/sequences.rb +304 -0
  191. data/lib/synthra/types/crypto/crypto.rb +162 -0
  192. data/lib/synthra/types/date_time/dates.rb +387 -0
  193. data/lib/synthra/types/finance_banking/banking.rb +424 -0
  194. data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
  195. data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
  196. data/lib/synthra/types/formula.rb +184 -0
  197. data/lib/synthra/types/health_medical/medical.rb +150 -0
  198. data/lib/synthra/types/hostile_payloads.rb +122 -0
  199. data/lib/synthra/types/json_array.rb +51 -0
  200. data/lib/synthra/types/media_entertainment/media.rb +62 -0
  201. data/lib/synthra/types/naughty_string.rb +30 -0
  202. data/lib/synthra/types/personal_names/chinese.rb +41 -0
  203. data/lib/synthra/types/personal_names/identifiers.rb +187 -0
  204. data/lib/synthra/types/personal_names/names.rb +246 -0
  205. data/lib/synthra/types/personal_names/national_id.rb +89 -0
  206. data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
  207. data/lib/synthra/types/regex.rb +248 -0
  208. data/lib/synthra/types/registry.rb +182 -0
  209. data/lib/synthra/types/repeating_element.rb +50 -0
  210. data/lib/synthra/types/scenario.rb +29 -0
  211. data/lib/synthra/types/technology_internet/apps.rb +67 -0
  212. data/lib/synthra/types/technology_internet/communication.rb +162 -0
  213. data/lib/synthra/types/technology_internet/devices.rb +80 -0
  214. data/lib/synthra/types/technology_internet/formats.rb +139 -0
  215. data/lib/synthra/types/technology_internet/networking.rb +143 -0
  216. data/lib/synthra/types/template.rb +92 -0
  217. data/lib/synthra/types/text_content/business.rb +128 -0
  218. data/lib/synthra/types/text_content/colors.rb +70 -0
  219. data/lib/synthra/types/text_content/misc.rb +237 -0
  220. data/lib/synthra/types/text_content/security.rb +130 -0
  221. data/lib/synthra/types/text_content/text_generation.rb +532 -0
  222. data/lib/synthra/types/travel/travel.rb +150 -0
  223. data/lib/synthra/utils/string_distance.rb +133 -0
  224. data/lib/synthra/validator/dsl_validator.rb +339 -0
  225. data/lib/synthra/validator/path_validator.rb +615 -0
  226. data/lib/synthra/version.rb +35 -0
  227. data/lib/synthra/webhook_simulator.rb +341 -0
  228. data/lib/synthra.rb +259 -0
  229. data/schemas/address.dsl +16 -0
  230. data/schemas/api_response.dsl +8 -0
  231. data/schemas/error_payload.dsl +9 -0
  232. data/schemas/order.dsl +10 -0
  233. data/schemas/order_item.dsl +8 -0
  234. data/schemas/payment.dsl +11 -0
  235. data/schemas/social_post.dsl +13 -0
  236. data/schemas/user.dsl +10 -0
  237. data/scripts/batch_fix_all.rb +96 -0
  238. data/scripts/delete_old_files.rb +32 -0
  239. data/scripts/fix_all_grouped_files.rb +137 -0
  240. data/scripts/fix_all_indentation.rb +48 -0
  241. data/scripts/fix_all_syntax.rb +124 -0
  242. data/scripts/fix_grouped_files.rb +184 -0
  243. data/scripts/fix_syntax_errors.rb +108 -0
  244. data/scripts/group_domain_types.rb +112 -0
  245. data/scripts/group_domain_types_fixed.rb +150 -0
  246. data/scripts/merge_domains_to_one_file.rb +68 -0
  247. data/scripts/move_existing_types.rb +130 -0
  248. data/scripts/split_grouped_types.rb +142 -0
  249. data/tech_docs/README.md +134 -0
  250. data/tech_docs/advanced/streaming.md +405 -0
  251. data/tech_docs/advanced/thread_safety.md +253 -0
  252. data/tech_docs/api/overview.md +485 -0
  253. data/tech_docs/appendices/type_chart.md +193 -0
  254. data/tech_docs/basic_concepts.md +383 -0
  255. data/tech_docs/behaviors/overview.md +346 -0
  256. data/tech_docs/dsl/complex_types.md +790 -0
  257. data/tech_docs/dsl/core_types.md +464 -0
  258. data/tech_docs/dsl/datetime_types.md +325 -0
  259. data/tech_docs/dsl/field_modifiers.md +414 -0
  260. data/tech_docs/dsl/grammar.md +431 -0
  261. data/tech_docs/dsl/schema_definition.md +399 -0
  262. data/tech_docs/export/README.md +276 -0
  263. data/tech_docs/installation.md +273 -0
  264. data/tech_docs/integration/ci_cd.md +707 -0
  265. data/tech_docs/integration/ci_cd_guide.md +579 -0
  266. data/tech_docs/integration/factory_bot.md +485 -0
  267. data/tech_docs/integration/rails.md +630 -0
  268. data/tech_docs/integration/rspec.md +449 -0
  269. data/tech_docs/modes/overview.md +350 -0
  270. data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
  271. data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
  272. data/tech_docs/quick_start.md +256 -0
  273. data/tech_docs/templates/README.md +805 -0
  274. data/tech_docs/tutorials/advanced.md +371 -0
  275. data/tech_docs/tutorials/getting_started.md +189 -0
  276. data/tech_docs/tutorials/intermediate.md +231 -0
  277. data/tech_docs/tutorials/template_gallery.md +569 -0
  278. data/tech_example/01_basic_usage.rb +238 -0
  279. data/tech_example/02_types_demo.rb +336 -0
  280. data/tech_example/04_cli_usage.md +429 -0
  281. data/tech_example/05_database_seeding.rb +283 -0
  282. data/tech_example/07_rspec_integration.rb +359 -0
  283. data/tech_example/10_custom_types.rb +387 -0
  284. data/tech_example/12_behaviors.rb +372 -0
  285. data/tech_example/13_twitter_dm_example.rb +120 -0
  286. data/tech_example/14_exact_json_structure.rb +253 -0
  287. data/tech_example/16_lsp_server.rb +56 -0
  288. data/tech_example/17_property_testing.rb +92 -0
  289. data/tech_example/18_enhanced_repl.rb +120 -0
  290. data/tech_example/19_security_fuzzing.rb +145 -0
  291. data/tech_example/NEW_FEATURES.md +169 -0
  292. data/tech_example/README.md +118 -0
  293. data/tech_example/schemas/api_response.dsl +123 -0
  294. data/tech_example/schemas/ecommerce.dsl +121 -0
  295. data/tech_example/schemas/twitter_dm.dsl +109 -0
  296. data/tech_example/schemas/user.dsl +36 -0
  297. data/vscode-extension/README.md +246 -0
  298. data/vscode-extension/language-configuration.json +31 -0
  299. data/vscode-extension/package.json +55 -0
  300. data/vscode-extension/snippets/fakedatadsl.json +198 -0
  301. data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
  302. metadata +478 -0
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TextContent
6
+ # Buzzword type
7
+ class Buzzword < Base
8
+ BUZZWORDS = [
9
+ "Synergy", "Paradigm", "Leverage", "Disrupt", "Innovation",
10
+ "Scalable", "Agile", "Cloud", "Big Data", "AI", "Blockchain"
11
+ ].freeze
12
+
13
+ def generate_random(rng, context, args)
14
+ adapter = faker_adapter(context)
15
+ if adapter
16
+ adapter.buzzword
17
+
18
+ else
19
+ Faker::Company.buzzword
20
+ end
21
+
22
+ rescue StandardError
23
+ rng.sample(BUZZWORDS)
24
+ end
25
+
26
+
27
+ def generate_edge(rng, context, args)
28
+ ["", "Synergy"].sample(random: rng.instance_variable_get(:@random))
29
+ end
30
+
31
+ def generate_invalid(rng, context, args)
32
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
33
+ end
34
+ end
35
+
36
+ # CatchPhrase type
37
+ class CatchPhrase < Base
38
+ PHRASES = [
39
+ "Think Different", "Just Do It", "I'm Lovin' It",
40
+ "Because You're Worth It", "The Best a Man Can Get"
41
+ ].freeze
42
+
43
+ def generate_random(rng, context, args)
44
+ adapter = faker_adapter(context)
45
+ if adapter
46
+ adapter.catch_phrase
47
+
48
+ else
49
+ Faker::Company.catch_phrase
50
+ end
51
+
52
+ rescue StandardError
53
+ rng.sample(PHRASES)
54
+ end
55
+
56
+
57
+ def generate_edge(rng, context, args)
58
+ ["", "Just Do It"].sample(random: rng.instance_variable_get(:@random))
59
+ end
60
+
61
+ def generate_invalid(rng, context, args)
62
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
63
+ end
64
+ end
65
+
66
+ # Slogan type
67
+ class Slogan < Base
68
+ SLOGANS = [
69
+ "Just Do It", "Think Different", "I'm Lovin' It",
70
+ "Because You're Worth It", "The Best a Man Can Get",
71
+ "Have It Your Way", "Finger Lickin' Good"
72
+ ].freeze
73
+
74
+ def generate_random(rng, context, args)
75
+ adapter = faker_adapter(context)
76
+ if adapter && adapter.respond_to?(:slogan)
77
+ begin
78
+ adapter.slogan
79
+ rescue StandardError
80
+ rng.sample(SLOGANS)
81
+ end
82
+ else
83
+ # Faker doesn't have a direct slogan method, use catch_phrase
84
+ begin
85
+ Faker::Company.catch_phrase
86
+ rescue StandardError
87
+ # Fallback to English-only hardcoded list
88
+ rng.sample(SLOGANS) # fallback
89
+ end
90
+ end
91
+ end
92
+
93
+ def generate_edge(rng, context, args)
94
+ ["", "Just Do It"].sample(random: rng.instance_variable_get(:@random))
95
+ end
96
+
97
+ def generate_invalid(rng, context, args)
98
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
99
+ end
100
+ end
101
+
102
+ # FakeCompanyName type
103
+ class FakeCompanyName < Base
104
+ def generate_random(rng, context, args)
105
+ adapter = faker_adapter(context)
106
+ if adapter && adapter.respond_to?(:company_name)
107
+ adapter.company_name
108
+
109
+ else
110
+ Faker::Company.name
111
+ end
112
+
113
+ rescue StandardError
114
+ rng.sample(["Acme Corp", "Tech Solutions Inc", "Global Industries"])
115
+ end
116
+
117
+
118
+ def generate_edge(rng, context, args)
119
+ ["", "A", "Very Long Company Name"].sample(random: rng.instance_variable_get(:@random))
120
+ end
121
+
122
+ def generate_invalid(rng, context, args)
123
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TextContent
6
+ # Color type
7
+ class Color < Base
8
+ COLORS = [
9
+ "Red", "Blue", "Green", "Yellow", "Orange", "Purple",
10
+ "Pink", "Brown", "Black", "White", "Gray", "Cyan", "Magenta"
11
+ ].freeze
12
+
13
+ def generate_random(rng, context, args)
14
+ adapter = faker_adapter(context)
15
+ if adapter
16
+ adapter.color
17
+
18
+ else
19
+ Faker::Commerce.color
20
+ end
21
+
22
+ rescue StandardError
23
+ rng.sample(COLORS)
24
+ end
25
+
26
+
27
+ def generate_edge(rng, context, args)
28
+ ["", "Red", "Black"].sample(random: rng.instance_variable_get(:@random))
29
+ end
30
+
31
+ def generate_invalid(rng, context, args)
32
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
33
+ end
34
+ end
35
+
36
+ # HexColor type
37
+ class HexColor < Base
38
+ def generate_random(rng, context, args)
39
+ # Generate 6-digit hex color
40
+ chars = ('0'..'9').to_a + ('A'..'F').to_a
41
+ "##{6.times.map { rng.sample(chars) }.join}"
42
+ end
43
+
44
+ def generate_edge(rng, context, args)
45
+ ["#000000", "#FFFFFF", "#FF0000"].sample(random: rng.instance_variable_get(:@random))
46
+ end
47
+
48
+ def generate_invalid(rng, context, args)
49
+ [nil, "not a color", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
50
+ end
51
+ end
52
+
53
+ # ShortHexColor type
54
+ class ShortHexColor < Base
55
+ def generate_random(rng, context, args)
56
+ chars = ('0'..'9').to_a + ('A'..'F').to_a
57
+ "##{3.times.map { rng.sample(chars) }.join}"
58
+ end
59
+
60
+ def generate_edge(rng, context, args)
61
+ ["#000", "#FFF", "#F00"].sample(random: rng.instance_variable_get(:@random))
62
+ end
63
+
64
+ def generate_invalid(rng, context, args)
65
+ [nil, "not a color", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TextContent
6
+ # Avatar type
7
+ class Avatar < Base
8
+ def generate_random(rng, context, args)
9
+ height = args[:height] || 200
10
+ width = args[:width] || 200
11
+ "https://i.pravatar.cc/#{width}?img=#{rng.int(1, 70)}"
12
+ end
13
+
14
+ def generate_edge(rng, context, args)
15
+ ["", "https://i.pravatar.cc/1?img=1"].sample(random: rng.instance_variable_get(:@random))
16
+ end
17
+
18
+ def generate_invalid(rng, context, args)
19
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
20
+ end
21
+ end
22
+
23
+ # FileName type
24
+ class FileName < Base
25
+ EXTENSIONS = ["txt", "pdf", "doc", "xls", "jpg", "png", "gif", "mp4", "zip", "csv"].freeze
26
+
27
+ def generate_random(rng, context, args)
28
+ name = rng.sample([
29
+ "document", "file", "report", "data", "image", "video",
30
+ "archive", "spreadsheet", "presentation", "backup"
31
+ ])
32
+ number = rng.int(1, 999)
33
+ ext = rng.sample(EXTENSIONS)
34
+ "#{name}_#{number}.#{ext}"
35
+ end
36
+
37
+ def generate_edge(rng, context, args)
38
+ ["", "file.1", "very_long_file_name_that_exceeds_normal_limits.txt"].sample(random: rng.instance_variable_get(:@random))
39
+ end
40
+
41
+ def generate_invalid(rng, context, args)
42
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
43
+ end
44
+ end
45
+
46
+ # Frequency type
47
+ class Frequency < Base
48
+ FREQUENCIES = ["Daily", "Weekly", "Monthly", "Quarterly", "Yearly", "Once", "Never"].freeze
49
+
50
+ def generate_random(rng, context, args)
51
+ rng.sample(FREQUENCIES)
52
+ end
53
+
54
+ def generate_edge(rng, context, args)
55
+ ["", "Daily", "Never"].sample(random: rng.instance_variable_get(:@random))
56
+ end
57
+
58
+ def generate_invalid(rng, context, args)
59
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
60
+ end
61
+ end
62
+
63
+ # LinkedInSkill type
64
+ class LinkedInSkill < Base
65
+ SKILLS = [
66
+ "JavaScript", "Python", "Java", "Ruby", "Go", "Rust",
67
+ "React", "Vue", "Angular", "Node.js", "SQL", "MongoDB",
68
+ "AWS", "Docker", "Kubernetes", "Git", "Agile", "Scrum"
69
+ ].freeze
70
+
71
+ def generate_random(rng, context, args)
72
+ rng.sample(SKILLS)
73
+ end
74
+
75
+ def generate_edge(rng, context, args)
76
+ ["", "JavaScript", "Python"].sample(random: rng.instance_variable_get(:@random))
77
+ end
78
+
79
+ def generate_invalid(rng, context, args)
80
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
81
+ end
82
+ end
83
+
84
+ # NatoPhonetic type
85
+ class NatoPhonetic < Base
86
+ NATO_ALPHABET = [
87
+ "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot",
88
+ "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima",
89
+ "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo",
90
+ "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu"
91
+ ].freeze
92
+
93
+ def generate_random(rng, context, args)
94
+ min = args[:min] || 1
95
+ max = args[:max] || 5
96
+ count = rng.int(min, max)
97
+ count.times.map { rng.sample(NATO_ALPHABET) }.join(" ")
98
+ end
99
+
100
+ def generate_edge(rng, context, args)
101
+ ["", "Alpha", "Zulu"].sample(random: rng.instance_variable_get(:@random))
102
+ end
103
+
104
+ def generate_invalid(rng, context, args)
105
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
106
+ end
107
+ end
108
+
109
+ # RowNumber type
110
+ class RowNumber < Base
111
+ def generate_random(rng, context, args)
112
+ rng.int(1, 10000)
113
+ end
114
+
115
+ def generate_edge(rng, context, args)
116
+ [1, 10000, 0].sample(random: rng.instance_variable_get(:@random))
117
+ end
118
+
119
+ def generate_invalid(rng, context, args)
120
+ [nil, "not a number", -1, [], {}].sample(random: rng.instance_variable_get(:@random))
121
+ end
122
+ end
123
+
124
+ # SqlExpression type
125
+ class SqlExpression < Base
126
+ def generate_random(rng, context, args)
127
+ value = args[:value] || "SELECT * FROM users"
128
+ # Return as-is, but note this is intentionally not executed
129
+ value
130
+ end
131
+
132
+ def generate_edge(rng, context, args)
133
+ ["", "SELECT 1", "DROP TABLE users"].sample(random: rng.instance_variable_get(:@random))
134
+ end
135
+
136
+ def generate_invalid(rng, context, args)
137
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
138
+ end
139
+ end
140
+
141
+ # University type
142
+ class University < Base
143
+ UNIVERSITIES = [
144
+ "Harvard University", "Stanford University", "MIT", "Oxford University",
145
+ "Cambridge University", "Yale University", "Princeton University", "Columbia University"
146
+ ].freeze
147
+
148
+ def generate_random(rng, context, args)
149
+ rng.sample(UNIVERSITIES)
150
+ end
151
+
152
+ def generate_edge(rng, context, args)
153
+ ["", "MIT", "Harvard University"].sample(random: rng.instance_variable_get(:@random))
154
+ end
155
+
156
+ def generate_invalid(rng, context, args)
157
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
158
+ end
159
+ end
160
+
161
+ # Blank type
162
+ class Blank < Base
163
+ def generate_random(rng, context, args)
164
+ ""
165
+ end
166
+
167
+ def generate_edge(rng, context, args)
168
+ [""]
169
+ end
170
+
171
+ def generate_invalid(rng, context, args)
172
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
173
+ end
174
+ end
175
+
176
+ # Race type
177
+ class Race < Base
178
+ RACES = [
179
+ "White", "Black or African American", "Asian", "American Indian or Alaska Native",
180
+ "Native Hawaiian or Other Pacific Islander", "Other", "Prefer not to say"
181
+ ].freeze
182
+
183
+ def generate_random(rng, context, args)
184
+ rng.sample(RACES)
185
+ end
186
+
187
+ def generate_edge(rng, context, args)
188
+ ["", "White", "Other"].sample(random: rng.instance_variable_get(:@random))
189
+ end
190
+
191
+ def generate_invalid(rng, context, args)
192
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
193
+ end
194
+ end
195
+
196
+ # DepartmentCorporate type
197
+ class DepartmentCorporate < Base
198
+ DEPARTMENTS = [
199
+ "Engineering", "Sales", "Marketing", "HR", "Finance",
200
+ "Operations", "Legal", "IT", "Customer Support", "Product"
201
+ ].freeze
202
+
203
+ def generate_random(rng, context, args)
204
+ rng.sample(DEPARTMENTS)
205
+ end
206
+
207
+ def generate_edge(rng, context, args)
208
+ ["", "Engineering", "Sales"].sample(random: rng.instance_variable_get(:@random))
209
+ end
210
+
211
+ def generate_invalid(rng, context, args)
212
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
213
+ end
214
+ end
215
+
216
+ # DepartmentRetail type
217
+ class DepartmentRetail < Base
218
+ DEPARTMENTS = [
219
+ "Electronics", "Clothing", "Home & Garden", "Sports & Outdoors",
220
+ "Toys & Games", "Books", "Automotive", "Health & Beauty", "Grocery"
221
+ ].freeze
222
+
223
+ def generate_random(rng, context, args)
224
+ rng.sample(DEPARTMENTS)
225
+ end
226
+
227
+ def generate_edge(rng, context, args)
228
+ ["", "Electronics", "Grocery"].sample(random: rng.instance_variable_get(:@random))
229
+ end
230
+
231
+ def generate_invalid(rng, context, args)
232
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TextContent
6
+ # Password type
7
+ class Password < Base
8
+ def generate_random(rng, context, args)
9
+ min_length = args[:min_length] || 8
10
+ min_upper = args[:min_upper] || 1
11
+ min_lower = args[:min_lower] || 1
12
+ min_numbers = args[:min_numbers] || 1
13
+ min_symbols = args[:min_symbols] || 0
14
+
15
+ uppercase = ('A'..'Z').to_a
16
+ lowercase = ('a'..'z').to_a
17
+ numbers = ('0'..'9').to_a
18
+ symbols = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=']
19
+
20
+ password = []
21
+ password.concat(min_upper.times.map { rng.sample(uppercase) })
22
+ password.concat(min_lower.times.map { rng.sample(lowercase) })
23
+ password.concat(min_numbers.times.map { rng.sample(numbers) })
24
+ password.concat(min_symbols.times.map { rng.sample(symbols) })
25
+
26
+ # Fill remaining length
27
+ all_chars = uppercase + lowercase + numbers + symbols
28
+ remaining = min_length - password.length
29
+ password.concat(remaining.times.map { rng.sample(all_chars) }) if remaining > 0
30
+
31
+ password.shuffle(random: rng.instance_variable_get(:@random)).join
32
+ end
33
+
34
+ def generate_edge(rng, context, args)
35
+ ["", "A", "12345678"].sample(random: rng.instance_variable_get(:@random))
36
+ end
37
+
38
+ def generate_invalid(rng, context, args)
39
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
40
+ end
41
+ end
42
+
43
+ # PasswordHash type
44
+ class PasswordHash < Base
45
+ def generate_random(rng, context, args)
46
+ # Generate bcrypt-like hash (60 characters)
47
+ chars = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['./']
48
+ "$2a$10$#{54.times.map { rng.sample(chars) }.join}"
49
+ end
50
+
51
+ def generate_edge(rng, context, args)
52
+ ["$2a$10$00000000000000000000000000000000000000000000000000000000"].sample(random: rng.instance_variable_get(:@random))
53
+ end
54
+
55
+ def generate_invalid(rng, context, args)
56
+ [nil, "not a hash", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
57
+ end
58
+ end
59
+
60
+ # Md5 type
61
+ class Md5 < Base
62
+ def generate_random(rng, context, args)
63
+ # Generate 32-character hex MD5 hash
64
+ chars = ('0'..'9').to_a + ('a'..'f').to_a
65
+ 32.times.map { rng.sample(chars) }.join
66
+ end
67
+
68
+ def generate_edge(rng, context, args)
69
+ ["00000000000000000000000000000000", "ffffffffffffffffffffffffffffffff"].sample(random: rng.instance_variable_get(:@random))
70
+ end
71
+
72
+ def generate_invalid(rng, context, args)
73
+ [nil, "not a hash", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
74
+ end
75
+ end
76
+
77
+ # Sha1 type
78
+ class Sha1 < Base
79
+ def generate_random(rng, context, args)
80
+ # Generate 40-character hex SHA1 hash
81
+ chars = ('0'..'9').to_a + ('a'..'f').to_a
82
+ 40.times.map { rng.sample(chars) }.join
83
+ end
84
+
85
+ def generate_edge(rng, context, args)
86
+ ["0000000000000000000000000000000000000000", "ffffffffffffffffffffffffffffffffffffffff"].sample(random: rng.instance_variable_get(:@random))
87
+ end
88
+
89
+ def generate_invalid(rng, context, args)
90
+ [nil, "not a hash", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
91
+ end
92
+ end
93
+
94
+ # Sha256 type
95
+ class Sha256 < Base
96
+ def generate_random(rng, context, args)
97
+ # Generate 64-character hex SHA256 hash
98
+ chars = ('0'..'9').to_a + ('a'..'f').to_a
99
+ 64.times.map { rng.sample(chars) }.join
100
+ end
101
+
102
+ def generate_edge(rng, context, args)
103
+ ["0000000000000000000000000000000000000000000000000000000000000000", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"].sample(random: rng.instance_variable_get(:@random))
104
+ end
105
+
106
+ def generate_invalid(rng, context, args)
107
+ [nil, "not a hash", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
108
+ end
109
+ end
110
+
111
+ # Encrypt type
112
+ class Encrypt < Base
113
+ def generate_random(rng, context, args)
114
+ # Generate a base64-like encrypted string
115
+ chars = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/', '=']
116
+ length = rng.int(20, 40)
117
+ length.times.map { rng.sample(chars) }.join
118
+ end
119
+
120
+ def generate_edge(rng, context, args)
121
+ ["", "AAAAAAAAAAAAAAAAAAAA", "ZZZZZZZZZZZZZZZZZZZZ"].sample(random: rng.instance_variable_get(:@random))
122
+ end
123
+
124
+ def generate_invalid(rng, context, args)
125
+ [nil, "not encrypted", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end