js-routes 2.2.10 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f69479723e452f1b4ed09bf940b3150ad45430b5c601f966f05a082bce0a9494
4
- data.tar.gz: bd47ceb7b1cba241262b8308e913f7d87aef6304d93d9185026e70dd4980487f
3
+ metadata.gz: 97421ede18a16a1cb38ede32268ea60e79dc3aeee2dbe419cbbc4f117848cebb
4
+ data.tar.gz: d65a56e1026ef6551a7e0c30f90278245dfed8b4ceca460c285b16855586709c
5
5
  SHA512:
6
- metadata.gz: 4f67b2ccc88195647ea7c694f935848aad52ddd9e46ac1a766df0c29b7e123a147169deb5b8207c8d3a598fcf0c0ba01f98b0d24ee30b326737200f02f2f8235
7
- data.tar.gz: 9aad6d181099b3fdd7ada0facf1269e08669cd1181f94d3039f0e13f8bf2bc5a44172e13843fec5a8317b4c99e1eee6a2de2343e34fe6c3cddebb7a63f9608fb
6
+ metadata.gz: 13c8299991c8821aff0aa09f4b90ce3a38a9881b780688a6aabadf4871ab79948a095feb0fc9c76b4cc51c84f00aa758f5276838234e963efa1bb641db526984
7
+ data.tar.gz: 651ae1108a3845a1b948c0b9a1bb9475a2374d6178bd0cf35a7da2dca990081b2bfd40fb2beb92301a4efa3cdef143e83e04a7c39afb7394a685383d9a6b8a91
data/CHANGELOG.md CHANGED
@@ -1,12 +1,24 @@
1
1
  # Changelog
2
2
 
