Class: Synthra::Export::Javascript
- Defined in:
- lib/synthra/export/javascript.rb
Overview
Exports schema as JavaScript with JSDoc type annotations
Constant Summary collapse
- TYPE_MAPPINGS =
Type mappings from DSL types to JSDoc types
{ # Strings "uuid" => "string", "ulid" => "string", "email" => "string", "url" => "string", "ip" => "string", "ipv6" => "string", "date" => "string", "past_date" => "string", "future_date" => "string", "timestamp" => "string", "text" => "string", "name" => "string", "full_name" => "string", "first_name" => "string", "last_name" => "string", "phone" => "string", "city" => "string", "country" => "string", "country_code" => "string", "postal_code" => "string", "state" => "string", "street" => "string", "address" => "string", "username" => "string", "social_handle" => "string", "domain" => "string", "user_agent" => "string", "mac_address" => "string", "iban" => "string", "credit_card" => "string", "currency" => "string", "currency_code" => "string", "paragraph" => "string", "sentence" => "string", "word" => "string", "message_text" => "string", "hashtag_text" => "string", "snowflake_id" => "string", "numeric_string_id" => "string", # Numbers (integers + floats both map to JS number) "number" => "number", "integer" => "number", "age" => "number", "airport_elevation" => "number", "discount" => "number", "formula" => "number", "row_number" => "number", "sequence" => "number", "id_sequence" => "number", "float" => "number", "money" => "number", "latitude" => "number", "longitude" => "number", "airport_latitude" => "number", "airport_longitude" => "number", "product_price" => "number", "tax_rate" => "number", "transaction_amount" => "number", # Boolean "boolean" => "boolean", # Date (string in JSON) "date_between" => "string", "mobile_device_release_date" => "string", "now" => "string", "datetime" => "string", # Objects "object" => "Object", "map_by_field" => "Object", # Arrays "array" => "Array", "empty_array" => "Array", "json_array" => "Array", "indices_pair" => "Array.<number>" }.freeze
Class Method Summary collapse
-
.export_all(registry, **options) ⇒ String
Export all schemas in a registry.
Instance Method Summary collapse
- #build_array_type(args) ⇒ Object private
- #build_const_type(args) ⇒ Object private
- #build_enum_type(args) ⇒ Object private
- #build_factory_function(target_schema) ⇒ Object private
- #build_one_of_type(args) ⇒ Object private
- #build_typedef(target_schema) ⇒ Object
- #collect_field_schemas(field, schemas) ⇒ Object private
- #collect_referenced_schemas ⇒ Object private
- #export ⇒ Object
- #field_default_value(field) ⇒ Object private
- #field_to_javascript(field) ⇒ Object private
Constructor Details
This class inherits a constructor from Synthra::Export::Base
Class Method Details
.export_all(registry, **options) ⇒ String
Export all schemas in a registry
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/synthra/export/javascript.rb', line 131 def self.export_all(registry, **) lines = [] lines << "/**" lines << " * Generated from Synthra schemas" lines << " * Schemas: #{registry.names.join(', ')}" lines << " */" lines << "" registry.schemas.each do |name, schema| exporter = new(schema, registry: registry, **) lines << exporter.build_typedef(schema) lines << "" end lines.join("\n") end |
Instance Method Details
#build_array_type(args) ⇒ Object (private)
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/synthra/export/javascript.rb', line 250 def build_array_type(args) element = args[:element] if element if schema_reference?(element.to_s) "Array.<#{element}>" elsif TYPE_MAPPINGS[element.to_s] "Array.<#{TYPE_MAPPINGS[element.to_s]}>" else # Unknown element types are string-producing types (e.g. array(string)). "Array.<string>" end else "Array.<*>" end end |
#build_const_type(args) ⇒ Object (private)
236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/synthra/export/javascript.rb', line 236 def build_const_type(args) value = args[:value] case value when String "'#{value}'" when TrueClass, FalseClass value.to_s when Numeric value.to_s else "'#{value}'" end end |
#build_enum_type(args) ⇒ Object (private)
231 232 233 234 |
# File 'lib/synthra/export/javascript.rb', line 231 def build_enum_type(args) values = args[:values]&.map { |v| v.respond_to?(:value) ? v.value : v } || [] "(#{values.map { |v| "'#{v}'" }.join('|')})" end |
#build_factory_function(target_schema) ⇒ Object (private)
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/synthra/export/javascript.rb', line 275 def build_factory_function(target_schema) lines = [] lines << "/**" lines << " * Create a new #{target_schema.name} object" lines << " * @param {Partial<#{target_schema.name}>} [overrides] - Optional field overrides" lines << " * @returns {#{target_schema.name}}" lines << " */" lines << "function create#{target_schema.name}(overrides = {}) {" lines << " return {" target_schema.fields.each_with_index do |field, i| default = field_default_value(field) comma = i < target_schema.fields.length - 1 ? "," : "" lines << " #{field.name}: overrides.#{field.name} ?? #{default}#{comma}" end lines << " };" lines << "}" lines.join("\n") end |
#build_one_of_type(args) ⇒ Object (private)
266 267 268 269 270 271 272 273 |
# File 'lib/synthra/export/javascript.rb', line 266 def build_one_of_type(args) schemas = args[:schemas] || [] types = schemas.map do |s| schema_name = s.is_a?(Hash) ? (s[:schema] || s["schema"]) : s.to_s schema_reference?(schema_name) ? schema_name : "Object" end "(#{types.join('|')})" end |
#build_typedef(target_schema) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/synthra/export/javascript.rb', line 148 def build_typedef(target_schema) lines = [] # JSDoc typedef lines << "/**" lines << " * @typedef {Object} #{target_schema.name}" if target_schema.deprecated? lines << " * @deprecated #{target_schema. || 'This type is deprecated'}" end target_schema.fields.each do |field| js_type = field_to_javascript(field) optional = field.optional? ? " (optional)" : "" nullable = field.nullable? ? "|null" : "" lines << " * @property {#{js_type}#{nullable}} #{field.optional? ? "[#{field.name}]" : field.name}#{optional}" end lines << " */" lines.join("\n") end |
#collect_field_schemas(field, schemas) ⇒ Object (private)
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/synthra/export/javascript.rb', line 180 def collect_field_schemas(field, schemas) type_name = field.type_name if schema_reference?(type_name) ref_schema = get_schema(type_name) if ref_schema && !schemas.any? { |s| s.name == ref_schema.name } schemas << ref_schema ref_schema.fields.each { |f| collect_field_schemas(f, schemas) } end end if type_name == "array" element = field.type_args[:element] if element && schema_reference?(element.to_s) ref_schema = get_schema(element.to_s) if ref_schema && !schemas.any? { |s| s.name == ref_schema.name } schemas << ref_schema ref_schema.fields.each { |f| collect_field_schemas(f, schemas) } end end end end |
#collect_referenced_schemas ⇒ Object (private)
172 173 174 175 176 177 178 |
# File 'lib/synthra/export/javascript.rb', line 172 def collect_referenced_schemas schemas = [] schema.fields.each do |field| collect_field_schemas(field, schemas) end schemas.uniq(&:name) end |
#export ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/synthra/export/javascript.rb', line 96 def export lines = [] # Add header comment lines << "/**" lines << " * Generated from Synthra schema: #{schema.name}" lines << " * Version: #{schema.version}" if schema.version lines << " * @deprecated #{schema.}" if schema.deprecated? lines << " */" lines << "" # Export referenced schemas first exported = Set.new collect_referenced_schemas.each do |ref_schema| lines << build_typedef(ref_schema) lines << "" exported << ref_schema.name end # Export main schema lines << build_typedef(schema) unless exported.include?(schema.name) # Add factory function lines << "" lines << build_factory_function(schema) lines.join("\n") end |
#field_default_value(field) ⇒ Object (private)
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/synthra/export/javascript.rb', line 296 def field_default_value(field) type_name = field.type_name return "null" if field.optional? || field.nullable? case type_name when "uuid", "ulid", "text", "name", "email", "url", "phone", "city", "country", "address" "''" when "number", "integer", "float", "money", "id_sequence" "0" when "boolean" "false" when "array" "[]" when "object", "map_by_field" "{}" when "enum" values = field.type_args[:values] || [] values.first ? "'#{values.first.respond_to?(:value) ? values.first.value : values.first}'" : "''" when "const" value = field.type_args[:value] value.is_a?(String) ? "'#{value}'" : value.to_s when "timestamp", "now", "date", "past_date", "future_date" "new Date().toISOString()" else schema_reference?(type_name) ? "{}" : "null" end end |
#field_to_javascript(field) ⇒ Object (private)
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/synthra/export/javascript.rb', line 203 def field_to_javascript(field) type_name = field.type_name type_args = field.type_args case type_name when "enum" build_enum_type(type_args) when "const" build_const_type(type_args) when "array" build_array_type(type_args) when "one_of" build_one_of_type(type_args) when "map_by_field" "Object.<string, Object>" else if TYPE_MAPPINGS[type_name] TYPE_MAPPINGS[type_name] elsif schema_reference?(type_name) type_name else # Most Synthra types generate strings, so an unmapped, non-structural # type is a string rather than the any-type wildcard. "string" end end end |