js-routes 1.4.14 → 2.0.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: f8a952ba9e2f582074e459b770227628ee2cecf37cd50d03978ba9690bac5a94
4
- data.tar.gz: 151da0e08b1b47fd6caa3bfbb1a5311ac0a528a9c88bb53b05dea181438823fb
3
+ metadata.gz: 52b735748b525770a79a5dcb0fe510b50350e3e22541fcb34f39fbc04b9a4f02
4
+ data.tar.gz: ca5ec3a0e5adcf943854681413dfc11f4da9cd91c46a3bb817ee85ea6da303a0
5
5
  SHA512:
6
- metadata.gz: 586fc3bcbef2fc96c12b0d53b5f9fd58eb19b8f5987ca7a6dac068ecc6865c363a4207e69afd4d0fe0c6d252d7b0c507428c7257a99cabf6fc34ba0c5afe29ea
7
- data.tar.gz: 10276a454e7f07fe6166957c18516214c34853859f4e8645e06105984e80fb18b77016cbc398a1cdd5351eba6f4d38ce78555f34498be04f35e353c341500c75
6
+ metadata.gz: 820f89d751dfb532235098abcaf5a26e568d5acd34ab469ccf8d61dfaa4427ac59e8597860ce9cd05728869c401d72e5beb6501aac2ee9713772091db80cc0d5
7
+ data.tar.gz: 0ba55b8c600a1ea89737a860b5ca728572972e149900c35fd39ac439dcae0f9af8541649f356c4341b4331a73ede9382ed20b9c75311cb24c27cb7eebd510c29
data/.eslintrc.js ADDED
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: [
4
+ 'eslint:recommended',
5
+ 'plugin:@typescript-eslint/eslint-recommended',
6
+ 'plugin:@typescript-eslint/recommended',
7
+ 'prettier/@typescript-eslint',
8
+ ],
9
+ parser: '@typescript-eslint/parser',
10
+ plugins: ['@typescript-eslint'],
11
+ rules: {
12
+ '@typescript-eslint/ban-types': 'off',
13
+ '@typescript-eslint/no-explicit-any': 'off'
14
+ },
15
+ };
data/.gitignore CHANGED
@@ -60,3 +60,5 @@ gemfiles/*.lock
60
60
  /spec/dummy/app/assets/javascripts/routes.js
61
61
  /spec/dummy/logs
62
62
  /spec/dummy/tmp
63
+ node_modules
64
+
data/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 14
data/.travis.yml CHANGED
@@ -5,7 +5,6 @@ before_install:
5
5
  - gem install bundler # need for jruby and ruby-head
6
6
 
7
7
  rvm:
8
- - 2.3.1
9
8
  - 2.4.1
10
9
  - 2.5.3
11
10
  - 2.6.0
@@ -22,6 +21,8 @@ gemfile:
22
21
  - gemfiles/rails50_sprockets_3.gemfile
23
22
  - gemfiles/rails51_sprockets_3.gemfile
24
23
  - gemfiles/rails52_sprockets_3.gemfile
24
+ env:
25
+ TRAVIS_CI: true
25
26
 
26
27
  sudo: false
27
28
  dist: xenial
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## master
2
2
 
3
+ ## v2.0.1
4
+
5
+ * Fixed backward compatibility issue [#272](https://github.com/railsware/js-routes/issues/272)
6
+
7
+ ## v2.0.0
8
+
9
+ Version 2.0 has some breaking changes.
10
+ See [UPGRADE TO 2.0](./VERSION_2_UPGRADE.md) for guidance.
11
+
12
+ * `module_type` option support
13
+ * `documentation` option spport
14
+ * Migrated implementation to typescript
15
+ * ESM tree shaking support
16
+ * Support camel case `toParam` version of `to_param` property
17
+
3
18
  ## v1.4.14
4
19
 
5
20
  * Fix compatibility with UMD modules #237 [Comment](https://github.com/railsware/js-routes/issues/237#issuecomment-752754679)
data/Readme.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  Generates javascript file that defines all Rails named routes as javascript helpers
6
6
 
7
+ [UPGRADE TO 2.0](./VERSION_2_UPGRADE.md)
8
+
7
9
  ## Intallation
8
10
 
9
11
  Your Rails Gemfile:
@@ -14,6 +16,8 @@ gem "js-routes"
14
16
 
15
17
  ## Setup
16
18
 
19
+ ### Quick Start
20
+
17
21
  Run:
18
22
 
19
23
  ```
@@ -23,19 +27,24 @@ rake js:routes
23
27
  Make routes available globally in `app/javascript/packs/application.js`:
24
28
 
25
29
  ``` javascript
26
- window.Routes = require('routes');
30
+ import * as Routes from 'routes';
31
+ window.Routes = Routes;
27
32
  ```
28
33
 
29
34
  Individual routes can be imported using:
30
35
 
31
36
  ``` javascript
32
- import {edit_post_path, new_post_path} from 'routes';
37
+ import {edit_post_path} from 'routes';
38
+ console.log(edit_post_path(1))
33
39
  ```
34
40
 
35
41
  **Note**: that this setup requires `rake js:routes` to be run each time routes file is updated.
36
42
 
43
+ <div id='webpacker'></div>
44
+
37
45
  #### Webpacker + automatic updates
38
46
 
47
+
39
48
  This setup can automatically update your routes without `rake js:routes` being called manually.
40
49
  It requires [rails-erb-loader](https://github.com/usabilityhub/rails-erb-loader) npm package to work.
41
50
 
@@ -62,9 +71,9 @@ module.exports = {
62
71
  }
63
72
  ```
64
73
 
65
- Enable `erb` extension in `config/webpacker/environment.js`:
74
+ Enable `erb` extension in `config/webpack/environment.js`:
66
75
 
67
- ```
76
+ ``` javascript
68
77
  const erb = require('./loaders/erb')
69
78
  environment.loaders.append('erb', erb)
70
79
  ```
@@ -78,13 +87,23 @@ Create routes file `app/javascript/routes.js.erb`:
78
87
  Use routes wherever you need them `app/javascript/packs/application.js`:
79
88
 
80
89
  ``` javascript
81
- window.Routes = require('routes.js.erb');
90
+ import * as Routes from 'routes.js.erb';
91
+ window.Routes = Routes;
82
92
  ```
83
93
 
84
94
  #### Sprockets (Deprecated)
85
95
 
86
96
  If you are using [Sprockets](https://github.com/rails/sprockets-rails) you may configure js-routes in the following way.
87
97
 
98
+ Setup the initializer (e.g. `config/initializers/js_routes.rb`):
99
+
100
+ ``` ruby
101
+ JsRoutes.setup do |config|
102
+ config.module_type = nil
103
+ config.namespace = 'Routes'
104
+ end
105
+ ```
106
+
88
107
  Require JsRoutes in `app/assets/javascripts/application.js` or other bundle
89
108
 
90
109
  ``` js
@@ -114,6 +133,7 @@ end
114
133
  Or dynamically in JavaScript, although only [Formatter Options](#formatter-options) are supported (see below)
115
134
 
116
135
  ``` js
136
+ import * as Routes from 'routes'
117
137
  Routes.configure({
118
138
  option: value
119
139
  });
@@ -126,6 +146,12 @@ Routes.config(); // current config
126
146
 
127
147
  Options to configure JavaScript file generator. These options are only available in Ruby context but not JavaScript.
128
148
 
149
+ * `module_type` - JavaScript module type for generated code. [Article](https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm)
150
+ * Options: `ESM`, `UMD`, `CJS`, `AMD`, `nil`.
151
+ * Default: `ESM`
152
+ * `nil` option can be used in case you don't want generated code to export anything.
153
+ * `documentation` - specifies if each route should be annotated with [JSDoc](https://jsdoc.app/) comment
154
+ * Default: `true`
129
155
  * `exclude` - Array of regexps to exclude from routes.
130
156
  * Default: `[]`
131
157
  * The regexp applies only to the name before the `_path` suffix, eg: you want to match exactly `settings_path`, the regexp should be `/^settings$/`
@@ -134,11 +160,10 @@ Options to configure JavaScript file generator. These options are only available
134
160
  * The regexp applies only to the name before the `_path` suffix, eg: you want to match exactly `settings_path`, the regexp should be `/^settings$/`
135
161
  * `namespace` - global object used to access routes.
136
162
  * Supports nested namespace like `MyProject.routes`
137
- * Default: `Routes`
138
- * `camel_case` - Generate camel case route names.
163
+ * Default: `nil`
164
+ * `camel_case` - specifies if route helpers should be generated in camel case instead of underscore case.
139
165
  * Default: `false`
140
- * `url_links` - Generate `*_url` helpers (in addition to the default `*_path` helpers).
141
- * Example: `true`
166
+ * `url_links` - specifies if `*_url` helpers should be generated (in addition to the default `*_path` helpers).
142
167
  * Default: `false`
143
168
  * Note: generated URLs will first use the protocol, host, and port options specified in the route definition. Otherwise, the URL will be based on the option specified in the `default_url_options` config. If no default option has been set, then the URL will fallback to the current URL based on `window.location`.
144
169
  * `compact` - Remove `_path` suffix in path routes(`*_url` routes stay untouched if they were enabled)
@@ -173,29 +198,30 @@ Options to configure routes formatting. These options are available both in Ruby
173
198
  In case you need multiple route files for different parts of your application, you have to create the files manually.
174
199
  If your application has an `admin` and an `application` namespace for example:
175
200
 
176
- ```
177
- # app/javascript/admin/routes.js.erb
178
- <%= JsRoutes.generate(namespace: "AdminRoutes", include: /admin/) %>
201
+ ``` erb
202
+ // app/javascript/admin/routes.js.erb
203
+ <%= JsRoutes.generate(include: /admin/) %>
179
204
  ```
180
205
 
181
- ```
182
- # app/javascript/customer/routes.js.erb
183
- <%= JsRoutes.generate(namespace: "CustomerRoutes", exclude: /admin/) %>
206
+ ``` erb
207
+ // app/javascript/customer/routes.js.erb
208
+ <%= JsRoutes.generate(exclude: /admin/) %>
184
209
  ```
185
210
 
186
- In order to generate the routes JS code to a string:
211
+ You can manipulate the generated helper manually by injecting ruby into javascript:
187
212
 
188
- ``` ruby
189
- routes_js = JsRoutes.generate(options)
213
+ ``` erb
214
+ export const routes = <%= JsRoutes.generate(module_type: nil, namespace: nil) %>
190
215
  ```
191
216
 
192
217
  If you want to generate the routes files outside of the asset pipeline, you can use `JsRoutes.generate!`:
193
218
 
194
219
  ``` ruby
195
- path = "app/javascript"
196
- JsRoutes.generate!("#{path}/app_routes.js", namespace: "AppRoutes", exclude: [/^admin_/, /^api_/])
197
- JsRoutes.generate!("#{path}/adm_routes.js", namespace: "AdmRoutes", include: /^admin_/)
198
- JsRoutes.generate!("#{path}/api_routes.js", namespace: "ApiRoutes", include: /^api_/, default_url_options: {format: "json"})
220
+ path = Rails.root.join("app/javascript")
221
+
222
+ JsRoutes.generate!("#{path}/app_routes.js", exclude: [/^admin_/, /^api_/])
223
+ JsRoutes.generate!("#{path}/adm_routes.js", include: /^admin_/)
224
+ JsRoutes.generate!("#{path}/api_routes.js", include: /^api_/, default_url_options: {format: "json"})
199
225
  ```
200
226
 
201
227
  ## Usage
@@ -203,6 +229,8 @@ JsRoutes.generate!("#{path}/api_routes.js", namespace: "ApiRoutes", include: /^a
203
229
  Configuration above will create a nice javascript file with `Routes` object that has all the rails routes available:
204
230
 
205
231
  ``` js
232
+ import * as Routes from 'routes';
233
+
206
234
  Routes.users_path() // => "/users"
207
235
  Routes.user_path(1) // => "/users/1"
208
236
  Routes.user_path(1, {format: 'json'}) // => "/users/1.json"
@@ -243,11 +271,11 @@ This function allow to get the same `spec` for route, if you will get string rep
243
271
  '' + Routes.user_path // => "/users/:id(.:format)"
244
272
  ```
245
273
 
246
- Route function also contain inside attribute `required_params` required param names as array:
274
+ Route function also contain method `requiredParams` inside which returns required param names array:
247
275
 
248
276
  ```js
249
- Routes.users_path.required_params // => []
250
- Routes.user_path.required_params // => ['id']
277
+ Routes.users_path.requiredParams() // => []
278
+ Routes.user_path.requiredParams() // => ['id']
251
279
  ```
252
280
 
253
281
 
@@ -268,9 +296,34 @@ Routes.company_project_path({company_id: 1, id: 2, _options: true}) // => "/comp
268
296
 
269
297
  ## What about security?
270
298
 
271
- JsRoutes itself does not have security holes. It makes URLs
272
- without access protection more reachable by potential attacker.
273
- In order to prevent this use `:exclude` option for sensitive urls like `/admin_/`
299
+ JsRoutes itself does not have security holes.
300
+ It makes URLs without access protection more reachable by potential attacker.
301
+ If that is an issue for you, you may use one of the following solutions:
302
+
303
+ ### Explicit Import + ESM Tree shaking
304
+
305
+ Make sure `module_type` is set to `ESM` (the default) and JS files import only required routes into the file like:
306
+
307
+ ``` javascript
308
+ import {
309
+ inbox_path,
310
+ inboxes_path,
311
+ inbox_message_path,
312
+ inbox_attachment_path,
313
+ user_path,
314
+ } from 'routes.js.erb'
315
+ ```
316
+
317
+ ### Exclude option
318
+
319
+ Split your routes into multiple files related to each section of your website like:
320
+
321
+ ``` javascript
322
+ // admin-routes.js.erb
323
+ <%= JsRoutes.generate(include: /^admin_/)
324
+ // app-routes.js.erb
325
+ <%= JsRoutes.generate(exclude: /^admin_/)
326
+ ```
274
327
 
275
328
  ## JsRoutes and Heroku
276
329
 
@@ -290,11 +343,20 @@ There are some alternatives available. Most of them has only basic feature and d
290
343
  Advantages of this one are:
291
344
 
292
345
  * Rails 4,5,6 support
346
+ * [ESM Tree shaking](https://webpack.js.org/guides/tree-shaking/) support
293
347
  * Rich options set
294
348
  * Full rails compatibility
295
349
  * Support Rails `#to_param` convention for seo optimized paths
296
350
  * Well tested
297
351
 
352
+ ## Version 2 TODO
353
+
354
+ * Add routes generation .d.ts file
355
+ * Add config option on the output format: js, ts, d.ts
356
+ * Add prettier
357
+ * Add eslint
358
+ * Add development guide
359
+
298
360
  #### Thanks to [contributors](https://github.com/railsware/js-routes/contributors)
299
361
 
300
362
  #### Have fun
@@ -0,0 +1,61 @@
1
+ ## Version 2.0 upgrade notes
2
+
3
+ ### Using ESM module by default
4
+
5
+ The default setting are now changed:
6
+
7
+ Setting | Old | New
8
+ --- | --- | ---
9
+ module\_type | nil | ESM
10
+ namespace | Routes | nil
11
+
12
+ This is more optimized setup for WebPacker. You can restore the old configuration like this:
13
+
14
+ ``` ruby
15
+ JsRoutes.setup do |config|
16
+ config.module_type = nil
17
+ config.namespace = 'Routes'
18
+ end
19
+ ```
20
+
21
+ However, [ESM+Webpacker](/Readme.md#webpacker) upgrade is recommended.
22
+
23
+ ### `required_params` renamed
24
+
25
+ In case you are using `required_params` property, it is now renamed and converted to a method:
26
+
27
+ ``` javascript
28
+ // Old style
29
+ Routes.post_path.required_params // => ['id']
30
+ // New style
31
+ Routes.post_path.requiredParams() // => ['id']
32
+ ```
33
+
34
+ ### ParameterMissing error rework
35
+
36
+ `ParameterMissing` is renamed to `ParametersMissing` error and now list all missing parameters instead of just first encountered in its message. Missing parameters are now available via `ParametersMissing#keys` property.
37
+
38
+ ``` javascript
39
+ try {
40
+ return Routes.inbox_path();
41
+ } catch(error) {
42
+ if (error.name === 'ParametersMissing') {
43
+ console.warn(`Missing route keys ${error.keys.join(', ')}. Ignoring.`);
44
+ return "#";
45
+ } else {
46
+ throw error;
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### JSDoc comment format
52
+
53
+ New version of js-routes generates function comment in the [JSDoc](https://jsdoc.app) format.
54
+ If you have any problems with that disable the annotation:
55
+
56
+ ``` ruby
57
+ JsRoutes.setup do |config|
58
+ config.documentation = false
59
+ end
60
+ ```
61
+
data/js-routes.gemspec CHANGED
@@ -7,13 +7,16 @@ Gem::Specification.new do |s|
7
7
  s.name = %q{js-routes}
8
8
  s.version = JsRoutes::VERSION
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ if s.respond_to? :required_rubygems_version=
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0")
12
+ end
11
13
  s.authors = ["Bogdan Gusiev"]
12
14
  s.description = %q{Generates javascript file that defines all Rails named routes as javascript helpers}
13
15
  s.email = %q{agresso@gmail.com}
14
16
  s.extra_rdoc_files = [
15
17
  "LICENSE.txt"
16
18
  ]
19
+ s.required_ruby_version = '>= 2.4.0'
17
20
  s.files = `git ls-files`.split("\n")
18
21
  s.homepage = %q{http://github.com/railsware/js-routes}
19
22
  s.licenses = ["MIT"]
@@ -24,13 +27,13 @@ Gem::Specification.new do |s|
24
27
  s.add_development_dependency(%q<sprockets-rails>)
25
28
  s.add_development_dependency(%q<rspec>, [">= 3.0.0"])
26
29
  s.add_development_dependency(%q<bundler>, [">= 1.1.0"])
27
- s.add_development_dependency(%q<coffee-script>, [">= 0"])
28
30
  s.add_development_dependency(%q<appraisal>, [">= 0.5.2"])
31
+ s.add_development_dependency(%q<bump>, [">= 0.10.0"])
29
32
  if defined?(JRUBY_VERSION)
30
33
  s.add_development_dependency(%q<therubyrhino>, [">= 2.0.4"])
31
34
  else
32
35
  s.add_development_dependency(%q<byebug>)
33
36
  s.add_development_dependency(%q<pry-byebug>)
34
- s.add_development_dependency(%q<mini_racer>, [">= 0.2.4"])
37
+ s.add_development_dependency(%q<mini_racer>, [">= 0.4.0"])
35
38
  end
36
39
  end
data/lib/js_routes.rb CHANGED
@@ -3,6 +3,7 @@ if defined?(::Rails) && defined?(::Sprockets::Railtie)
3
3
  require 'js_routes/engine'
4
4
  end
5
5
  require 'js_routes/version'
6
+ require 'active_support/core_ext/string/indent'
6
7
 
7
8
  class JsRoutes
8
9
 
@@ -19,7 +20,7 @@ class JsRoutes
19
20
  sprockets_dir = Rails.root.join('app','assets','javascripts')
20
21
  sprockets_file = sprockets_dir.join('routes.js')
21
22
  webpacker_file = webpacker_dir.join('routes.js')
22
- !Dir.exists?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
23
+ !Dir.exist?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
23
24
  end,
24
25
  prefix: -> { Rails.application.config.relative_url_root || "" },
25
26
  url_links: false,
@@ -28,7 +29,9 @@ class JsRoutes
28
29
  compact: false,
29
30
  serializer: nil,
30
31
  special_options_key: "_options",
31
- application: -> { Rails.application }
32
+ application: -> { Rails.application },
33
+ module_type: 'ESM',
34
+ documentation: true,
32
35
  } #:nodoc:
33
36
 
34
37
  NODE_TYPES = {
@@ -72,6 +75,10 @@ class JsRoutes
72
75
  def to_hash
73
76
  Hash[*members.zip(values).flatten(1)].symbolize_keys
74
77
  end
78
+
79
+ def esm?
80
+ self.module_type === 'ESM'
81
+ end
75
82
  end
76
83
 
77
84
  #
@@ -83,11 +90,6 @@ class JsRoutes
83
90
  configuration.tap(&block) if block
84
91
  end
85
92
 
86
- def options
87
- ActiveSupport::Deprecation.warn('JsRoutes.options method is deprecated use JsRoutes.configuration instead')
88
- configuration
89
- end
90
-
91
93
  def configuration
92
94
  @configuration ||= Configuration.new
93
95
  end
@@ -125,8 +127,7 @@ class JsRoutes
125
127
 
126
128
  {
127
129
  'GEM_VERSION' => JsRoutes::VERSION,
128
- 'ROUTES' => js_routes,
129
- 'NODE_TYPES' => json(NODE_TYPES),
130
+ 'ROUTES_OBJECT' => routes_object,
130
131
  'RAILS_VERSION' => ActionPack.version,
131
132
  'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
132
133
 
@@ -136,9 +137,12 @@ class JsRoutes
136
137
  'PREFIX' => json(@configuration.prefix),
137
138
  'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
138
139
  'SERIALIZER' => @configuration.serializer || json(nil),
140
+ 'MODULE_TYPE' => json(@configuration.module_type),
141
+ 'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
139
142
  }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)|
140
- js.gsub!(key, value.to_s)
141
- end
143
+ js.gsub!("RubyVariables.#{key}", value.to_s) ||
144
+ raise("Missing key #{key} in JS template")
145
+ end + routes_export
142
146
  end
143
147
 
144
148
  def generate!(file_name = nil)
@@ -170,19 +174,37 @@ class JsRoutes
170
174
  application.routes.named_routes.to_a
171
175
  end
172
176
 
173
- def js_routes
174
- js_routes = named_routes.sort_by(&:first).flat_map do |_, route|
175
- [build_route_if_match(route)] + mounted_app_routes(route)
177
+ def routes_object
178
+ return json({}) if @configuration.esm?
179
+ properties = routes_list.map do |comment, name, body|
180
+ "#{comment}#{name}: #{body}".indent(2)
181
+ end
182
+ "{\n" + properties.join(",\n\n") + "}\n"
183
+ end
184
+
185
+ STATIC_EXPORTS = [:configure, :config, :serialize].map do |name|
186
+ ["", name, "__jsr.#{name}"]
187
+ end
188
+
189
+ def routes_export
190
+ return "" unless @configuration.esm?
191
+ [*STATIC_EXPORTS, *routes_list].map do |comment, name, body|
192
+ "#{comment}export const #{name} = #{body};"
193
+ end.join("\n\n")
194
+ end
195
+
196
+ def routes_list
197
+ named_routes.sort_by(&:first).flat_map do |_, route|
198
+ build_routes_if_match(route) + mounted_app_routes(route)
176
199
  end.compact
177
- "{\n" + js_routes.join(",\n") + "}\n"
178
200
  end
179
201
 
180
202
  def mounted_app_routes(route)
181
203
  rails_engine_app = get_app_from_route(route)
182
204
  if rails_engine_app.respond_to?(:superclass) &&
183
205
  rails_engine_app.superclass == Rails::Engine && !route.path.anchored
184
- rails_engine_app.routes.named_routes.map do |_, engine_route|
185
- build_route_if_match(engine_route, route)
206
+ rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
207
+ build_routes_if_match(engine_route, route)
186
208
  end
187
209
  else
188
210
  []
@@ -199,12 +221,17 @@ class JsRoutes
199
221
  end
200
222
  end
201
223
 
202
- def build_route_if_match(route, parent_route = nil)
224
+ def build_routes_if_match(route, parent_route = nil)
203
225
  if any_match?(route, parent_route, @configuration[:exclude]) ||
204
226
  !any_match?(route, parent_route, @configuration[:include])
205
- nil
227
+ []
206
228
  else
207
- build_js(route, parent_route)
229
+ name = [parent_route.try(:name), route.name].compact
230
+ parent_spec = parent_route.try(:path).try(:spec)
231
+ route_arguments = route_js_arguments(route, parent_spec)
232
+ return [false, true].map do |absolute|
233
+ route_js(name, parent_spec, route, route_arguments, absolute)
234
+ end
208
235
  end
209
236
  end
210
237
 
@@ -215,59 +242,72 @@ class JsRoutes
215
242
  matchers.any? { |regex| full_route =~ regex }
216
243
  end
217
244
 
218
- def build_js(route, parent_route)
219
- name = [parent_route.try(:name), route.name].compact
220
- route_name = generate_route_name(name, (:path unless @configuration[:compact]))
221
- parent_spec = parent_route.try(:path).try(:spec)
222
- route_arguments = route_js_arguments(route, parent_spec)
223
- url_link = generate_url_link(name, route_arguments)
224
- <<-JS.strip!
225
- // #{name.join('.')} => #{parent_spec}#{route.path.spec}
226
- // function(#{build_params(route.required_parts)})
227
- #{route_name}: Utils.route(#{route_arguments})#{",\n" + url_link if url_link.length > 0}
228
- JS
245
+ def route_js(name_parts, parent_spec, route, route_arguments, absolute)
246
+ if absolute
247
+ return nil unless @configuration[:url_links]
248
+ route_arguments = route_arguments + [json(true)]
249
+ end
250
+ name_suffix = absolute ? :url : @configuration[:compact] ? nil : :path
251
+ name = generate_route_name(name_parts, name_suffix)
252
+ body = "__jsr.r(#{route_arguments.join(', ')})"
253
+ comment = documentation(route, parent_spec)
254
+ [ comment, name, body ]
255
+ end
256
+
257
+ def documentation(route, parent_spec)
258
+ return nil unless @configuration[:documentation]
259
+ <<-JS
260
+ /**
261
+ * Generates rails route to
262
+ * #{parent_spec}#{route.path.spec}#{build_params(route.required_parts)}
263
+ * @param {object | undefined} options
264
+ * @returns {string} route path
265
+ */
266
+ JS
229
267
  end
