js-routes 1.4.1 → 2.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 (50) hide show
  1. checksums.yaml +5 -5
  2. data/.eslintrc.js +15 -0
  3. data/.gitignore +5 -0
  4. data/.nvmrc +1 -0
  5. data/.travis.yml +37 -30
  6. data/Appraisals +16 -13
  7. data/CHANGELOG.md +95 -0
  8. data/Rakefile +6 -2
  9. data/Readme.md +220 -88
  10. data/VERSION_2_UPGRADE.md +66 -0
  11. data/app/assets/javascripts/js-routes.js.erb +1 -1
  12. data/gemfiles/{rails40.gemfile → rails40_sprockets_2.gemfile} +1 -1
  13. data/gemfiles/{rails40_sprockets3.gemfile → rails40_sprockets_3.gemfile} +0 -0
  14. data/gemfiles/{rails41.gemfile → rails41_sprockets_2.gemfile} +1 -1
  15. data/gemfiles/{rails41_sprockets3.gemfile → rails41_sprockets_3.gemfile} +0 -0
  16. data/gemfiles/{rails32.gemfile → rails42_sprockets_2.gemfile} +2 -2
  17. data/gemfiles/{rails42_sprockets3.gemfile → rails42_sprockets_3.gemfile} +1 -1
  18. data/gemfiles/{rails50_sprockets3.gemfile → rails50_sprockets_3.gemfile} +1 -1
  19. data/gemfiles/rails51_sprockets_3.gemfile +8 -0
  20. data/gemfiles/rails52_sprockets_3.gemfile +8 -0
  21. data/js-routes.gemspec +9 -6
  22. data/lib/js_routes/engine.rb +6 -18
  23. data/lib/js_routes/version.rb +1 -1
  24. data/lib/js_routes.rb +329 -171
  25. data/lib/routes.d.ts +79 -0
  26. data/lib/routes.js +499 -485
  27. data/lib/routes.ts +732 -0
  28. data/lib/tasks/js_routes.rake +8 -2
  29. data/package.json +37 -0
  30. data/spec/dummy/app/assets/config/manifest.js +2 -0
  31. data/spec/js_routes/default_serializer_spec.rb +19 -3
  32. data/spec/js_routes/{amd_compatibility_spec.rb → module_types/amd_spec.rb} +1 -9
  33. data/spec/js_routes/module_types/cjs_spec.rb +15 -0
  34. data/spec/js_routes/module_types/dts/routes.spec.d.ts +114 -0
  35. data/spec/js_routes/module_types/dts/test.spec.ts +56 -0
  36. data/spec/js_routes/module_types/dts_spec.rb +111 -0
  37. data/spec/js_routes/module_types/esm_spec.rb +45 -0
  38. data/spec/js_routes/{generated_javascript_spec.rb → module_types/umd_spec.rb} +33 -27
  39. data/spec/js_routes/options_spec.rb +92 -50
  40. data/spec/js_routes/rails_routes_compatibility_spec.rb +107 -45
  41. data/spec/js_routes/zzz_last_post_rails_init_spec.rb +19 -8
  42. data/spec/spec_helper.rb +45 -42
  43. data/spec/support/routes.rb +19 -14
  44. data/spec/tsconfig.json +4 -0
  45. data/tsconfig.json +28 -0
  46. data/yarn.lock +2145 -0
  47. metadata +47 -34
  48. data/gemfiles/rails42.gemfile +0 -8
  49. data/gemfiles/rails50.gemfile +0 -8
  50. data/lib/routes.js.coffee +0 -386
data/lib/js_routes.rb CHANGED
@@ -1,46 +1,32 @@
1
1
  require 'uri'
2
- require 'js_routes/engine' if defined?(Rails)
2
+ if defined?(::Rails) && defined?(::Sprockets::Railtie)
3
+ require 'js_routes/engine'
4
+ end
3
5
  require 'js_routes/version'
6
+ require 'active_support/core_ext/string/indent'
4
7
 
5
8
  class JsRoutes
6
9
 
