js-routes 2.2.0 → 2.2.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: 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