js-routes 2.0.5 → 2.1.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: c9a63dedd682c2cf4330ffc7c4ce012845e35fae3c315846a2ba5ef52b980ba2
4
- data.tar.gz: 5e62c6831d3799376fad6a8e6e433488c4674bc7d7ac4917fe9f9e0a0ca9f03d
3
+ metadata.gz: 242f329ab92abe8be4a2fa3790f72a3f161a6c2355b2392eae484a36a91d3a24
4
+ data.tar.gz: 120e5191eccfe3a8978c89ecb690a4f93a62279b249c58bc84b9273fe3e900c7
5
5
  SHA512:
6
- metadata.gz: 2ee773fcb0b7ea746248c06d6fac1365a23ab732ff16620d555bb4d035e9661187d02fb093a127a9d240e0621976cbc6680996c22e065bd70e7c8d2318e37753
7
- data.tar.gz: 5a7e0d7fc1b1af56c4ee72a3b8cdef0d6b42671425c35b60410ffe2b62e63779deeb733ca5293fc62507b224094686de436d763f7b49ffc29248b1fc2e653d71
6
+ metadata.gz: e1998fd3c98dff227905bfcd8a09be8bb6901d3da7293b60d1a6f11c3a2627c623372324a13010cbe425eb7b93781fa64db042c08e7b4123d4a50ec8bd8814b2
7
+ data.tar.gz: 5395c808f148bd39a99de0ce748cbb3a57c27620f048764bfcf6a455ac6ce2bbc43e282f4c660ba019f8d4b5df39a316728bb673d56b2667aecb667dde82d91b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## master
2
2
 