7
- #
8
- # OPTIONS
9
- #
10
+ class Configuration
11
+ DEFAULTS = {
12
+ namespace: nil,
13
+ exclude: [],
14
+ include: //,
15
+ file: nil,
16
+ prefix: -> { Rails.application.config.relative_url_root || "" },
17
+ url_links: false,
18
+ camel_case: false,
19
+ default_url_options: {},
20
+ compact: false,
21
+ serializer: nil,
22
+ special_options_key: "_options",
23
+ application: -> { Rails.application },
24
+ module_type: 'ESM',
25
+ documentation: true,
26
+ } #:nodoc:
27
+
28
+ attr_accessor(*DEFAULTS.keys)
10
29
 
11
- DEFAULT_PATH = File.join('app','assets','javascripts','routes.js')
12
-
13
- DEFAULTS = {
14
- namespace: "Routes",
15
- exclude: [],
16
- include: //,
17
- file: DEFAULT_PATH,
18
- prefix: -> { Rails.application.config.relative_url_root || "" },
19
- url_links: false,
20
- camel_case: false,
21
- default_url_options: {},
22
- compact: false,
23
- serializer: nil,
24
- special_options_key: "_options",
25
- application: -> { Rails.application }
26
- }
27
-
28
- NODE_TYPES = {
29
- GROUP: 1,
30
- CAT: 2,
31
- SYMBOL: 3,
32
- OR: 4,
33
- STAR: 5,
34
- LITERAL: 6,
35
- SLASH: 7,
36
- DOT: 8
37
- }
38
-
39
- LAST_OPTIONS_KEY = "options".freeze
40
- FILTERED_DEFAULT_PARTS = [:controller, :action, :subdomain]
41
- URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
42
-
43
- class Configuration < Struct.new(*DEFAULTS.keys)
44
30
  def initialize(attributes = nil)
45
31
  assign(DEFAULTS)
46
32
  return unless attributes
@@ -52,6 +38,7 @@ class JsRoutes
52
38
  value = value.call if value.is_a?(Proc)
53
39
  send(:"#{attribute}=", value)
54
40
  end
41
+ normalize_and_verify
55
42
  self
56
43
  end
57
44
 
@@ -66,6 +53,52 @@ class JsRoutes
66
53
  def to_hash
67
54
  Hash[*members.zip(values).flatten(1)].symbolize_keys
68
55
  end
56
+
57
+ def esm?
58
+ module_type === 'ESM'
59
+ end
60
+
61
+ def dts?
62
+ self.module_type === 'DTS'
63
+ end
64
+
65
+ def modern?
66
+ esm? || dts?
67
+ end
68
+
69
+ def source_file
70
+ File.dirname(__FILE__) + "/" + default_file_name
71
+ end
72
+
73
+ def output_file
74
+ webpacker_dir = Rails.root.join('app', 'javascript')
75
+ sprockets_dir = Rails.root.join('app','assets','javascripts')
76
+ file_name = file || default_file_name
77
+ sprockets_file = sprockets_dir.join(file_name)
78
+ webpacker_file = webpacker_dir.join(file_name)
79
+ !Dir.exist?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
80
+ end
81
+
82
+ def normalize_and_verify
83
+ normalize
84
+ verify
85
+ end
86
+
87
+ protected
88
+
89
+ def default_file_name
90
+ dts? ? "routes.d.ts" : "routes.js"
91
+ end
92
+
93
+ def normalize
94
+ self.module_type = module_type&.upcase || 'NIL'
95
+ end
96
+
97
+ def verify
98
+ if module_type != 'NIL' && namespace
99
+ raise "JsRoutes namespace option can only be used if module_type is nil"
100
+ end
101
+ end
69
102
  end
70
103
 
71
104
  #
@@ -75,11 +108,7 @@ class JsRoutes
75
108
  class << self
76
109
  def setup(&block)
77
110
  configuration.tap(&block) if block
78
- end
79
-
80
- def options
81
- ActiveSupport::Deprecation.warn('JsRoutes.options method is deprecated use JsRoutes.configuration instead')
82
- configuration
111
+ configuration.normalize_and_verify
83
112
  end
84
113
 
85
114
  def configuration
@@ -90,22 +119,13 @@ class JsRoutes
90
119
  new(opts).generate
91
120
  end
92
121
 
