js-routes 1.4.14 → 2.0.0

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: 86ed2a6e4f90ea3c7bbc91836148b23121acbb21c59e4b26e55f0925a2d37fce
4
+ data.tar.gz: 485241d5aa3e009545a78113c49e2781be677cb4ddfe91286329f325f8a6b9dc
5
5
  SHA512:
6
- metadata.gz: 586fc3bcbef2fc96c12b0d53b5f9fd58eb19b8f5987ca7a6dac068ecc6865c363a4207e69afd4d0fe0c6d252d7b0c507428c7257a99cabf6fc34ba0c5afe29ea
7
- data.tar.gz: 10276a454e7f07fe6166957c18516214c34853859f4e8645e06105984e80fb18b77016cbc398a1cdd5351eba6f4d38ce78555f34498be04f35e353c341500c75
6
+ metadata.gz: 75844cdc35fc7cbf506fdd40eb00bc002c8bdc35397607943d28519572ae63f3f374cd249c4f50c218a979ffbbafe3938d5d2de0d1f03505e00549b9483a7ae6
7
+ data.tar.gz: ffb6920c23e81c18cc4c6e1476ae61f60801973e93583cd481ef6cd9f45171005de01124cc62aefc7862c2451cdbde31787efeeb8d2fb2e9dab223b1f5964230
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,16 @@
1
1
  ## master
2
2
 
3
+ ## v2.0.0
4
+
5
+ Version 2.0 has some breaking changes.
6
+ See [UPGRADE TO 2.0](./VERSION_2_UPGRADE.md) for guidance.
7
+
8
+ * `module_type` option support
9
+ * `documentation` option spport
10
+ * Migrated implementation to typescript
11
+ * ESM tree shaking support
12
+ * Support camel case `toParam` version of `to_param` property
13
+
3
14
  ## v1.4.14
4
15
 
5
16
  * 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
 
@@ -64,7 +73,7 @@ module.exports = {
64
73
 
65
74
  Enable `erb` extension in `config/webpacker/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)
@@ -175,27 +200,28 @@ If your application has an `admin` and an `application` namespace for example:
175
200
 
176
201
  ```
177
202
  # app/javascript/admin/routes.js.erb
178
- <%= JsRoutes.generate(namespace: "AdminRoutes", include: /admin/) %>
203
+ <%= JsRoutes.generate(include: /admin/) %>
179
204
  ```
180
205
 
181
206
  ```
182
207
  # app/javascript/customer/routes.js.erb
183
- <%= JsRoutes.generate(namespace: "CustomerRoutes", exclude: /admin/) %>
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