230
268
 
231
269
  def route_js_arguments(route, parent_spec)
232
270
  required_parts = route.required_parts
233
- parts_table = route.parts.each_with_object({}) do |part, hash|
234
- hash[part] = required_parts.include?(part)
271
+ parts_table = {}
272
+ route.parts.each do |part, hash|
273
+ parts_table[part] ||= {}
274
+ if required_parts.include?(part)
275
+ # Using shortened keys to reduce js file size
276
+ parts_table[part][:r] = true
277
+ end
235
278
  end
236
- default_options = route.defaults.select do |part, _|
237
- FILTERED_DEFAULT_PARTS.exclude?(part) &&
279
+ route.defaults.each do |part, value|
280
+ if FILTERED_DEFAULT_PARTS.exclude?(part) &&
238
281
  URL_OPTIONS.include?(part) || parts_table[part]
282
+ parts_table[part] ||= {}
283
+ # Using shortened keys to reduce js file size
284
+ parts_table[part][:d] = value
285
+ end
239
286
  end
240
287
  [
241
- # JS objects don't preserve the order of properties which is crucial,
242
- # so array is a better choice.
243
- parts_table.to_a,
244
- default_options,
288
+ parts_table,
245
289
  serialize(route.path.spec, parent_spec)
246
290
  ].map do |argument|