93
- def generate!(file_name=nil, opts = {})
94
- if file_name.is_a?(Hash)
95
- opts = file_name
96
- file_name = opts[:file]
97
- end
98
- new(opts).generate!(file_name)
122
+ def generate!(file_name=nil, **opts)
123
+ new(file: file_name, **opts).generate!
99
124
  end
100
125
 
101
- # Under rails 3.1.1 and higher, perform a check to ensure that the
102
- # full environment will be available during asset compilation.
103
- # This is required to ensure routes are loaded.
104
- def assert_usable_configuration!
105
- if 3 == Rails::VERSION::MAJOR && !Rails.application.config.assets.initialize_on_precompile
106
- raise("Cannot precompile js-routes unless environment is initialized. Please set config.assets.initialize_on_precompile to true.")
107
- end
108
- true
126
+ def definitions!(file_name = nil, **opts)
127
+ file_name ||= configuration.file&.sub!(%r{\.(j|t)s\Z}, ".d.ts")
128
+ new(file: file_name, module_type: 'DTS', **opts).generate!
109
129
  end
110
130
 
111
131
  def json(string)
@@ -126,66 +146,127 @@ class JsRoutes
126
146
  if named_routes.to_a.empty? && application.respond_to?(:reload_routes!)
127
147
  application.reload_routes!
128
148
  end
149
+ content = File.read(@configuration.source_file)
129
150
 
130
- {
131
- "GEM_VERSION" => JsRoutes::VERSION,
132
- "ROUTES" => js_routes,
133
- "DEPRECATED_BEHAVIOR" => Rails.version < "4",
134
- "NODE_TYPES" => json(NODE_TYPES),
135
-
136
- "APP_CLASS" => application.class.to_s,
137
- "NAMESPACE" => json(@configuration.namespace),
138
- "DEFAULT_URL_OPTIONS" => json(@configuration.default_url_options),
139
- "PREFIX" => json(@configuration.prefix),
140
- "SPECIAL_OPTIONS_KEY" => json(@configuration.special_options_key),
141
- "SERIALIZER" => @configuration.serializer || json(nil),
142
- }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)|
143
- js.gsub!(key, value.to_s)
151
+ if !@configuration.dts?
152
+ content = js_variables.inject(content) do |js, (key, value)|
153
+ js.gsub!("RubyVariables.#{key}", value.to_s) ||
154
+ raise("Missing key #{key} in JS template")
155
+ end
144
156
  end
157
+ content + routes_export + prevent_types_export
145
158
  end
146
159
 
147
- def generate!(file_name = nil)
148
- # Some libraries like Devise do not yet loaded their routes so we will wait
149
- # until initialization process finish
160
+ def generate!
161
+ # Some libraries like Devise did not load their routes yet
162
+ # so we will wait until initialization process finishes
150
163
  # https://github.com/railsware/js-routes/issues/7
151
164
  Rails.configuration.after_initialize do
152
- file_name ||= self.class.configuration['file']
153
- File.open(Rails.root.join(file_name), 'w') do |f|
154
- f.write generate
165
+ file_path = Rails.root.join(@configuration.output_file)
166
+ source_code = generate
167
+
168
+ # We don't need to rewrite file if it already exist and have same content.
169
+ # It helps asset pipeline or webpack understand that file wasn't changed.
170
+ next if File.exist?(file_path) && File.read(file_path) == source_code
171
+
172
+ File.open(file_path, 'w') do |f|
173
+ f.write source_code
155
174
  end
156
175
  end
157
176
  end
158
177
 
159
178
  protected
160
179
 
180
+ def js_variables
181
+ {
182
+ 'GEM_VERSION' => JsRoutes::VERSION,
183
+ 'ROUTES_OBJECT' => routes_object,
184
+ 'RAILS_VERSION' => ActionPack.version,
185
+ 'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
186
+
187
+ 'APP_CLASS' => application.class.to_s,
188
+ 'NAMESPACE' => json(@configuration.namespace),
189
+ 'DEFAULT_URL_OPTIONS' => json(@configuration.default_url_options),
190
+ 'PREFIX' => json(@configuration.prefix),
191
+ 'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
192
+ 'SERIALIZER' => @configuration.serializer || json(nil),
193
+ 'MODULE_TYPE' => json(@configuration.module_type),
194
+ 'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
195
+ }
196
+ end
197
+
161
198
  def application