3
+ ## v2.1.0
4
+
5
+ * Support typescript defintions file aka `routes.d.ts`. See [Readme.md](./Readme.md#definitions) for more information.
6
+
7
+ ## v2.0.8
8
+
9
+ * Forbid usage of `namespace` option if `module_type` is not `nil`. [#281](https://github.com/railsware/js-routes/issues/281).
10
+
11
+ ## v2.0.7
12
+
13
+ * Remove source map annotation from JS file. Fixes [#277](https://github.com/railsware/js-routes/issues/277)
14
+ * Generated file is not minified, so it is better to use app side bundler/compressor for source maps
15
+
16
+
17
+ ## v2.0.6
18
+
19
+ * Disable `namespace` option default for all envs [#278](https://github.com/railsware/js-routes/issues/278)
20
+
3
21
  ## v2.0.5
4
22
 
5
23
  * Fixed backward compatibility issue [#276](https://github.com/railsware/js-routes/issues/276)
data/Readme.md CHANGED
@@ -20,22 +20,26 @@ gem "js-routes"
20
20
 
21
21
  Run:
22
22
 
23
- ```
23
+ ``` sh
24
24
  rake js:routes
25
+ # OR for typescript support
26
+ rake js:routes:typescript
25
27
  ```
26
28
 
27
- Make routes available globally in `app/javascript/packs/application.js`:
29
+
30
+ Individual routes can be imported using:
28
31
 
29
32
  ``` javascript
30
- import * as Routes from 'routes';
31
- window.Routes = Routes;
33
+ import {edit_post_path, posts_path} from 'routes';
34
+ console.log(posts_path({format: 'json'})) // => "/posts.json"
35
+ console.log(edit_post_path(1)) // => "/posts/1/edit"
32
36
  ```
33
37
 
34
- Individual routes can be imported using:
38
+ Make routes available globally in `app/javascript/packs/application.js`:
35
39
 
36
40
  ``` javascript
37
- import {edit_post_path} from 'routes';
38
- console.log(edit_post_path(1))
41
+ import * as Routes from 'routes';
42
+ window.Routes = Routes;
39
43
  ```
40
44
 
41
45
  **Note**: that this setup requires `rake js:routes` to be run each time routes file is updated.
@@ -91,6 +95,22 @@ import * as Routes from 'routes.js.erb';
91
95
  window.Routes = Routes;
92
96
  ```
93
97
 
98
+ <div id='definitions'></div>
99
+
100
+ #### Typescript Definitions
101
+
102
+ JsRoutes has typescript support out of the box. In order to generate typscript definitions file (aka `routes.d.ts`) you can call:
103
+
104
+ ``` ruby
105
+ JsRoutes.definitions!
106
+ ```
107
+
108
+ Or create an automatic updates file at `app/javascript/routes.d.ts.erb`:
109
+
110
+ ``` erb
111
+ <%= JsRoutes.defintions %>
112
+ ```
113
+
94
114
  #### Sprockets (Deprecated)
95
115
 
96
116
  If you are using [Sprockets](https://github.com/rails/sprockets-rails) you may configure js-routes in the following way.
@@ -147,7 +167,7 @@ Routes.config(); // current config
147
167
  Options to configure JavaScript file generator. These options are only available in Ruby context but not JavaScript.
148
168
 
149
169
  * `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`.
170
+ * Options: `ESM`, `UMD`, `CJS`, `AMD`, `DTS`, `nil`.
151
171
  * Default: `ESM`
152
172
  * `nil` option can be used in case you don't want generated code to export anything.
153
173
  * `documentation` - specifies if each route should be annotated with [JSDoc](https://jsdoc.app/) comment
@@ -159,6 +179,7 @@ Options to configure JavaScript file generator. These options are only available
159
179
  * Default: `[]`
160
180
  * The regexp applies only to the name before the `_path` suffix, eg: you want to match exactly `settings_path`, the regexp should be `/^settings$/`
161
181
  * `namespace` - global object used to access routes.
182
+ * Only available if `module_type` option is set to `nil`.
162
183
  * Supports nested namespace like `MyProject.routes`
163
184
  * Default: `nil`
164
185
  * `camel_case` - specifies if route helpers should be generated in camel case instead of underscore case.
@@ -314,29 +335,20 @@ import {
314
335
  } from 'routes.js.erb'
315
336
  ```
316
337
 
338
+ Such import structure allows for moddern JS bundlers like [Webpack](https://webpack.js.org/) to only include explicitly imported routes into JS bundle file.
339
+ See [Tree Shaking](https://webpack.js.org/guides/tree-shaking/) for more information.
340
+
317
341
  ### Exclude option
318
342
 
319
343
  Split your routes into multiple files related to each section of your website like:
320
344
 
321
345
  ``` javascript
322
346
  // admin-routes.js.erb
323
- <%= JsRoutes.generate(include: /^admin_/)
347
+ <%= JsRoutes.generate(include: /^admin_/) %>
324
348
  // app-routes.js.erb
325
- <%= JsRoutes.generate(exclude: /^admin_/)
349
+ <%= JsRoutes.generate(exclude: /^admin_/) %>
326
350
  ```
327
351
 
328
- ## JsRoutes and Heroku
329
-
330
- When using this setup on Heroku, it is impossible to use the asset pipeline. You should use the "Very Advanced Setup" schema in this case.
331
-
332
- For example create routes.js.erb in assets folder with needed content:
333
-
334
- ``` erb
335
- <%= JsRoutes.generate(options) %>
336
- ```
337
-
338
- This should just work.
339
-
340
352
  ## Advantages over alternatives
341
353
 
342
354
  There are some alternatives available. Most of them has only basic feature and don't reach the level of quality I accept.
data/VERSION_2_UPGRADE.md CHANGED
@@ -2,23 +2,40 @@
2
2
 
3
3
  ### Using ESM module by default
4
4
 
5
- The default setting are now changed:
5
+ New version of JsRoutes doesn't try to guess your javascript environment module system because JS has generated a ton of legacy module systems in the past.
6
+ [ESM+Webpacker](/Readme.md#webpacker) upgrade is recommended.
6
7
 
7
- Setting | Old | New
8
- --- | --- | ---
9
- module\_type | nil | ESM
10
- namespace | Routes | nil
8
+ However, if you don't want to follow that pass, specify `module_type` configuration option instead based on module system available in your JS environment.
9
+ Here are supported values:
11
10
 
12
- This is more optimized setup for WebPacker. You can restore the old configuration like this:
11
+ * CJS
12
+ * UMD
13
+ * AMD
14
+ * ESM
15
+ * nil
16
+
17
+ [Explaination Article](https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm)
18
+
19
+ If you don't want to use any JS module system and make routes available via a **global variable**, specify `nil` as a `module_type` and use `namespace` option:
13
20
 
14
21
  ``` ruby
15
22
  JsRoutes.setup do |config|
16
23
  config.module_type = nil
17
- config.namespace = 'Routes'
24
+ config.namespace = "Routes"
18
25
  end
19
26
  ```
20
27
 
21
- However, [ESM+Webpacker](/Readme.md#webpacker) upgrade is recommended.
28
+ ### JSDoc comment
29
+
30
+ New version of js-routes generates function comment in the [JSDoc](https://jsdoc.app) format.
31
+ If you have any problems with that, you can disable it like this:
32
+
33
+
34
+ ``` ruby
35
+ JsRoutes.setup do |config|
36
+ config.documentation = false
37
+ end
38
+ ```
22
39
 
23
40
  ### `required_params` renamed
24
41
 
@@ -47,15 +64,3 @@ try {
47
64
  }
48
65
  }
49
66
  ```
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
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
 
26
26
  s.add_runtime_dependency(%q<railties>, [">= 4"])
27
27
  s.add_development_dependency(%q<sprockets-rails>)
28
- s.add_development_dependency(%q<rspec>, [">= 3.0.0"])
28
+ s.add_development_dependency(%q<rspec>, [">= 3.10.0"])
29
29
  s.add_development_dependency(%q<bundler>, [">= 1.1.0"])
30
30
  s.add_development_dependency(%q<appraisal>, [">= 0.5.2"])
31
31
  s.add_development_dependency(%q<bump>, [">= 0.10.0"])
@@ -1,3 +1,3 @@
1
1
  class JsRoutes
2
- VERSION = "2.0.5"
2
+ VERSION = "2.1.0"
3
3
  end
data/lib/js_routes.rb CHANGED
@@ -7,48 +7,26 @@ require 'active_support/core_ext/string/indent'
7
7
 
8
8
  class JsRoutes
9
9
 
10
- #
11
- # OPTIONS
12
- #
10
+ class Configuration
11
+ DEFAULTS = {
12
+ namespace: nil,
13
+ exclude: [],
14
+ include: //,
15
+ file: nil,
16
+ prefix: -> { Rails.application.config.relative_url_root || "" },
17
+ url_links: false,
18
+ camel_case: false,
19
+ default_url_options: {},
20
+ compact: false,
21
+ serializer: nil,
22
+ special_options_key: "_options",
23
+ application: -> { Rails.application },
24
+ module_type: 'ESM',
25
+ documentation: true,
26
+ } #:nodoc:
27
+
28
+ attr_accessor(*DEFAULTS.keys)
13
29
 
14
- DEFAULTS = {
15
- namespace: -> { defined?(Webpacker) ? nil : "Routes" },
16
- exclude: [],
17
- include: //,
18
- file: -> do
19
- webpacker_dir = Rails.root.join('app', 'javascript')
20
- sprockets_dir = Rails.root.join('app','assets','javascripts')
21
- sprockets_file = sprockets_dir.join('routes.js')
22
- webpacker_file = webpacker_dir.join('routes.js')
23
- !Dir.exist?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
24
- end,
25
- prefix: -> { Rails.application.config.relative_url_root || "" },
26
- url_links: false,
27
- camel_case: false,
28
- default_url_options: {},
29
- compact: false,
30
- serializer: nil,
31
- special_options_key: "_options",
32
- application: -> { Rails.application },
33
- module_type: 'ESM',
34
- documentation: true,
35
- } #:nodoc:
36
-
37
- NODE_TYPES = {
38
- GROUP: 1,
39
- CAT: 2,
40
- SYMBOL: 3,
41
- OR: 4,
42
- STAR: 5,
43
- LITERAL: 6,
44
- SLASH: 7,
45
- DOT: 8
46
- } #:nodoc:
47
-
48
- FILTERED_DEFAULT_PARTS = [:controller, :action] #:nodoc:
49
- URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain] #:nodoc:
50
-
51
- class Configuration < Struct.new(*DEFAULTS.keys)
52
30
  def initialize(attributes = nil)
53
31
  assign(DEFAULTS)
54
32
  return unless attributes
@@ -60,6 +38,7 @@ class JsRoutes
60
38
  value = value.call if value.is_a?(Proc)
61
39
  send(:"#{attribute}=", value)
62
40
  end
41
+ normalize_and_verify
63
42
  self
64
43
  end
65
44
 
@@ -76,7 +55,49 @@ class JsRoutes
76
55
  end
77
56
 
78
57
  def esm?
79
- self.module_type === 'ESM'
58
+ module_type === 'ESM'
59
+ end
60
+
61
+ def dts?
62
+ self.module_type === 'DTS'
63
+ end
64
+
65
+ def modern?
66
+ esm? || dts?
67
+ end
68
+
69
+ def source_file
70
+ File.dirname(__FILE__) + "/" + default_file_name
71
+ end
72
+
73
+ def output_file
74
+ webpacker_dir = Rails.root.join('app', 'javascript')
75
+ sprockets_dir = Rails.root.join('app','assets','javascripts')
76
+ file_name = file || default_file_name
77
+ sprockets_file = sprockets_dir.join(file_name)
78
+ webpacker_file = webpacker_dir.join(file_name)
79
+ !Dir.exist?(webpacker_dir) && defined?(::Sprockets) ? sprockets_file : webpacker_file
80
+ end
81
+
82
+ def normalize_and_verify
83
+ normalize
84
+ verify
85
+ end
86
+
87
+ protected
88
+
89
+ def default_file_name
90
+ dts? ? "routes.d.ts" : "routes.js"
91
+ end
92
+
93
+ def normalize
94
+ self.module_type = module_type&.upcase || 'NIL'
95
+ end
96
+
97
+ def verify
98
+ if module_type != 'NIL' && namespace
99
+ raise "JsRoutes namespace option can only be used if module_type is nil"
100
+ end
80
101
  end
81
102
  end
82
103
 
@@ -87,6 +108,7 @@ class JsRoutes
87
108
  class << self
88
109
  def setup(&block)
89
110
  configuration.tap(&block) if block
111
+ configuration.normalize_and_verify
90
112
  end
91
113
 
92
114
  def configuration
@@ -97,12 +119,13 @@ class JsRoutes
97
119
  new(opts).generate
98
120
  end
99
121
 
100
- def generate!(file_name=nil, opts = {})
101
- if file_name.is_a?(Hash)
102
- opts = file_name
103
- file_name = opts[:file]
104
- end
105
- new(opts).generate!(file_name)
122
+ def generate!(file_name=nil, **opts)
123
+ new(file: file_name, **opts).generate!
124
+ end
125
+
126
+ def definitions!(file_name = nil, **opts)
127
+ file_name ||= configuration.file&.sub!(%r{\.(j|t)s\Z}, ".d.ts")
128
+ new(file: file_name, module_type: 'DTS', **opts).generate!
106
129
  end
107
130
 
108
131
  def json(string)
@@ -123,48 +146,55 @@ class JsRoutes
123
146
  if named_routes.to_a.empty? && application.respond_to?(:reload_routes!)
124
147
  application.reload_routes!
125
148
  end
149
+ content = File.read(@configuration.source_file)
126
150
 
127
- {
128
- 'GEM_VERSION' => JsRoutes::VERSION,
129
- 'ROUTES_OBJECT' => routes_object,
130
- 'RAILS_VERSION' => ActionPack.version,
131
- 'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
132
-
133
- 'APP_CLASS' => application.class.to_s,
134
- 'NAMESPACE' => json(@configuration.namespace),
135
- 'DEFAULT_URL_OPTIONS' => json(@configuration.default_url_options),
136
- 'PREFIX' => json(@configuration.prefix),
137
- 'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
138
- 'SERIALIZER' => @configuration.serializer || json(nil),
139
- 'MODULE_TYPE' => json(@configuration.module_type),
140
- 'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
141
- }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)|
142
- js.gsub!("RubyVariables.#{key}", value.to_s) ||
151
+ if !@configuration.dts?
152
+ content = js_variables.inject(content) do |js, (key, value)|
153
+ js.gsub!("RubyVariables.#{key}", value.to_s) ||
143
154
  raise("Missing key #{key} in JS template")
144
- end + routes_export
155
+ end
156
+ end
157
+ content + routes_export + prevent_types_export
145
158
  end
146
159
 
147
- def generate!(file_name = nil)
148
- # Some libraries like Devise do not yet loaded their routes so we will wait
149
- # until initialization process finish
160
+ def generate!
161
+ # Some libraries like Devise did not load their routes yet
162
+ # so we will wait until initialization process finishes
150
163
  # https://github.com/railsware/js-routes/issues/7
151
164
  Rails.configuration.after_initialize do
152
- file_name ||= self.class.configuration['file']
153
- file_path = Rails.root.join(file_name)
154
- js_content = generate
165
+ file_path = Rails.root.join(@configuration.output_file)
166
+ source_code = generate
155
167
 
156
168
  # We don't need to rewrite file if it already exist and have same content.
157
169
  # It helps asset pipeline or webpack understand that file wasn't changed.
158
- next if File.exist?(file_path) && File.read(file_path) == js_content
170
+ next if File.exist?(file_path) && File.read(file_path) == source_code
159
171
 
160
172
  File.open(file_path, 'w') do |f|
161
- f.write js_content
173
+ f.write source_code
162
174
  end
163
175
  end
164
176
  end
165
177
 
166
178
  protected
167
179
 
180
+ def js_variables
181
+ {
182
+ 'GEM_VERSION' => JsRoutes::VERSION,
183
+ 'ROUTES_OBJECT' => routes_object,
184
+ 'RAILS_VERSION' => ActionPack.version,
185
+ 'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
186
+
187
+ 'APP_CLASS' => application.class.to_s,
188
+ 'NAMESPACE' => json(@configuration.namespace),
189
+ 'DEFAULT_URL_OPTIONS' => json(@configuration.default_url_options),
190
+ 'PREFIX' => json(@configuration.prefix),
191
+ 'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
192
+ 'SERIALIZER' => @configuration.serializer || json(nil),
193
+ 'MODULE_TYPE' => json(@configuration.module_type),
194
+ 'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
195
+ }
196
+ end
197
+
168
198
  def application
169
199
  @configuration.application
170
200
  end
@@ -178,32 +208,52 @@ class JsRoutes
178
208
  end
179
209
 
180
210
  def routes_object
181
- return json({}) if @configuration.esm?
211
+ return json({}) if @configuration.modern?
182
212
  properties = routes_list.map do |comment, name, body|
183
213
  "#{comment}#{name}: #{body}".indent(2)
184
214
  end
185
215
  "{\n" + properties.join(",\n\n") + "}\n"
186
216
  end
187
217
 
188
- STATIC_EXPORTS = [:configure, :config, :serialize].map do |name|
189
- ["", name, "__jsr.#{name}"]
218
+ def static_exports
219
+ [:configure, :config, :serialize].map do |name|
220
+ [
221
+ "", name,
222
+ @configuration.dts? ?
223
+ "RouterExposedMethods['#{name}']" :
224
+ "__jsr.#{name}"
225
+ ]
226
+ end
190
227
  end
191
228
 
192
229
  def routes_export
193
- return "" unless @configuration.esm?
194
- [*STATIC_EXPORTS, *routes_list].map do |comment, name, body|
195
- "#{comment}export const #{name} = #{body};"
196
- end.join("\n\n")
230
+ return "" unless @configuration.modern?
231
+ [*static_exports, *routes_list].map do |comment, name, body|
232
+ "#{comment}export const #{name}#{export_separator}#{body};\n\n"
233
+ end.join
234
+ end
235
+
236
+ def prevent_types_export
237
+ return "" unless @configuration.dts?
238
+ <<-JS
239
+ // By some reason this line prevents all types in a file
240
+ // from being automatically exported
241
+ export {};
242
+ JS
243
+ end
244
+
245
+ def export_separator
246
+ @configuration.dts? ? ': ' : ' = '
197
247
  end
198
248
 
199
249
  def routes_list
200
250
  named_routes.sort_by(&:first).flat_map do |_, route|
201
251
  route_helpers_if_match(route) + mounted_app_routes(route)
202
- end.compact
252
+ end
203
253
  end
204
254
 
205
255
  def mounted_app_routes(route)
206
- rails_engine_app = get_app_from_route(route)
256
+ rails_engine_app = app_from_route(route)
207
257
  if rails_engine_app.respond_to?(:superclass) &&
208
258
  rails_engine_app.superclass == Rails::Engine && !route.path.anchored
209
259
  rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
@@ -214,7 +264,7 @@ class JsRoutes
214
264
  end
215
265
  end
216
266
 
217
- def get_app_from_route(route)
267
+ def app_from_route(route)
218
268
  # rails engine in Rails 4.2 use additional
219
269
  # ActionDispatch::Routing::Mapper::Constraints, which contain app
220
270
  if route.app.respond_to?(:app) && route.app.respond_to?(:constraints)
@@ -229,6 +279,19 @@ class JsRoutes
229
279
  end
230
280
 
231
281
  class JsRoute #:nodoc:
282
+ FILTERED_DEFAULT_PARTS = [:controller, :action]
283
+ URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
284
+ NODE_TYPES = {
285
+ GROUP: 1,
286
+ CAT: 2,
287
+ SYMBOL: 3,
288
+ OR: 4,
289
+ STAR: 5,
290
+ LITERAL: 6,
291
+ SLASH: 7,
292
+ DOT: 8
293
+ }
294
+
232
295
  attr_reader :configuration, :route, :parent_route
233
296
 
234
297
  def initialize(configuration, route, parent_route = nil)
@@ -238,22 +301,36 @@ class JsRoutes
238
301
  end
239
302
 
240
303
  def helpers
241
- unless match_configuration?
242
- []
243
- else
244
- [false, true].map do |absolute|
245
- absolute && !@configuration[:url_links] ?
246
- nil : [ documentation, helper_name(absolute), body(absolute) ]
247
- end
304
+ helper_types.map do |absolute|
305
+ [ documentation, helper_name(absolute), body(absolute) ]
248
306
  end
249
307
  end
250
308
 
309
+ def helper_types
310
+ return [] unless match_configuration?
311
+ @configuration[:url_links] ? [true, false] : [false]
312
+ end
313
+
251
314
  def body(absolute)
252
- "__jsr.r(#{arguments(absolute).join(', ')})"
315
+ @configuration.dts? ?
316
+ definition_body : "__jsr.r(#{arguments(absolute).map{|a| json(a)}.join(', ')})"
317
+ end
318
+
319
+ def definition_body
320
+ args = required_parts.map{|p| "#{apply_case(p)}: RequiredRouteParameter"}
321
+ args << "options?: #{optional_parts_type} & RouteOptions"
322
+ "((\n#{args.join(",\n").indent(2)}\n) => string) & RouteHelperExtras"
323
+ end
324
+
325
+ def optional_parts_type
326
+ @optional_parts_type ||=
327
+ "{" + optional_parts.map {|p| "#{p}?: OptionalRouteParameter"}.join(', ') + "}"
253
328
  end
254
329
 
330
+ protected
331
+
255
332
  def arguments(absolute)
256
- absolute ? base_arguments + [json(true)] : base_arguments
333
+ absolute ? [*base_arguments, true] : base_arguments
257
334
  end
258
335
 
259
336
  def match_configuration?
@@ -298,10 +375,15 @@ JS
298
375
  route.required_parts
299
376
  end
300
377
 
301
- protected
378
+ def optional_parts
379
+ route.path.optional_names
380
+ end
302
381
 
303
382
  def base_arguments
304
- return @base_arguments if defined?(@base_arguments)
383
+ @base_arguments ||= [parts_table, serialize(spec, parent_spec)]
384
+ end
385
+
386
+ def parts_table
305
387
  parts_table = {}
306
388
  route.parts.each do |part, hash|
307
389
  parts_table[part] ||= {}
@@ -318,11 +400,7 @@ JS
318
400
  parts_table[part][:d] = value
319
401
  end
320
402
  end
321
- @base_arguments = [
322
- parts_table, serialize(spec, parent_spec)
323
- ].map do |argument|
324
- json(argument)
325
- end
403
+ parts_table
326
404
  end
327
405
 
328
406
  def documentation_params