3
- ## master
3
+ ## v2.3.1
4
+
5
+ * Add timestamp on when routes.js was generated into banner.
6
+ * Fix application specified directly without proc. [#323](https://github.com/railsware/js-routes/issues/323)
7
+ * Support `optional_definition_params` option. See [Related Docs](./Readme.md#optional-definition-params).
8
+
9
+ ## v2.3.0
10
+
11
+ * Drop support of Rails 4.x
12
+ * Fix support of shakapacker [#321](https://github.com/railsware/js-routes/issues/321).
13
+ * Fix support for Rails 8 [#319](https://github.com/railsware/js-routes/issues/319)
14
+ * Deprecated `rake js:routes:typescript`.
15
+ `rake js:routes` now automatically detects if types support can be used on not.
4
16
 
5
17
  ## v2.2.10
6
18
 
7
19
  * Remove sorbet files from repo
8
20
  * Clearly define files included in gem
9
- * Fix Middleware and Middleware generator bugs [#316](https://github.com/railsware/js-routes/issue/316)
21
+ * Fix Middleware and Middleware generator bugs [#316](https://github.com/railsware/js-routes/issues/316)
10
22
  * Remove empty object linter warning on DTS module
11
23
  * Generators: Add `.ts` extension when searching for main JS file of the project
12
24
 
@@ -14,7 +26,8 @@
14
26
 
15
27
  * Fix middleware error for non-modern setup.
16
28
  * Added [Sorbet](https://sorbet.org/) method signatures.
17
- * Always use DTS module type when calling JsRoutes.definitions or .definitions!. [#313](https://github.com/railsware/js-routes/issues/313)
29
+ * Always use DTS module type when calling JsRoutes.definitions or .definitions!.
30
+ [#313](https://github.com/railsware/js-routes/issues/313)
18
31
 
19
32
  ## v2.2.8
20
33
 
data/Readme.md CHANGED
@@ -2,7 +2,16 @@
2
2
 
3
3
  [![CI](https://github.com/railsware/js-routes/actions/workflows/ci.yml/badge.svg)](https://github.com/railsware/js-routes/actions/workflows/ci.yml)
4
4
 
5
- Generates javascript file that defines all Rails named routes as javascript helpers
5
+ Generates javascript file that defines all Rails named routes as javascript helpers:
6
+
7
+ ``` js
8
+ import { root_path, api_user_path } from './routes';
9
+
10
+ root_path() # => /
11
+ api_user_path(25, include_profile: true, format: 'json') // => /api/users/25.json?include_profile=true
12
+ ```
13
+
14
+ [More Examples](#usage)
6
15
 
7
16
  ## Intallation
8
17
 
@@ -33,8 +42,8 @@ There are several possible ways to setup JsRoutes:
33
42
 
34
43
  ### Quick Start
35
44
 
36
- Setup [Rack Middleware](https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack)
37
- to automatically generate and maintain `routes.js` file and corresponding
45
+ Setup [Rack Middleware](https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack)
46
+ to automatically generate and maintain `routes.js` file and corresponding
38
47
  [Typescript definitions](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html) `routes.d.ts`:
39
48
 
40
49
  #### Use a Generator
@@ -61,13 +70,12 @@ import {post_path} from '../routes';
61
70
  alert(post_path(1))
62
71
  ```
63
72
 
64
- Upgrade js building process to update js-routes files in `Rakefile`:
73
+ Upgrade js building process to update js-routes files in `Rakefile`:
65
74
 
66
75
  ``` ruby
67
- task "javascript:build" => "js:routes:typescript"
76
+ task "javascript:build" => "js:routes"
68
77
  # For setups without jsbundling-rails
69
- task "assets:precompile" => "js:routes:typescript"
70
-
78
+ task "assets:precompile" => "js:routes"
71
79
  ```
72
80
 
73
81
  Add js-routes files to `.gitignore`:
@@ -227,7 +235,7 @@ JsRoutes.definitions! # to output to file
227
235
  JsRoutes.definitions # to output to string
228
236
  ```
229
237
 
230
- Even more advanced setups can be achieved by setting `module_type` to `DTS` inside [configuration](#module_type)
238
+ Even more advanced setups can be achieved by setting `module_type` to `DTS` inside [configuration](#module_type)
231
239
  which will cause any `JsRoutes` instance to generate defintions instead of routes themselves.
232
240
 
233
241
  <div id="sprockets"></div>
@@ -316,9 +324,13 @@ Options to configure JavaScript file generator. These options are only available
316
324
  * Sample route call when option is set to true: `users() // => /users`
317
325
  * `application` - a key to specify which rails engine you want to generate routes too.
318
326
  * This option allows to only generate routes for a specific rails engine, that is mounted into routes instead of all Rails app routes
319
- * Default: `Rails.application`
327
+ * It is recommended to wrap the value with `lambda`. This will reduce the reliance on order during initialization your application.
328
+ * Default: `-> { Rails.application }`
320
329
  * `file` - a file location where generated routes are stored
321
330
  * Default: `app/javascript/routes.js` if setup with Webpacker, otherwise `app/assets/javascripts/routes.js` if setup with Sprockets.
331
+ * `optional_definition_params` - make all route paramters in definition optional
332
+ * See [related compatibility issue](#optional-definition-params)
333
+ * Default: `false`
322
334
 
323
335
  <div id="formatter-options"></div>
324
336
 
@@ -348,35 +360,35 @@ Configuration above will create a nice javascript file with `Routes` object that
348
360
  ``` js
349
361
  import {
350
362
  user_path, user_project_path, company_path
351
- } as Routes from 'routes';
363
+ } from 'routes';
352
364
 
353
- users_path()
365
+ users_path()
354
366
  // => "/users"
355
367
 
356
- user_path(1)
368
+ user_path(1)
357
369
  // => "/users/1"
358
-
359
- user_path(1, {format: 'json'})
370
+
371
+ user_path(1, {format: 'json'})
360
372
  // => "/users/1.json"
361
373
 
362
- user_path(1, {anchor: 'profile'})
374
+ user_path(1, {anchor: 'profile'})
363
375
  // => "/users/1#profile"
364
376
 
365
- new_user_project_path(1, {format: 'json'})
377
+ new_user_project_path(1, {format: 'json'})
366
378
  // => "/users/1/projects/new.json"
367
379
 
368
- user_project_path(1,2, {q: 'hello', custom: true})
380
+ user_project_path(1,2, {q: 'hello', custom: true})
369
381
  // => "/users/1/projects/2?q=hello&custom=true"
370
382
 
371
- user_project_path(1,2, {hello: ['world', 'mars']})
383
+ user_project_path(1,2, {hello: ['world', 'mars']})
372
384
  // => "/users/1/projects/2?hello%5B%5D=world&hello%5B%5D=mars"
373
385
 
374
386
  var google = {id: 1, name: "Google"};
375
- company_path(google)
387
+ company_path(google)
376
388
  // => "/companies/1"
377
389
 
378
390
  var google = {id: 1, name: "Google", to_param: "google"};
379
- company_path(google)
391
+ company_path(google)
380
392
  // => "/companies/google"
381
393
  ```
382
394
 
@@ -419,14 +431,63 @@ In this case you would need to pass a special key to help:
419
431
  ``` js
420
432
  import {company_project_path} from '../routes'
421
433
 
422
- company_project_path({company_id: 1, id: 2}) // => Not enough parameters
423
- company_project_path({company_id: 1, id: 2, _options: true}) // => "/companies/1/projects/2"
434
+ company_project_path({company_id: 1, id: 2})
435
+ // => Not enough parameters
436
+ company_project_path({company_id: 1, id: 2, _options: true})
437
+ // => "/companies/1/projects/2"
438
+ ```
439
+
440
+ Use `special_options_key` to configure the `_options` parameter name.
441
+
442
+ <div id="optional-definition-params"></div>
443
+
444
+ ### Rails required parameters specified as optional
445
+
446
+ Rails is very flexible on how route parameters can be specified.
447
+ All of the following calls will make the same result:
448
+
449
+ ``` ruby
450
+ # Given route
451
+ # /inboxes/:inbox_id/messages/:message_id/attachments/:id
452
+ # every call below returns:
453
+ # => "/inboxes/1/messages/2/attachments/3"
454
+
455
+ inbox_message_attachment_path(1, 2, 3)
456
+ inbox_message_attachment_path(1, 2, id: 3)
457
+ inbox_message_attachment_path(1, message_id: 2, id: 3)
458
+ inbox_message_attachment_path(inbox_id: 1, message_id: 2, id: 3)
459
+
460
+ # including these mad versions
461
+ inbox_message_attachment_path(2, inbox_id: 1, id: 3)
462
+ inbox_message_attachment_path(1, 3, message_id: 2)
463
+ inbox_message_attachment_path(3, inbox_id: 1, message_id: 2)
424
464
  ```
425
465
 
466
+ While all of these methods are supported by JsRoutes, it is impossible to support them in `DTS` type definitions.
467
+ If you are using routes like this, use the following configuration that will prevent required parameters presence to be validated by definition:
468
+
469
+ ``` ruby
470
+ JsRoutes.configure do |c|
471
+ c.optional_definition_params = true
472
+ end
473
+ ```
474
+
475
+ This will enforce the following route signature:
476
+
477
+ ``` typescript
478
+ export const inbox_message_attachment_path: ((
479
+ inbox_id?: RequiredRouteParameter,
480
+ message_id?: RequiredRouteParameter,
481
+ id?: RequiredRouteParameter,
482
+ options?: RouteOptions
483
+ ) => string) & RouteHelperExtras;
484
+ ```
485
+
486
+ That will make every call above valid.
426
487
 
427
488
  ## What about security?
428
489
 
429
- JsRoutes itself does not have security holes.
490
+ JsRoutes itself does not have security holes.
430
491
  It makes URLs without access protection more reachable by potential attacker.
431
492
  If that is an issue for you, you may use one of the following solutions:
432
493
 
@@ -459,15 +520,13 @@ console.log(routes.inbox_path); // OK, only `inbox_path` is included in the bund
459
520
  console.log(Object.keys(routes)); // forces bundler to include all exports, breaking tree shaking
460
521
  ```
461
522
 
462
- ### Exclude option
523
+ ### Exclude/Include options
463
524
 
464
525
  Split your routes into multiple files related to each section of your website like:
465
526
 
466
- ``` javascript
467
- // admin-routes.js.erb
468
- <%= JsRoutes.generate(include: /^admin_/) %>
469
- // app-routes.js.erb
470
- <%= JsRoutes.generate(exclude: /^admin_/) %>
527
+ ``` ruby
528
+ JsRoutes.generate!('app/javascript/admin-routes.js', include: /^admin_/) %>
529
+ JsRoutes.generate!('app/javascript/app-routes.js', exclude: /^admin_/) %>
471
530
  ```
472
531
 
473
532
  ## Advantages over alternatives
@@ -475,17 +534,9 @@ Split your routes into multiple files related to each section of your website li
475
534
  There are some alternatives available. Most of them has only basic feature and don't reach the level of quality I accept.
476
535
  Advantages of this one are:
477
536
 
478
- * Rails 4,5,6 support
537
+ * Actively maintained
479
538
  * [ESM Tree shaking](https://webpack.js.org/guides/tree-shaking/) support
480
539
  * Rich options set
481
540
  * Full rails compatibility
482
541
  * Support Rails `#to_param` convention for seo optimized paths
483
542
  * Well tested
484
-
485
- #### Thanks to [contributors](https://github.com/railsware/js-routes/contributors)
486
-
487
- #### Have fun
488
-
489
-
490
- ## License
491
- [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes?ref=badge_large)
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
+
2
3
  require "pathname"
3
4
  require "js_routes/types"
5
+ require 'js_routes/utils'
4
6
 
5
7
  module JsRoutes
6
8
  class Configuration
@@ -35,6 +37,8 @@ module JsRoutes
35
37
  attr_accessor :documentation
36
38
  sig { returns(T.nilable(String)) }
37
39
  attr_accessor :module_type
40
+ sig { returns(T::Boolean) }
41
+ attr_accessor :optional_definition_params
38
42
 
39
43
  sig {params(attributes: T.nilable(Options)).void }
40
44
  def initialize(attributes = nil)
@@ -52,6 +56,7 @@ module JsRoutes
52
56
  @application = T.let(-> { Rails.application }, ApplicationCaller)
53
57
  @module_type = T.let('ESM', T.nilable(String))
54
58
  @documentation = T.let(true, T::Boolean)
59
+ @optional_definition_params = T.let(false, T::Boolean)
55
60
 
56
61
  return unless attributes
57
62
  assign(attributes)
@@ -114,14 +119,14 @@ module JsRoutes
114
119
 
115
120
  sig { returns(Pathname) }
116
121
  def output_file
117
- webpacker_dir = defined?(::Webpacker) ?
118
- T.unsafe(::Webpacker).config.source_path :
119
- pathname('app', 'javascript')
122
+ shakapacker = JsRoutes::Utils.shakapacker
123
+ shakapacker_dir = shakapacker ?
124
+ shakapacker.config.source_path : pathname('app', 'javascript')
120
125
  sprockets_dir = pathname('app','assets','javascripts')
121
126
  file_name = file || default_file_name
122
127
  sprockets_file = sprockets_dir.join(file_name)
123
- webpacker_file = webpacker_dir.join(file_name)
124
- !Dir.exist?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
128
+ webpacker_file = shakapacker_dir.join(file_name)
129
+ !Dir.exist?(shakapacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
125
130
  end
126
131
 
127
132
  protected
@@ -10,8 +10,7 @@ class JsRoutes::Generators::Middleware < JsRoutes::Generators::Base
10
10
  if path = application_js_path
11
11
  inject_into_file path, pack_content
12
12
  end
13
- JsRoutes.generate!
14
- JsRoutes.definitions! if JsRoutes.configuration.modern?
13
+ JsRoutes.generate!(typed: true)
15
14
  end
16
15
 
17
16
  protected
@@ -34,10 +33,9 @@ alert(`JsRoutes installed.\\nYour root path is ${root_path()}`)
34
33
 
35
34
  def rakefile_content
36
35
  enhanced_task = depends_on_js_bundling? ? "javascript:build" : "assets:precompile"
37
- dependency_task = JsRoutes.configuration.modern? ? "js:routes:typescript" : 'js:routes'
38
36
  <<-RB
39
37
  # Update js-routes file before javascript build
40
- task "#{enhanced_task}" => "#{dependency_task}"
38
+ task "#{enhanced_task}" => "js:routes"
41
39
  RB
42
40
  end
43
41
 
@@ -1,11 +1,12 @@
1
1
  require "rails/generators"
2
+ require 'js_routes/utils'
2
3
 
3
4
  class JsRoutes::Generators::Webpacker < Rails::Generators::Base
4
5
 
5
6
  def create_webpack
6
7
  copy_file "initializer.rb", "config/initializers/js_routes.rb"
7
8
  copy_file "erb.js", "config/webpack/loaders/erb.js"
8
- copy_file "routes.js.erb", "#{Webpacker.config.source_path}/routes.js.erb"
9
+ copy_file "routes.js.erb", "#{JsRoutes::Utils.shakapacker.config.source_path}/routes.js.erb"
9
10
  inject_into_file "config/webpack/environment.js", loader_content
10
11
  if path = application_js_path
11
12
  inject_into_file path, pack_content
@@ -24,9 +24,16 @@ module JsRoutes
24
24
  sig {returns(String)}
25
25
  def generate
26
26
  # Ensure routes are loaded. If they're not, load them.
27
+
27
28
  application = T.unsafe(self.application)
28
- if named_routes.empty? && application.respond_to?(:reload_routes!, true)
29
- application.reload_routes!
29
+ if named_routes.empty?
30
+ if application.is_a?(Rails::Application)
31
+ if Rails.version >= "8.0.0"
32
+ application.reload_routes_unless_loaded
33
+ else
34
+ application.reload_routes!
35
+ end
36
+ end
30
37
  end
31
38
  content = File.read(@configuration.source_file)
32
39
 
@@ -69,15 +76,14 @@ module JsRoutes
69
76
 
70
77
  sig { returns(T::Hash[String, String]) }
71
78
  def js_variables
72
- version = Rails.version
73
79
  prefix = @configuration.prefix
74
80
  prefix = prefix.call if prefix.is_a?(Proc)
75
81
  {
76
82
  'GEM_VERSION' => JsRoutes::VERSION,
83
+ 'TIMESTAMP' => Time.now.to_s,
77
84
  'ROUTES_OBJECT' => routes_object,
78
85
  'RAILS_VERSION' => ::Rails.version,
79
- 'DEPRECATED_GLOBBING_BEHAVIOR' => version >= '4.0.0' && version < '4.1.0',
80
- 'DEPRECATED_FALSE_PARAMETER_BEHAVIOR' => version < '7.0.0',
86
+ 'DEPRECATED_FALSE_PARAMETER_BEHAVIOR' => Rails.version < '7.0.0',
81
87
  'APP_CLASS' => application.class.to_s,
82
88
  'DEFAULT_URL_OPTIONS' => json(@configuration.default_url_options),
83
89
  'PREFIX' => json(prefix),
@@ -111,7 +117,8 @@ module JsRoutes
111
117
 
112
118
  sig { returns(Application) }
113
119
  def application
114
- @configuration.application.call
120
+ app = @configuration.application
121
+ app.is_a?(Proc) ? app.call : app
115
122
  end
116
123
 
117
124
  sig { params(value: T.untyped).returns(String) }
@@ -178,8 +185,8 @@ export {};
178
185
  sig { params(route: JourneyRoute).returns(T::Array[StringArray]) }
179
186
  def mounted_app_routes(route)
180
187
  rails_engine_app = T.unsafe(app_from_route(route))
181
- if rails_engine_app.respond_to?(:superclass) &&
182
- rails_engine_app.superclass == Rails::Engine && !route.path.anchored
188
+ if rails_engine_app.is_a?(Class) &&
189
+ rails_engine_app < Rails::Engine && !route.path.anchored
183
190
  rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
184
191
  route_helpers_if_match(engine_route, route)
185
192
  end
@@ -191,9 +198,9 @@ export {};
191
198
  sig { params(route: JourneyRoute).returns(T.untyped) }
192
199
  def app_from_route(route)
193
200
  app = route.app
194
- # rails engine in Rails 4.2 use additional
201
+ # Rails Engine can use additional
195
202
  # ActionDispatch::Routing::Mapper::Constraints, which contain app
196
- if app.respond_to?(:app) && app.respond_to?(:constraints)
203
+ if app.is_a?(ActionDispatch::Routing::Mapper::Constraints)
197
204
  app.app
198
205
  else
199
206
  app
@@ -39,8 +39,7 @@ module JsRoutes
39
39
 
40
40
  sig { void }
41
41
  def regenerate
42
- JsRoutes.generate!
43
- JsRoutes.definitions! if JsRoutes.configuration.modern?
42
+ JsRoutes.generate!(typed: true)
44
43
  end
45
44
 
46
45
  sig { returns(T.nilable(Time)) }
@@ -66,7 +66,8 @@ module JsRoutes
66
66
  sig { returns(String) }
67
67
  def definition_body
68
68
  options_type = optional_parts_type ? "#{optional_parts_type} & RouteOptions" : "RouteOptions"
69
- args = required_parts.map{|p| "#{apply_case(p)}: RequiredRouteParameter"}
69
+ predicate = @configuration.optional_definition_params ? '?' : ''
70
+ args = required_parts.map{|p| "#{apply_case(p)}#{predicate}: RequiredRouteParameter"}
70
71
  args << "options?: #{options_type}"
71
72
  "((\n#{args.join(",\n").indent(2)}\n) => string) & RouteHelperExtras"
72
73
  end
@@ -194,7 +195,9 @@ JS
194
195
  sig { params(spec: SpecNode, parent_spec: T.nilable(RouteSpec)).returns(T.nilable(T.any(UntypedArray, String))) }
195
196
  def serialize(spec, parent_spec=nil)
196
197
  return nil unless spec
197
- # Rails 4 globbing requires * removal
198
+ # Removing special character prefix from route variable name
199
+ # * for globbing
200
+ # : for common parameter
198
201
  return spec.tr(':*', '') if spec.is_a?(String)
199
202
 
200
203
  result = serialize_spec(spec, parent_spec)
@@ -17,7 +17,7 @@ module JsRoutes
17
17
  JourneyRoute = T.type_alias{ActionDispatch::Journey::Route}
18
18
  RouteSpec = T.type_alias {T.untyped}
19
19
  Application = T.type_alias { T.any(T::Class[Rails::Engine], Rails::Application) }
20
- ApplicationCaller = T.type_alias { T.proc.returns(Application) }
20
+ ApplicationCaller = T.type_alias { T.any(Application, T.proc.returns(Application)) }
21
21
  Clusivity = T.type_alias { T.any(Regexp, T::Array[Regexp]) }
22
22
  FileName = T.type_alias { T.any(String, Pathname, NilClass) }
23
23
  ConfigurationBlock = T.type_alias { T.proc.params(arg0: JsRoutes::Configuration).void }
@@ -0,0 +1,18 @@
1
+ # typed: strict
2
+
3
+ module JsRoutes
4
+ module Utils
5
+ extend T::Sig
6
+ sig {returns(T.untyped)}
7
+ def self.shakapacker
8
+ if defined?(::Shakapacker)
9
+ ::Shakapacker
10
+ elsif defined?(::Webpacker)
11
+ ::Webpacker
12
+ else
13
+ nil
14
+ end
15
+ end
16
+ end
17
+
18
+ end
@@ -1,4 +1,4 @@
1
1
  # typed: strict
2
2
  module JsRoutes
3
- VERSION = "2.2.10"
3
+ VERSION = "2.3.1"
4
4
  end
data/lib/js_routes.rb CHANGED
@@ -34,9 +34,10 @@ module JsRoutes
34
34
  Instance.new(**opts).generate
35
35
  end
36
36
 
37
- sig { params(file_name: FileName, opts: T.untyped).void }
38
- def generate!(file_name = configuration.file, **opts)
37
+ sig { params(file_name: FileName, typed: T::Boolean, opts: T.untyped).void }
38
+ def generate!(file_name = configuration.file, typed: false, **opts)
39
39
  Instance.new(file: file_name, **opts).generate!
40
+ definitions!(file_name, **opts) if typed
40
41
  end
41
42
 
42
43
  sig { params(file_name: FileName, opts: T.untyped).void }
@@ -46,12 +47,14 @@ module JsRoutes
46
47
 
47
48
  sig { params(opts: T.untyped).returns(String) }
48
49
  def definitions(**opts)
49
- generate(**opts, module_type: 'DTS',)
50
+ generate(**opts, module_type: 'DTS')
50
51
  end
51
52
 
52
53
  sig { params(file_name: FileName, opts: T.untyped).void }
53
54
  def definitions!(file_name = nil, **opts)
54
- file_name ||= configuration.file&.sub(%r{(\.d)?\.(j|t)s\Z}, ".d.ts")
55
+ file_name ||= configuration.file
56
+
57
+ file_name = file_name&.sub(%r{(\.d)?\.(j|t)s\Z}, ".d.ts")
55
58
  generate!(file_name, **opts, module_type: 'DTS')
56
59
  end
57
60
 
data/lib/routes.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  /**
2
- * File generated by js-routes RubyVariables.GEM_VERSION
2
+ * File generated by js-routes RubyVariables.GEM_VERSION on RubyVariables.TIMESTAMP
3
3
  * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
4
  */
5
5
  declare type Optional<T> = {
6
6
  [P in keyof T]?: T[P] | null;
7
7
  };
8
+ declare type Collection<T> = Record<string, T>;
8
9
  declare type BaseRouteParameter = string | boolean | Date | number;
9
10
  declare type MethodRouteParameter = BaseRouteParameter | (() => BaseRouteParameter);
10
11
  declare type ModelRouteParameter = {
@@ -19,8 +20,8 @@ declare type OptionalRouteParameter = undefined | null | RequiredRouteParameter;
19
20
  declare type QueryRouteParameter = OptionalRouteParameter | QueryRouteParameter[] | {
20
21
  [k: string]: QueryRouteParameter;
21
22
  };
22
- declare type RouteParameters = Record<string, QueryRouteParameter>;
23
- declare type Serializable = Record<string, unknown>;
23
+ declare type RouteParameters = Collection<QueryRouteParameter>;
24
+ declare type Serializable = Collection<unknown>;
24
25
  declare type Serializer = (value: Serializable) => string;
25
26
  declare type RouteHelperExtras = {
26
27
  requiredParams(): string[];
@@ -32,9 +33,9 @@ declare type RequiredParameters<T extends number> = T extends 1 ? [RequiredRoute
32
33
  RequiredRouteParameter,
33
34
  RequiredRouteParameter
34
35
  ] : RequiredRouteParameter[];
35
- declare type RouteHelperOptions = RouteOptions & Record<string, OptionalRouteParameter>;
36
+ declare type RouteHelperOptions = RouteOptions & Collection<OptionalRouteParameter>;
36
37
  declare type RouteHelper<T extends number = number> = ((...args: [...RequiredParameters<T>, RouteHelperOptions]) => string) & RouteHelperExtras;
37
- declare type RouteHelpers = Record<string, RouteHelper>;
38
+ declare type RouteHelpers = Collection<RouteHelper>;
38
39
  declare type Configuration = {
39
40
  prefix: string;
40
41
  default_url_options: RouteParameters;
@@ -56,14 +57,13 @@ declare type KeywordUrlOptions = Optional<{
56
57
  params: RouteParameters;
57
58
  }>;
58
59
  declare type RouteOptions = KeywordUrlOptions & RouteParameters;
59
- declare type PartsTable = Record<string, {
60
+ declare type PartsTable = Collection<{
60
61
  r?: boolean;
61
62
  d?: OptionalRouteParameter;
62
63
  }>;
63
64
  declare type ModuleType = "CJS" | "AMD" | "UMD" | "ESM" | "DTS" | "NIL";
64
65
  declare const RubyVariables: {
65
66
  PREFIX: string;
66
- DEPRECATED_GLOBBING_BEHAVIOR: boolean;
67
67
  DEPRECATED_FALSE_PARAMETER_BEHAVIOR: boolean;
68
68
  SPECIAL_OPTIONS_KEY: string;
69
69
  DEFAULT_URL_OPTIONS: RouteParameters;
@@ -76,5 +76,5 @@ declare const define: undefined | (((arg: unknown[], callback: () => unknown) =>
76
76
  amd?: unknown;
77
77
  });
78
78
  declare const module: {
79
- exports: any;
79
+ exports: unknown;
80
80
  } | undefined;
data/lib/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * File generated by js-routes RubyVariables.GEM_VERSION
2
+ * File generated by js-routes RubyVariables.GEM_VERSION on RubyVariables.TIMESTAMP
3
3
  * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
4
  */
5
5
  // eslint-disable-next-line
@@ -30,8 +30,9 @@ RubyVariables.WRAPPER(
30
30
  const ModuleReferences = {
31
31
  CJS: {
32
32
  define(routes) {
33
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
34
- module.exports = routes;
33
+ if (module) {
34
+ module.exports = routes;
35
+ }
35
36
  },
36
37
  isSupported() {
37
38
  return typeof module === "object";
@@ -39,10 +40,11 @@ RubyVariables.WRAPPER(
39
40
  },
40
41
  AMD: {
41
42
  define(routes) {
42
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
43
- define([], function () {
44
- return routes;
45
- });
43
+ if (define) {
44
+ define([], function () {
45
+ return routes;
46
+ });
47
+ }
46
48
  },
47
49
  isSupported() {
48
50
  return typeof define === "function" && !!define.amd;
@@ -290,9 +292,9 @@ RubyVariables.WRAPPER(
290
292
  if (url_params.length) {
291
293
  result += "?" + url_params;
292
294
  }
293
- result += keyword_parameters.anchor
294
- ? "#" + keyword_parameters.anchor
295
- : "";
295
+ if (keyword_parameters.anchor) {
296
+ result += "#" + keyword_parameters.anchor;
297
+ }
296
298
  if (absolute) {
297
299
  result = this.route_url(keyword_parameters) + result;
298
300
  }
@@ -413,9 +415,7 @@ RubyVariables.WRAPPER(
413
415
  value = value.join("/");
414
416
  }
415
417
  const result = this.path_identifier(value);
416
- return RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR
417
- ? result
418
- : encodeURI(result);
418
+ return encodeURI(result);
419
419
  }
420
420
  get_prefix() {
421
421
  const prefix = this.configuration.prefix;
@@ -502,28 +502,27 @@ RubyVariables.WRAPPER(
502
502
  define_module(name, module) {
503
503
  this.ensure_module_supported(name);
504
504
  ModuleReferences[name].define(module);
505
+ return module;
505
506
  }
506
507
  }
507
- const Utils = new UtilsClass();
508
+ const utils = new UtilsClass();
508
509
  // We want this helper name to be short
509
510
  const __jsr = {
510
511
  r(parts_table, route_spec, absolute) {
511
- return Utils.route(parts_table, route_spec, absolute);
512
+ return utils.route(parts_table, route_spec, absolute);
512
513
  },
513
514
  };
514
- const result = {
515
+ return utils.define_module(RubyVariables.MODULE_TYPE, {
515
516
  ...__jsr,
516
517
  configure: (config) => {
517
- return Utils.configure(config);
518
+ return utils.configure(config);
518
519
  },
519
520
  config: () => {
520
- return Utils.config();
521
+ return utils.config();
521
522
  },
522
523
  serialize: (object) => {
523
- return Utils.serialize(object);
524
+ return utils.serialize(object);
524
525
  },
525
526
  ...RubyVariables.ROUTES_OBJECT,
526
- };
527
- Utils.define_module(RubyVariables.MODULE_TYPE, result);
528
- return result;
527
+ });
529
528
  })();
data/lib/routes.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  /**
2
- * File generated by js-routes RubyVariables.GEM_VERSION
2
+ * File generated by js-routes RubyVariables.GEM_VERSION on RubyVariables.TIMESTAMP
3
3
  * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
4
  */
5
5
 
6
6
  type Optional<T> = { [P in keyof T]?: T[P] | null };
7
+ type Collection<T> = Record<string, T>;
8
+
7
9
  type BaseRouteParameter = string | boolean | Date | number;
8
10
  type MethodRouteParameter = BaseRouteParameter | (() => BaseRouteParameter);
9
11
  type ModelRouteParameter =
@@ -16,9 +18,9 @@ type QueryRouteParameter =
16
18
  | OptionalRouteParameter
17
19
  | QueryRouteParameter[]
18
20
  | { [k: string]: QueryRouteParameter };
19
- type RouteParameters = Record<string, QueryRouteParameter>;
21
+ type RouteParameters = Collection<QueryRouteParameter>;
20
22
 
21
- type Serializable = Record<string, unknown>;
23
+ type Serializable = Collection<unknown>;
22
24
  type Serializer = (value: Serializable) => string;
23
25
  type RouteHelperExtras = {
24
26
  requiredParams(): string[];
@@ -40,14 +42,14 @@ type RequiredParameters<T extends number> = T extends 1
40
42
  ]
41
43
  : RequiredRouteParameter[];
42
44
 
43
- type RouteHelperOptions = RouteOptions & Record<string, OptionalRouteParameter>;
45
+ type RouteHelperOptions = RouteOptions & Collection<OptionalRouteParameter>;
44
46
 
45
47
  type RouteHelper<T extends number = number> = ((
46
48
  ...args: [...RequiredParameters<T>, RouteHelperOptions]
47
49
  ) => string) &
48
50
  RouteHelperExtras;
49
51
 
50
- type RouteHelpers = Record<string, RouteHelper>;
52
+ type RouteHelpers = Collection<RouteHelper>;
51
53
 
52
54
  type Configuration = {
53
55
  prefix: string;
@@ -74,13 +76,12 @@ type KeywordUrlOptions = Optional<{
74
76
 
75
77
  type RouteOptions = KeywordUrlOptions & RouteParameters;
76
78
 
77
- type PartsTable = Record<string, { r?: boolean; d?: OptionalRouteParameter }>;
79
+ type PartsTable = Collection<{ r?: boolean; d?: OptionalRouteParameter }>;
78
80
 
79
81
  type ModuleType = "CJS" | "AMD" | "UMD" | "ESM" | "DTS" | "NIL";
80
82
 
81
83
  declare const RubyVariables: {
82
84
  PREFIX: string;
83
- DEPRECATED_GLOBBING_BEHAVIOR: boolean;
84
85
  DEPRECATED_FALSE_PARAMETER_BEHAVIOR: boolean;
85
86
  SPECIAL_OPTIONS_KEY: string;
86
87
  DEFAULT_URL_OPTIONS: RouteParameters;
@@ -94,7 +95,7 @@ declare const define:
94
95
  | undefined
95
96
  | (((arg: unknown[], callback: () => unknown) => void) & { amd?: unknown });
96
97
 
97
- declare const module: { exports: any } | undefined;
98
+ declare const module: { exports: unknown } | undefined;
98
99
 
99
100
  // eslint-disable-next-line
100
101
  RubyVariables.WRAPPER(
@@ -148,8 +149,9 @@ RubyVariables.WRAPPER(
148
149
  const ModuleReferences: Record<ModuleType, ModuleDefinition> = {
149
150
  CJS: {
150
151
  define(routes) {
151
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
152
- module!.exports = routes;
152
+ if (module) {
153
+ module.exports = routes;
154
+ }
153
155
  },
154
156
  isSupported() {
155
157
  return typeof module === "object";
@@ -157,10 +159,11 @@ RubyVariables.WRAPPER(
157
159
  },
158
160
  AMD: {
159
161
  define(routes) {
160
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
161
- define!([], function () {
162
- return routes;
163
- });
162
+ if (define) {
163
+ define([], function () {
164
+ return routes;
165
+ });
166
+ }
164
167
  },
165
168
  isSupported() {
166
169
  return typeof define === "function" && !!define.amd;
@@ -419,6 +422,7 @@ RubyVariables.WRAPPER(
419
422
  }
420
423
  return { keyword_parameters, query_parameters };
421
424
  }
425
+
422
426
  build_route(
423
427
  parts: string[],
424
428
  required_params: string[],
@@ -450,9 +454,9 @@ RubyVariables.WRAPPER(
450
454
  if (url_params.length) {
451
455
  result += "?" + url_params;
452
456
  }
453
- result += keyword_parameters.anchor
454
- ? "#" + keyword_parameters.anchor
455
- : "";
457
+ if (keyword_parameters.anchor) {
458
+ result += "#" + keyword_parameters.anchor;
459
+ }
456
460
  if (absolute) {
457
461
  result = this.route_url(keyword_parameters) + result;
458
462
  }
@@ -601,9 +605,7 @@ RubyVariables.WRAPPER(
601
605
  value = value.join("/");
602
606
  }
603
607
  const result = this.path_identifier(value as any);
604
- return RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR
605
- ? result
606
- : encodeURI(result);
608
+ return encodeURI(result);
607
609
  }
608
610
 
609
611
  get_prefix(): string {
@@ -679,7 +681,7 @@ RubyVariables.WRAPPER(
679
681
  return (isBrowser && window?.location?.port) || "";
680
682
  }
681
683
 
682
- is_object(value: unknown): value is Record<string, unknown> {
684
+ is_object(value: unknown): value is Collection<unknown> {
683
685
  return (
684
686
  typeof value === "object" &&
685
687
  Object.prototype.toString.call(value) === "[object Object]"
@@ -717,13 +719,17 @@ RubyVariables.WRAPPER(
717
719
  }
718
720
  }
719
721
 
720
- define_module(name: ModuleType, module: RouterExposedMethods): void {
722
+ define_module(
723
+ name: ModuleType,
724
+ module: RouterExposedMethods
725
+ ): RouterExposedMethods {
721
726
  this.ensure_module_supported(name);
722
727
  ModuleReferences[name].define(module);
728
+ return module;
723
729
  }
724
730
  }
725
731
 
726
- const Utils = new UtilsClass();
732
+ const utils = new UtilsClass();
727
733
 
728
734
  // We want this helper name to be short
729
735
  const __jsr = {
@@ -732,25 +738,22 @@ RubyVariables.WRAPPER(
732
738
  route_spec: RouteTree,
733
739
  absolute?: boolean
734
740
  ): RouteHelper {
735
- return Utils.route(parts_table, route_spec, absolute);
741
+ return utils.route(parts_table, route_spec, absolute);
736
742
  },
737
743
  };
738
744
 
739
- const result = {
745
+ return utils.define_module(RubyVariables.MODULE_TYPE, {
740
746
  ...__jsr,
741
747
  configure: (config: Partial<Configuration>) => {
742
- return Utils.configure(config);
748
+ return utils.configure(config);
743
749
  },
744
750
  config: (): Configuration => {
745
- return Utils.config();
751
+ return utils.config();
746
752
  },
747
753
  serialize: (object: Serializable): string => {
748
- return Utils.serialize(object);
754
+ return utils.serialize(object);
749
755
  },
750
756
  ...RubyVariables.ROUTES_OBJECT,
751
- };
752
-
753
- Utils.define_module(RubyVariables.MODULE_TYPE, result);
754
- return result;
757
+ });
755
758
  }
756
759
  )();
@@ -2,13 +2,15 @@ namespace :js do
2
2
  desc "Make a js file with all rails route URL helpers"
3
3
  task routes: :environment do
4
4
  require "js-routes"
5
- JsRoutes.generate!
5
+ JsRoutes.generate!(typed: true)
6
6
  end
7
7
 
8
8
  namespace :routes do
9
9
  desc "Make a js file with all rails route URL helpers and typescript definitions for them"
10
10
  task typescript: "js:routes" do
11
- JsRoutes.definitions!
11
+ ActiveSupport::Deprecation.warn(
12
+ "`js:routes:typescript` task is deprecated. Please use `js:routes` instead."
13
+ )
12
14
  end
13
15
  end
14
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: js-routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.10
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdan Gusiev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-03 00:00:00.000000000 Z
11
+ date: 2024-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4'
19
+ version: '5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4'
26
+ version: '5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sorbet-runtime
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,48 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.5.2
97
- - !ruby/object:Gem::Dependency
98
- name: bump
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 0.10.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 0.10.0
111
- - !ruby/object:Gem::Dependency
112
- name: byebug
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: pry-byebug
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
97
  - !ruby/object:Gem::Dependency
140
98
  name: mini_racer
141
99
  requirement: !ruby/object:Gem::Requirement
@@ -172,6 +130,7 @@ files:
172
130
  - lib/js_routes/middleware.rb
173
131
  - lib/js_routes/route.rb
174
132
  - lib/js_routes/types.rb
133
+ - lib/js_routes/utils.rb
175
134
  - lib/js_routes/version.rb
176
135
  - lib/routes.d.ts
177
136
  - lib/routes.js
@@ -185,9 +144,9 @@ licenses:
185
144
  - MIT
186
145
  metadata:
187
146
  bug_tracker_uri: https://github.com/railsware/js-routes/issues
188
- changelog_uri: https://github.com/railsware/js-routes/blob/v2.2.10/CHANGELOG.md
147
+ changelog_uri: https://github.com/railsware/js-routes/blob/v2.3.1/CHANGELOG.md
189
148
  documentation_uri: https://github.com/railsware/js-routes
190
- source_code_uri: https://github.com/railsware/js-routes/tree/v2.2.10/activerecord
149
+ source_code_uri: https://github.com/railsware/js-routes/tree/v2.3.1/activerecord
191
150
  rubygems_mfa_required: 'true'
192
151
  github_repo: ssh://github.com/railsware/js-routes
193
152
  post_install_message:
@@ -205,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
164
  - !ruby/object:Gem::Version
206
165
  version: '0'
207
166
  requirements: []
208
- rubygems_version: 3.2.22
167
+ rubygems_version: 3.5.16
209
168
  signing_key:
210
169
  specification_version: 4
211
170
  summary: Brings Rails named routes to javascript