162
199
  @configuration.application
163
200
  end
164
201
 
202
+ def json(string)
203
+ self.class.json(string)
204
+ end
205
+
165
206
  def named_routes
166
207
  application.routes.named_routes.to_a
167
208
  end
168
209
 
169
- def js_routes
170
- js_routes = named_routes.sort_by(&:first).flat_map do |_, route|
171
- [build_route_if_match(route)] + mounted_app_routes(route)
172
- end.compact
173
- "{\n" + js_routes.join(",\n") + "}\n"
210
+ def routes_object
211
+ return json({}) if @configuration.modern?
212
+ properties = routes_list.map do |comment, name, body|
213
+ "#{comment}#{name}: #{body}".indent(2)
214
+ end
215
+ "{\n" + properties.join(",\n\n") + "}\n"
216
+ end
217
+
218
+ def static_exports
219
+ [:configure, :config, :serialize].map do |name|
220
+ [
221
+ "", name,
222
+ @configuration.dts? ?
223
+ "RouterExposedMethods['#{name}']" :
224
+ "__jsr.#{name}"
225
+ ]
226
+ end
227
+ end
228
+
229
+ def routes_export
230
+ return "" unless @configuration.modern?
231
+ [*static_exports, *routes_list].map do |comment, name, body|
232
+ "#{comment}export const #{name}#{export_separator}#{body};\n\n"
233
+ end.join
234
+ end
235
+
236
+ def prevent_types_export
237
+ return "" unless @configuration.dts?
238
+ <<-JS
239
+ // By some reason this line prevents all types in a file
240
+ // from being automatically exported
241
+ export {};
242
+ JS
243
+ end
244
+
245
+ def export_separator
246
+ @configuration.dts? ? ': ' : ' = '
247
+ end
248
+
249
+ def routes_list
250
+ named_routes.sort_by(&:first).flat_map do |_, route|
251
+ route_helpers_if_match(route) + mounted_app_routes(route)
252
+ end
174
253
  end
175
254
 
176
255
  def mounted_app_routes(route)
177
- rails_engine_app = get_app_from_route(route)
178
- if rails_engine_app.respond_to?(:superclass) && rails_engine_app.superclass == Rails::Engine && !route.path.anchored
179
- rails_engine_app.routes.named_routes.map do |_, engine_route|
180
- build_route_if_match(engine_route, route)
256
+ rails_engine_app = app_from_route(route)
257
+ if rails_engine_app.respond_to?(:superclass) &&
258
+ rails_engine_app.superclass == Rails::Engine && !route.path.anchored
259
+ rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
260
+ route_helpers_if_match(engine_route, route)
181
261
  end
182
262
  else
183
263
  []
184
264
  end
185
265
  end
186
266
 
187
- def get_app_from_route(route)
188
- # rails engine in Rails 4.2 use additional ActionDispatch::Routing::Mapper::Constraints, which contain app
267
+ def app_from_route(route)
268
+ # rails engine in Rails 4.2 use additional
269
+ # ActionDispatch::Routing::Mapper::Constraints, which contain app
189
270
  if route.app.respond_to?(:app) && route.app.respond_to?(:constraints)
190
271
  route.app.app
191
272
  else
@@ -193,101 +274,178 @@ class JsRoutes
193
274
  end
194
275
  end
195
276
 
196
- def build_route_if_match(route, parent_route=nil)
197
- if any_match?(route, parent_route, @configuration[:exclude]) || !any_match?(route, parent_route, @configuration[:include])
198
- nil
199
- else
200
- build_js(route, parent_route)
201
- end
277
+ def route_helpers_if_match(route, parent_route = nil)
278
+ JsRoute.new(@configuration, route, parent_route).helpers
202
279
  end
203
280
 
204
- def any_match?(route, parent_route, matchers)
205
- full_route = [parent_route.try(:name), route.name].compact.join('_')
281
+ class JsRoute #:nodoc:
282
+ FILTERED_DEFAULT_PARTS = [:controller, :action]
283
+ URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
284
+ NODE_TYPES = {
285
+ GROUP: 1,
286
+ CAT: 2,
287
+ SYMBOL: 3,
288
+ OR: 4,
289
+ STAR: 5,
290
+ LITERAL: 6,
291
+ SLASH: 7,
292
+ DOT: 8
293
+ }
294
+
295
+ attr_reader :configuration, :route, :parent_route
296
+
297
+ def initialize(configuration, route, parent_route = nil)
298
+ @configuration = configuration
299
+ @route = route
300
+ @parent_route = parent_route
301
+ end
206
302
 