247
291
  json(argument)
248
- end.join(', ')
249
- end
250
-
251
- def generate_url_link(name, route_arguments)
252
- return '' unless @configuration[:url_links]
253
-
254
- <<-JS.strip!
255
- #{generate_route_name(name, :url)}: Utils.route(#{route_arguments}, true)
256
- JS
292
+ end
257
293
  end
258
294
 
259
295
  def generate_route_name(*parts)
260
- route_name = parts.compact.join('_')
261
- @configuration[:camel_case] ? route_name.camelize(:lower) : route_name
296
+ apply_case(parts.compact.join('_'))
262
297
  end
263
298
 
264
299
  def json(string)
265
300
  self.class.json(string)
266
301
  end
267
302
 
303
+ def apply_case(value)
304
+ @configuration[:camel_case] ? value.to_s.camelize(:lower) : value
305
+ end
306
+
268
307
  def build_params(required_parts)
269
- params = required_parts + [LAST_OPTIONS_KEY]
270
- params.join(', ')
308
+ required_parts.map do |param|
309
+ "\n * @param {any} #{apply_case(param)}"
310
+ end.join
271
311
  end
272
312
 
273
313
  # This function serializes Journey route into JSON structure
@@ -296,7 +336,7 @@ class JsRoutes
296
336
  [
297
337
  NODE_TYPES[spec.type],
298
338
  serialize(spec.left, parent_spec),
299
- spec.respond_to?(:right) && serialize(spec.right)
300
- ]
339
+ spec.respond_to?(:right) ? serialize(spec.right) : nil
340
+ ].compact
301
341
  end
302
342
  end