js-routes 2.2.0 → 2.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 315ddd617bc6630cf5858afc5ba38d2c204f6167a7984ccdaf7171a50404e418
4
- data.tar.gz: 676d2d36107ee524c07517143499173c0658731cc06d1c52753e3ab2f4e6cb81
3
+ metadata.gz: 54158654106dece477c1fdf36afa52b504a43b8210c4c8d30f98d41ccd0ef600
4
+ data.tar.gz: a67b36754269392839bb6d2e86a20899ec2575437ac9667f10cdd9feb7306185
5
5
  SHA512:
6
- metadata.gz: 6c7f715e9afd02d1daebb882381e328595beca59a6a6d8c10a3a1518801522090e986c6b362174aaa9c51faf91508ee8e1cc6fff8ba118a08c32eb26c7205ba1
7
- data.tar.gz: 7f70bfa95a1fb42092f20118bb3f22f07e459ccc6f95b8d3b0651faf0457266152465873da6a4dfddc4d52df006d6f5b991e3608a083c1eb524fef5ed77ff0c8
6
+ metadata.gz: 582b6a39a062f6fcfd7b2cb4a57b4fd4573e343f93d5751ef764b7e3617cb7243801caf61ee971224a2c1a41e43a2f51221e5d3a40c12d5db21af98f47467044
7
+ data.tar.gz: f54b26ed68ed8ef2a6b4ad5ebf2e0322bfbec7385756a8578b5c11c01eca646d42baa5634d16cef6d16520e3eed4d1b1a37260e4ade943ee568b6b4755153cea
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## master
2
2
 