207
- matchers = Array(matchers)
208
- matchers.any? {|regex| full_route =~ regex}
209
- end
303
+ def helpers
304
+ helper_types.map do |absolute|
305
+ [ documentation, helper_name(absolute), body(absolute) ]
306
+ end
307
+ end
210
308
 
211
- def build_js(route, parent_route)
212
- name = [parent_route.try(:name), route.name].compact
213
- route_name = generate_route_name(name, (:path unless @configuration[:compact]))
214
- parent_spec = parent_route.try(:path).try(:spec)
215
- route_arguments = route_js_arguments(route, parent_spec)
216
- url_link = generate_url_link(name, route_name, route_arguments, route)
217
- _ = <<-JS.strip!
218
- // #{name.join('.')} => #{parent_spec}#{route.path.spec}
219
- // function(#{build_params(route.required_parts)})
220
- #{route_name}: Utils.route(#{route_arguments})#{",\n" + url_link if url_link.length > 0}
221
- JS
222
- end
309
+ def helper_types
310
+ return [] unless match_configuration?
311
+ @configuration[:url_links] ? [true, false] : [false]
312
+ end
223
313
 
224
- def route_js_arguments(route, parent_spec)
225
- required_parts = route.required_parts
226
- parts_table = route.parts.each_with_object({}) do |part, hash|
227
- hash[part] = required_parts.include?(part)
228
- end
229
- default_options = route.defaults.select do |part, _|
230
- FILTERED_DEFAULT_PARTS.exclude?(part) && URL_OPTIONS.include?(part) || parts_table[part]
231
- end
232
- [
233
- # JS objects don't preserve the order of properties which is crucial,
234
- # so array is a better choice.
235
- parts_table.to_a,
236
- default_options,
237
- serialize(route.path.spec, parent_spec)
238
- ].map do |argument|
239
- json(argument)
240
- end.join(", ")
241
- end
314
+ def body(absolute)
315
+ @configuration.dts? ?
316
+ definition_body : "__jsr.r(#{arguments(absolute).map{|a| json(a)}.join(', ')})"
317
+ end
242
318
 
243
- def generate_url_link(name, route_name, route_arguments, route)
244
- return "" unless @configuration[:url_links]
245
- <<-JS.strip!
246
- #{generate_route_name(name, :url)}: Utils.route(#{route_arguments}, true)
247
- JS
248
- end
319
+ def definition_body
320
+ args = required_parts.map{|p| "#{apply_case(p)}: RequiredRouteParameter"}
321
+ args << "options?: #{optional_parts_type} & RouteOptions"
322
+ "((\n#{args.join(",\n").indent(2)}\n) => string) & RouteHelperExtras"
323
+ end
249
324
 
250
- def generate_route_name(name, suffix)
251
- route_name = name.join('_')
252
- route_name << "_#{ suffix }" if suffix
253
- @configuration[:camel_case] ? route_name.camelize(:lower) : route_name
254
- end
325
+ def optional_parts_type
326
+ @optional_parts_type ||=
327
+ "{" + optional_parts.map {|p| "#{p}?: OptionalRouteParameter"}.join(', ') + "}"
328
+ end
255
329
 
256
- def json(string)
257
- self.class.json(string)
258
- end
330
+ protected
259
331
 
260
- def build_params(required_parts)
261
- params = required_parts + [LAST_OPTIONS_KEY]
262
- params.join(", ")
263
- end
332
+ def arguments(absolute)
333
+ absolute ? [*base_arguments, true] : base_arguments
334
+ end
264
335
 
