js-routes 2.0.5 → 2.1.0

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: 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