3
+ ## v2.2.1
4
+
5
+ * Improve generator to update route files on `assets:precompile` and add them to `.gitignore by default` [#288](https://github.com/railsware/js-routes/issues/288#issuecomment-1012182815)
6
+
3
7
  ## v2.2.0
4
8
 
5
9
  * Use Rack Middleware to automatically update routes file in development [#288](https://github.com/railsware/js-routes/issues/288)
data/Readme.md CHANGED
@@ -16,12 +16,12 @@ gem "js-routes"
16
16
 
17
17
  ## Setup
18
18
 
19
- There are 3 possible ways to setup JsRoutes:
19
+ There are several possible ways to setup JsRoutes:
20
20
 
21
21
  * [Quick and easy](#quick-start)
22
22
  * Uses Rack Middleware to automatically update routes locally
23
23
  * Works great for a simple Rails application
24
- * [Webpacker](#webpacker) automatic updates
24
+ * [Webpacker ERB Loader](#webpacker)
25
25
  * Requires ESM module system (the default)
26
26
  * Doesn't support typescript definitions
27
27
  * [Advanced Setup](#advanced-setup)
@@ -33,18 +33,52 @@ There are 3 possible ways to setup JsRoutes:
33
33
 
34
34
  ### Quick Start
35
35
 
36
- Setup [Rack Middleware](https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack) to automatically generate and maintain `routes.js` file and corresponding [Typescript definitions](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html) `routes.d.ts`:
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
38
+ [Typescript definitions](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html) `routes.d.ts`:
37
39
 
38
- Run:
40
+ #### Use a Generator
41
+
42
+ Run a command:
39
43
 
40
44
  ``` sh
41
45
  rails generate js_routes:middleware
42
46
  ```
43
47
 
48
+ #### Setup Manually
49
+
50
+ Add the following to `config/environments/development.rb`:
51
+
52
+ ``` ruby
53
+ config.middleware.use(JsRoutes::Middleware)
54
+ ```
55
+
56
+ Use it in `app/javascript/packs/application.js`:
57
+
58
+ ``` javascript
59
+ import * as Routes from '../routes';
60
+ // window.Routes = Routes;
61
+ alert(Routes.post_path(1))
62
+ ```
63
+
64
+ Upgrade `rake assets:precompile` to update js-routes files:
65
+
66
+ ``` ruby
67
+ namespace :assets do
68
+ task :precompile => "js:routes:typescript"
69
+ end
70
+ ```
71
+
72
+ Add js-routes files to `.gitignore`:
73
+
74
+ ```
75
+ /app/javascript/routes.js
76
+ /app/javascript/routes.d.ts
77
+ ```
44
78
 
45
79
  <div id='webpacker'></div>
46
80
 
47
- ### Webpacker + automatic updates - Typescript
81
+ ### Webpacker ERB loader
48
82
 
49
83
  **IMPORTANT**: this setup doesn't support IDE autocompletion with [Typescript](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html)
50
84
 
@@ -111,7 +145,7 @@ window.Routes = Routes;
111
145
 
112
146
  **IMPORTANT**: that this setup requires the JS routes file to be updates manually
113
147
 
114
- You can run every time you want to generate a routes file:
148
+ Routes file can be generated with a `rake` task:
115
149
 
116
150
  ``` sh
117
151
  rake js:routes
@@ -122,6 +156,8 @@ rake js:routes:typescript
122
156
  In case you need multiple route files for different parts of your application, you have to create the files manually.
123
157
  If your application has an `admin` and an `application` namespace for example:
124
158
 
159
+ **IMPORTANT**: Requires [Webpacker ERB Loader](#webpacker) setup.
160
+
125
161
  ``` erb
126
162
  // app/javascript/admin/routes.js.erb
127
163
  <%= JsRoutes.generate(include: /admin/) %>
@@ -6,11 +6,12 @@ class JsRoutes::Generators::Middleware < Rails::Generators::Base
6
6
 
7
7
  def create_middleware
8
8
  copy_file "initializer.rb", "config/initializers/js_routes.rb"
9
- # copy_file "erb.js", "config/webpack/loaders/erb.js"
10
- # copy_file "routes.js.erb", "app/javascript/routes.js.erb"
11
- # inject_into_file "config/webpack/environment.js", loader_content
12
9
  inject_into_file "app/javascript/packs/application.js", pack_content
13
10
  inject_into_file "config/environments/development.rb", middleware_content, before: /^end\n\z/
11
+ inject_into_file "Rakefile", rakefile_content
12
+ inject_into_file ".gitignore", gitignore_content
13
+ JsRoutes.generate!
14
+ JsRoutes.definitions!
14
15
  end
15
16
 
16
17
  protected
@@ -25,9 +26,33 @@ window.Routes = Routes;
25
26
  def middleware_content
26
27
  <<-RB
27
28
 
28
- # Automatically update routes.js file
29
+ # Automatically update js-routes file
29
30
  # when routes.rb is changed
30
31
  config.middleware.use(JsRoutes::Middleware)
31
32
  RB
32
33
  end
34
+
35
+ def rakefile_content
36
+ <<-RB
37
+
38
+ # Update js-routes file before assets precompile
39
+ namespace :assets do
40
+ task :precompile => "js:routes:typescript"
41
+ end
42
+ RB
43
+ end
44
+
45
+ def gitignore_content
46
+ banner = <<-TXT
47
+
48
+ # Ignore automatically generated js-routes files.
49
+ TXT
50
+
51
+ banner + [
52
+ {},
53
+ {module_type: 'DTS'}
54
+ ].map do |config|
55
+ File.join('/', JsRoutes.new(config).configuration.output_file) + "\n"
56
+ end.join
57
+ end
33
58
  end
@@ -0,0 +1,172 @@
1
+ class JsRoutes
2
+ class Route #:nodoc:
3
+ FILTERED_DEFAULT_PARTS = [:controller, :action]
4
+ URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
5
+ NODE_TYPES = {
6
+ GROUP: 1,
7
+ CAT: 2,
8
+ SYMBOL: 3,
9
+ OR: 4,
10
+ STAR: 5,
11
+ LITERAL: 6,
12
+ SLASH: 7,
13
+ DOT: 8
14
+ }
15
+
16
+ attr_reader :configuration, :route, :parent_route
17
+
18
+ def initialize(configuration, route, parent_route = nil)
19
+ @configuration = configuration
20
+ @route = route
21
+ @parent_route = parent_route
22
+ end
23
+
24
+ def helpers
25
+ helper_types.map do |absolute|
26
+ [ documentation, helper_name(absolute), body(absolute) ]
27
+ end
28
+ end
29
+
30
+ def helper_types
31
+ return [] unless match_configuration?
32
+ @configuration[:url_links] ? [true, false] : [false]
33
+ end
34
+
35
+ def body(absolute)
36
+ @configuration.dts? ?
37
+ definition_body : "__jsr.r(#{arguments(absolute).map{|a| json(a)}.join(', ')})"
38
+ end
39
+
40
+ def definition_body
41
+ args = required_parts.map{|p| "#{apply_case(p)}: RequiredRouteParameter"}
42
+ args << "options?: #{optional_parts_type} & RouteOptions"
43
+ "((\n#{args.join(",\n").indent(2)}\n) => string) & RouteHelperExtras"
44
+ end
45
+
46
+ def optional_parts_type
47
+ @optional_parts_type ||=
48
+ "{" + optional_parts.map {|p| "#{p}?: OptionalRouteParameter"}.join(', ') + "}"
49
+ end
50
+
51
+ protected
52
+
53
+ def arguments(absolute)
54
+ absolute ? [*base_arguments, true] : base_arguments
55
+ end
56
+
57
+ def match_configuration?
58
+ !match?(@configuration[:exclude]) && match?(@configuration[:include])
59
+ end
60
+
61
+ def base_name
62
+ @base_name ||= parent_route ?
63
+ [parent_route.name, route.name].join('_') : route.name
64
+ end
65
+
66
+ def parent_spec
67
+ parent_route&.path&.spec
68
+ end
69
+
70
+ def spec
71
+ route.path.spec
72
+ end
73
+
74
+ def json(value)
75
+ JsRoutes.json(value)
76
+ end
77
+
78
+ def helper_name(absolute)
79
+ suffix = absolute ? :url : @configuration[:compact] ? nil : :path
80
+ apply_case(base_name, suffix)
81
+ end
82
+
83
+ def documentation
84
+ return nil unless @configuration[:documentation]
85
+ <<-JS
86
+ /**
87
+ * Generates rails route to
88
+ * #{parent_spec}#{spec}#{documentation_params}
89
+ * @param {object | undefined} options
90
+ * @returns {string} route path
91
+ */
92
+ JS
93
+ end
94
+
95
+ def required_parts
96
+ route.required_parts
97
+ end
98
+
99
+ def optional_parts
100
+ route.path.optional_names
101
+ end
102
+
103
+ def base_arguments
104
+ @base_arguments ||= [parts_table, serialize(spec, parent_spec)]
105
+ end
106
+
107
+ def parts_table
108
+ parts_table = {}
109
+ route.parts.each do |part, hash|
110
+ parts_table[part] ||= {}
111
+ if required_parts.include?(part)
112
+ # Using shortened keys to reduce js file size
113
+ parts_table[part][:r] = true
114
+ end
115
+ end
116
+ route.defaults.each do |part, value|
117
+ if FILTERED_DEFAULT_PARTS.exclude?(part) &&
118
+ URL_OPTIONS.include?(part) || parts_table[part]
119
+ parts_table[part] ||= {}
120
+ # Using shortened keys to reduce js file size
121
+ parts_table[part][:d] = value
122
+ end
123
+ end
124
+ parts_table
125
+ end
126
+
127
+ def documentation_params
128
+ required_parts.map do |param|
129
+ "\n * @param {any} #{apply_case(param)}"
130
+ end.join
131
+ end
132
+
133
+ def match?(matchers)
134
+ Array(matchers).any? { |regex| base_name =~ regex }
135
+ end
136
+
137
+ def apply_case(*values)
138
+ value = values.compact.map(&:to_s).join('_')
139
+ @configuration[:camel_case] ? value.camelize(:lower) : value
140
+ end
141
+
142
+ # This function serializes Journey route into JSON structure
143
+ # We do not use Hash for human readable serialization
144
+ # And preffer Array serialization because it is shorter.
145
+ # Routes.js file will be smaller.
146
+ def serialize(spec, parent_spec=nil)
147
+ return nil unless spec
148
+ # Rails 4 globbing requires * removal
149
+ return spec.tr(':*', '') if spec.is_a?(String)
150
+
151
+ result = serialize_spec(spec, parent_spec)
152
+ if parent_spec && result[1].is_a?(String) && parent_spec.type != :SLASH
153
+ result = [
154
+ # We encode node symbols as integer
155
+ # to reduce the routes.js file size
156
+ NODE_TYPES[:CAT],
157
+ serialize_spec(parent_spec),
158
+ result
159
+ ]
160
+ end
161
+ result
162
+ end
163
+
164
+ def serialize_spec(spec, parent_spec = nil)
165
+ [
166
+ NODE_TYPES[spec.type],
167
+ serialize(spec.left, parent_spec),
168
+ spec.respond_to?(:right) ? serialize(spec.right) : nil
169
+ ].compact
170
+ end
171
+ end
172
+ end
@@ -1,3 +1,3 @@
1
1
  class JsRoutes
2
- VERSION = "2.2.0"
2
+ VERSION = "2.2.1"
3
3
  end
data/lib/js_routes.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'uri'
2
+ require "pathname"
3
+
2
4
  if defined?(::Rails) && defined?(::Sprockets::Railtie)
3
5
  require 'js_routes/engine'
4
6
  end
5
7
  require 'js_routes/version'
8
+ require "js_routes/route"
6
9
  require 'active_support/core_ext/string/indent'
7
10
 
8
11
  class JsRoutes
@@ -75,8 +78,8 @@ class JsRoutes
75
78
  end
76
79
 
77
80
  def output_file
78
- webpacker_dir = Rails.root.join('app', 'javascript')
79
- sprockets_dir = Rails.root.join('app','assets','javascripts')
81
+ webpacker_dir = pathname('app', 'javascript')
82
+ sprockets_dir = pathname('app','assets','javascripts')
80
83
  file_name = file || default_file_name
81
84
  sprockets_file = sprockets_dir.join(file_name)
82
85
  webpacker_file = webpacker_dir.join(file_name)
@@ -90,6 +93,10 @@ class JsRoutes
90
93
 
91
94
  protected
92
95
 
96
+ def pathname(*parts)
97
+ Pathname.new(File.join(*parts))
98
+ end
99
+
93
100
  def default_file_name
94
101
  dts? ? "routes.d.ts" : "routes.js"
95
102
  end
@@ -141,6 +148,7 @@ class JsRoutes
141
148
  end
142
149
  end
143
150
 
151
+ attr_reader :configuration
144
152
  #
145
153
  # Implementation
146
154
  #
@@ -284,179 +292,9 @@ export {};
284
292
  end
285
293
 
286
294
  def route_helpers_if_match(route, parent_route = nil)
287
- JsRoute.new(@configuration, route, parent_route).helpers
295
+ Route.new(@configuration, route, parent_route).helpers
288
296
  end
289
297
 
290
- class JsRoute #:nodoc:
291
- FILTERED_DEFAULT_PARTS = [:controller, :action]
292
- URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
293
- NODE_TYPES = {
294
- GROUP: 1,
295
- CAT: 2,
296
- SYMBOL: 3,
297
- OR: 4,
298
- STAR: 5,
299
- LITERAL: 6,
300
- SLASH: 7,
301
- DOT: 8
302
- }
303
-
304
- attr_reader :configuration, :route, :parent_route
305
-
306
- def initialize(configuration, route, parent_route = nil)
307
- @configuration = configuration
308
- @route = route
309
- @parent_route = parent_route
310
- end
311
-
312
- def helpers
313
- helper_types.map do |absolute|
314
- [ documentation, helper_name(absolute), body(absolute) ]
315
- end
316
- end
317
-
318
- def helper_types
319
- return [] unless match_configuration?
320
- @configuration[:url_links] ? [true, false] : [false]
321
- end
322
-
323
- def body(absolute)
324
- @configuration.dts? ?
325
- definition_body : "__jsr.r(#{arguments(absolute).map{|a| json(a)}.join(', ')})"
326
- end
327
-
328
- def definition_body
329
- args = required_parts.map{|p| "#{apply_case(p)}: RequiredRouteParameter"}
330
- args << "options?: #{optional_parts_type} & RouteOptions"
331
- "((\n#{args.join(",\n").indent(2)}\n) => string) & RouteHelperExtras"
332
- end
333
-
334
- def optional_parts_type
335
- @optional_parts_type ||=
336
- "{" + optional_parts.map {|p| "#{p}?: OptionalRouteParameter"}.join(', ') + "}"
337
- end
338
-
339
- protected
340
-
341
- def arguments(absolute)
342
- absolute ? [*base_arguments, true] : base_arguments
343
- end
344
-
345
- def match_configuration?
346
- !match?(@configuration[:exclude]) && match?(@configuration[:include])
347
- end
348
-
349
- def base_name
350
- @base_name ||= parent_route ?
351
- [parent_route.name, route.name].join('_') : route.name
352
- end
353
-
354
- def parent_spec
355
- parent_route&.path&.spec
356
- end
357
-
358
- def spec
359
- route.path.spec
360
- end
361
-
362
- def json(value)
363
- JsRoutes.json(value)
364
- end
365
-
366
- def helper_name(absolute)
367
- suffix = absolute ? :url : @configuration[:compact] ? nil : :path
368
- apply_case(base_name, suffix)
369
- end
370
-
371
- def documentation
372
- return nil unless @configuration[:documentation]
373
- <<-JS
374
- /**
375
- * Generates rails route to
376
- * #{parent_spec}#{spec}#{documentation_params}
377
- * @param {object | undefined} options
378
- * @returns {string} route path
379
- */
380
- JS
381
- end
382
-
383
- def required_parts
384
- route.required_parts
385
- end
386
-
387
- def optional_parts
388
- route.path.optional_names
389
- end
390
-
391
- def base_arguments
392
- @base_arguments ||= [parts_table, serialize(spec, parent_spec)]
393
- end
394
-
395
- def parts_table
396
- parts_table = {}
397
- route.parts.each do |part, hash|
398
- parts_table[part] ||= {}
399
- if required_parts.include?(part)
400
- # Using shortened keys to reduce js file size
401
- parts_table[part][:r] = true
402
- end
403
- end
404
- route.defaults.each do |part, value|
405
- if FILTERED_DEFAULT_PARTS.exclude?(part) &&
406
- URL_OPTIONS.include?(part) || parts_table[part]
407
- parts_table[part] ||= {}
408
- # Using shortened keys to reduce js file size
409
- parts_table[part][:d] = value
410
- end
411
- end
412
- parts_table
413
- end
414
-
415
- def documentation_params
416
- required_parts.map do |param|
417
- "\n * @param {any} #{apply_case(param)}"
418
- end.join
419
- end
420
-
421
- def match?(matchers)
422
- Array(matchers).any? { |regex| base_name =~ regex }
423
- end
424
-
425
- def apply_case(*values)
426
- value = values.compact.map(&:to_s).join('_')
427
- @configuration[:camel_case] ? value.camelize(:lower) : value
428
- end
429
-
430
- # This function serializes Journey route into JSON structure
431
- # We do not use Hash for human readable serialization
432
- # And preffer Array serialization because it is shorter.
433
- # Routes.js file will be smaller.
434
- def serialize(spec, parent_spec=nil)
435
- return nil unless spec
436
- # Rails 4 globbing requires * removal
437
- return spec.tr(':*', '') if spec.is_a?(String)
438
-
439
- result = serialize_spec(spec, parent_spec)
440
- if parent_spec && result[1].is_a?(String) && parent_spec.type != :SLASH
441
- result = [
442
- # We encode node symbols as integer
443
- # to reduce the routes.js file size
444
- NODE_TYPES[:CAT],
445
- serialize_spec(parent_spec),
446
- result
447
- ]
448
- end
449
- result
450
- end
451
-
452
- def serialize_spec(spec, parent_spec = nil)
453
- [
454
- NODE_TYPES[spec.type],
455
- serialize(spec.left, parent_spec),
456
- spec.respond_to?(:right) ? serialize(spec.right) : nil
457
- ].compact
458
- end
459
- end
460
298
  module Generators
461
299
  end
462
300
  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.0
4
+ version: 2.2.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: 2021-12-21 00:00:00.000000000 Z
11
+ date: 2022-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -174,6 +174,7 @@ files:
174
174
  - lib/js_routes/generators/middleware.rb
175
175
  - lib/js_routes/generators/webpacker.rb
176
176
  - lib/js_routes/middleware.rb
177
+ - lib/js_routes/route.rb
177
178
  - lib/js_routes/version.rb
178
179
  - lib/routes.d.ts
179
180
  - lib/routes.js