265
- # This function serializes Journey route into JSON structure
266
- # We do not use Hash for human readable serialization
267
- # And preffer Array serialization because it is shorter.
268
- # Routes.js file will be smaller.
269
- def serialize(spec, parent_spec=nil)
270
- return nil unless spec
271
- return spec.tr(':', '') if spec.is_a?(String)
272
- result = serialize_spec(spec, parent_spec)
273
- if parent_spec && result[1].is_a?(String)
274
- result = [
275
- # We encode node symbols as integer
276
- # to reduce the routes.js file size
277
- NODE_TYPES[:CAT],
278
- serialize_spec(parent_spec),
279
- result
280
- ]
336
+ def match_configuration?
337
+ !match?(@configuration[:exclude]) && match?(@configuration[:include])
338
+ end
339
+
340
+ def base_name
341
+ @base_name ||= parent_route ?
342
+ [parent_route.name, route.name].join('_') : route.name
343
+ end
344
+
345
+ def parent_spec
346
+ parent_route&.path&.spec
347
+ end
348
+
349
+ def spec
350
+ route.path.spec
281
351
  end
282
- result
283
- end
284
352
 
285
- def serialize_spec(spec, parent_spec=nil)
286
- [
287
- NODE_TYPES[spec.type],
288
- serialize(spec.left, parent_spec),
289
- spec.respond_to?(:right) && serialize(spec.right)
290
- ]
353
+ def json(value)
354
+ JsRoutes.json(value)
355
+ end
356
+
357
+ def helper_name(absolute)
358
+ suffix = absolute ? :url : @configuration[:compact] ? nil : :path
359
+ apply_case(base_name, suffix)
360
+ end
361
+
362
+ def documentation
363
+ return nil unless @configuration[:documentation]
364
+ <<-JS
365
+ /**
366
+ * Generates rails route to
367
+ * #{parent_spec}#{spec}#{documentation_params}
368
+ * @param {object | undefined} options
369
+ * @returns {string} route path
370
+ */
371
+ JS
372
+ end
373
+
374
+ def required_parts
375
+ route.required_parts
376
+ end
377
+
378
+ def optional_parts
379
+ route.path.optional_names
380
+ end
381
+
382
+ def base_arguments
383
+ @base_arguments ||= [parts_table, serialize(spec, parent_spec)]
384
+ end
385
+
386
+ def parts_table
387
+ parts_table = {}
388
+ route.parts.each do |part, hash|
389
+ parts_table[part] ||= {}
390
+ if required_parts.include?(part)
391
+ # Using shortened keys to reduce js file size
392
+ parts_table[part][:r] = true
393
+ end
394
+ end
395
+ route.defaults.each do |part, value|
396
+ if FILTERED_DEFAULT_PARTS.exclude?(part) &&
397
+ URL_OPTIONS.include?(part) || parts_table[part]
398
+ parts_table[part] ||= {}
399
+ # Using shortened keys to reduce js file size
400
+ parts_table[part][:d] = value
401
+ end
402
+ end
403
+ parts_table
404
+ end
405
+
406
+ def documentation_params
407
+ required_parts.map do |param|
408
+ "\n * @param {any} #{apply_case(param)}"
409
+ end.join
410
+ end
411
+
412
+ def match?(matchers)
413
+ Array(matchers).any? { |regex| base_name =~ regex }
414
+ end
415
+
416
+ def apply_case(*values)
417
+ value = values.compact.map(&:to_s).join('_')
418
+ @configuration[:camel_case] ? value.camelize(:lower) : value
419
+ end
420
+
421
+ # This function serializes Journey route into JSON structure
422
+ # We do not use Hash for human readable serialization
423
+ # And preffer Array serialization because it is shorter.
424
+ # Routes.js file will be smaller.
425
+ def serialize(spec, parent_spec=nil)
426
+ return nil unless spec
427
+ # Rails 4 globbing requires * removal
428
+ return spec.tr(':*', '') if spec.is_a?(String)
429
+
430
+ result = serialize_spec(spec, parent_spec)
431
+ if parent_spec && result[1].is_a?(String) && parent_spec.type != :SLASH
432
+ result = [
433
+ # We encode node symbols as integer
434
+ # to reduce the routes.js file size
435
+ NODE_TYPES[:CAT],
436
+ serialize_spec(parent_spec),
437
+ result
438
+ ]
439
+ end
440
+ result
441
+ end
442
+
443
+ def serialize_spec(spec, parent_spec = nil)
444
+ [
445
+ NODE_TYPES[spec.type],
446
+ serialize(spec.left, parent_spec),
447
+ spec.respond_to?(:right) ? serialize(spec.right) : nil
448
+ ].compact
449
+ end
291
450
  end
292
451
  end
293
-
data/lib/routes.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * File generated by js-routes RubyVariables.GEM_VERSION
3
+ * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
+ */
5
+ declare type Optional<T> = {
6
+ [P in keyof T]?: T[P] | null;
7
+ };
8
+ declare type BaseRouteParameter = string | boolean | Date | number;
9
+ declare type MethodRouteParameter = BaseRouteParameter | (() => BaseRouteParameter);
10
+ declare type ModelRouteParameter = {
11
+ id: MethodRouteParameter;
12
+ } | {
13
+ to_param: MethodRouteParameter;
14
+ } | {
15
+ toParam: MethodRouteParameter;
16
+ };
17
+ declare type RequiredRouteParameter = BaseRouteParameter | ModelRouteParameter;
18
+ declare type OptionalRouteParameter = undefined | null | RequiredRouteParameter;
19
+ declare type QueryRouteParameter = OptionalRouteParameter | QueryRouteParameter[] | {
20
+ [k: string]: QueryRouteParameter;
21
+ };
22
+ declare type RouteParameters = Record<string, QueryRouteParameter>;
23
+ declare type Serializable = Record<string, unknown>;
24
+ declare type Serializer = (value: Serializable) => string;
25
+ declare type RouteHelperExtras = {
26
+ requiredParams(): string[];
27
+ toString(): string;
28
+ };
29
+ declare type RequiredParameters<T extends number> = T extends 1 ? [RequiredRouteParameter] : T extends 2 ? [RequiredRouteParameter, RequiredRouteParameter] : T extends 3 ? [RequiredRouteParameter, RequiredRouteParameter, RequiredRouteParameter] : T extends 4 ? [
30
+ RequiredRouteParameter,
31
+ RequiredRouteParameter,
32
+ RequiredRouteParameter,
33
+ RequiredRouteParameter
34
+ ] : RequiredRouteParameter[];
35
+ declare type RouteHelperOptions<T extends string> = RouteOptions & Optional<Record<T, OptionalRouteParameter>>;
36
+ declare type RouteHelper<T extends number = number, U extends string = string> = ((...args: [...RequiredParameters<T>, RouteHelperOptions<U>]) => string) & RouteHelperExtras;
37
+ declare type RouteHelpers = Record<string, RouteHelper>;
38
+ declare type Configuration = {
39
+ prefix: string;
40
+ default_url_options: RouteParameters;
41
+ special_options_key: string;
42
+ serializer: Serializer;
43
+ };
44
+ interface RouterExposedMethods {
45
+ config(): Configuration;
46
+ configure(arg: Partial<Configuration>): Configuration;
47
+ serialize: Serializer;
48
+ }
49
+ declare type KeywordUrlOptions = Optional<{
50
+ host: string;
51
+ protocol: string;
52
+ subdomain: string;
53
+ port: string | number;
54
+ anchor: string;
55
+ trailing_slash: boolean;
56
+ }>;
57
+ declare type RouteOptions = KeywordUrlOptions & RouteParameters;
58
+ declare type PartsTable = Record<string, {
59
+ r?: boolean;
60
+ d?: OptionalRouteParameter;
61
+ }>;
62
+ declare type ModuleType = "CJS" | "AMD" | "UMD" | "ESM" | "DTS" | "NIL";
63
+ declare const RubyVariables: {
64
+ PREFIX: string;
65
+ DEPRECATED_GLOBBING_BEHAVIOR: boolean;
66
+ SPECIAL_OPTIONS_KEY: string;
67
+ DEFAULT_URL_OPTIONS: RouteParameters;
68
+ SERIALIZER: Serializer;
69
+ NAMESPACE: string;
70
+ ROUTES_OBJECT: RouteHelpers;
71
+ MODULE_TYPE: ModuleType;
72
+ WRAPPER: <T>(callback: T) => T;
73
+ };
74
+ declare const define: undefined | (((arg: unknown[], callback: () => unknown) => void) & {
75
+ amd?: unknown;
76
+ });
77
+ declare const module: {
78
+ exports: any;
79
+ } | undefined;