js-routes 1.4.9 → 2.0.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 +4 -4
- data/.eslintrc.js +15 -0
- data/.gitignore +4 -0
- data/.nvmrc +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +29 -0
- data/Readme.md +189 -65
- data/VERSION_2_UPGRADE.md +61 -0
- data/js-routes.gemspec +7 -4
- data/lib/js_routes.rb +109 -63
- data/lib/js_routes/engine.rb +0 -1
- data/lib/js_routes/version.rb +1 -1
- data/lib/routes.d.ts +64 -0
- data/lib/routes.js +479 -518
- data/lib/routes.js.map +1 -0
- data/lib/routes.ts +680 -0
- data/package.json +36 -0
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/js_routes/default_serializer_spec.rb +8 -3
- data/spec/js_routes/{amd_compatibility_spec.rb → module_types/amd_spec.rb} +1 -9
- data/spec/js_routes/module_types/cjs_spec.rb +15 -0
- data/spec/js_routes/module_types/esm_spec.rb +45 -0
- data/spec/js_routes/{generated_javascript_spec.rb → module_types/umd_spec.rb} +32 -26
- data/spec/js_routes/options_spec.rb +19 -6
- data/spec/js_routes/rails_routes_compatibility_spec.rb +40 -21
- data/spec/js_routes/zzz_last_post_rails_init_spec.rb +2 -2
- data/spec/spec_helper.rb +25 -17
- data/tsconfig.json +32 -0
- data/yarn.lock +2145 -0
- metadata +30 -20
- data/lib/routes.js.coffee +0 -411
@@ -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
|
-
|
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"]
|
@@ -21,16 +24,16 @@ Gem::Specification.new do |s|
|
|
21
24
|
s.summary = %q{Brings Rails named routes to javascript}
|
22
25
|
|
23
26
|
s.add_runtime_dependency(%q<railties>, [">= 4"])
|
24
|
-
s.
|
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.
|
37
|
+
s.add_development_dependency(%q<mini_racer>, [">= 0.4.0"])
|
35
38
|
end
|
36
39
|
end
|
data/lib/js_routes.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'uri'
|
2
|
-
|
2
|
+
if defined?(::Rails) && defined?(::Sprockets::Railtie)
|
3
|
+
require 'js_routes/engine'
|
4
|
+
end
|
3
5
|
require 'js_routes/version'
|
6
|
+
require 'active_support/core_ext/string/indent'
|
4
7
|
|
5
8
|
class JsRoutes
|
6
9
|
|
@@ -8,13 +11,17 @@ class JsRoutes
|
|
8
11
|
# OPTIONS
|
9
12
|
#
|
10
13
|
|
11
|
-
DEFAULT_PATH = File.join('app','assets','javascripts','routes.js')
|
12
|
-
|
13
14
|
DEFAULTS = {
|
14
|
-
namespace: "Routes",
|
15
|
+
namespace: -> { defined?(Webpacker) ? nil : "Routes" },
|
15
16
|
exclude: [],
|
16
17
|
include: //,
|
17
|
-
file:
|
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,
|
18
25
|
prefix: -> { Rails.application.config.relative_url_root || "" },
|
19
26
|
url_links: false,
|
20
27
|
camel_case: false,
|
@@ -22,8 +29,10 @@ class JsRoutes
|
|
22
29
|
compact: false,
|
23
30
|
serializer: nil,
|
24
31
|
special_options_key: "_options",
|
25
|
-
application: -> { Rails.application }
|
26
|
-
|
32
|
+
application: -> { Rails.application },
|
33
|
+
module_type: 'ESM',
|
34
|
+
documentation: true,
|
35
|
+
} #:nodoc:
|
27
36
|
|
28
37
|
NODE_TYPES = {
|
29
38
|
GROUP: 1,
|
@@ -34,11 +43,11 @@ class JsRoutes
|
|
34
43
|
LITERAL: 6,
|
35
44
|
SLASH: 7,
|
36
45
|
DOT: 8
|
37
|
-
}
|
46
|
+
} #:nodoc:
|
38
47
|
|
39
|
-
LAST_OPTIONS_KEY = "options".freeze
|
40
|
-
FILTERED_DEFAULT_PARTS = [:controller, :action]
|
41
|
-
URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain]
|
48
|
+
LAST_OPTIONS_KEY = "options".freeze #:nodoc:
|
49
|
+
FILTERED_DEFAULT_PARTS = [:controller, :action] #:nodoc:
|
50
|
+
URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain] #:nodoc:
|
42
51
|
|
43
52
|
class Configuration < Struct.new(*DEFAULTS.keys)
|
44
53
|
def initialize(attributes = nil)
|
@@ -66,6 +75,10 @@ class JsRoutes
|
|
66
75
|
def to_hash
|
67
76
|
Hash[*members.zip(values).flatten(1)].symbolize_keys
|
68
77
|
end
|
78
|
+
|
79
|
+
def esm?
|
80
|
+
self.module_type === 'ESM'
|
81
|
+
end
|
69
82
|
end
|
70
83
|
|
71
84
|
#
|
@@ -77,11 +90,6 @@ class JsRoutes
|
|
77
90
|
configuration.tap(&block) if block
|
78
91
|
end
|
79
92
|
|
80
|
-
def options
|
81
|
-
ActiveSupport::Deprecation.warn('JsRoutes.options method is deprecated use JsRoutes.configuration instead')
|
82
|
-
configuration
|
83
|
-
end
|
84
|
-
|
85
93
|
def configuration
|
86
94
|
@configuration ||= Configuration.new
|
87
95
|
end
|
@@ -119,8 +127,7 @@ class JsRoutes
|
|
119
127
|
|
120
128
|
{
|
121
129
|
'GEM_VERSION' => JsRoutes::VERSION,
|
122
|
-
'
|
123
|
-
'NODE_TYPES' => json(NODE_TYPES),
|
130
|
+
'ROUTES_OBJECT' => routes_object,
|
124
131
|
'RAILS_VERSION' => ActionPack.version,
|
125
132
|
'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
|
126
133
|
|
@@ -130,9 +137,12 @@ class JsRoutes
|
|
130
137
|
'PREFIX' => json(@configuration.prefix),
|
131
138
|
'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
|
132
139
|
'SERIALIZER' => @configuration.serializer || json(nil),
|
140
|
+
'MODULE_TYPE' => json(@configuration.module_type),
|
141
|
+
'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
|
133
142
|
}.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)|
|
134
|
-
js.gsub!(key, value.to_s)
|
135
|
-
|
143
|
+
js.gsub!("RubyVariables.#{key}", value.to_s) ||
|
144
|
+
raise("Missing key #{key} in JS template")
|
145
|
+
end + routes_export
|
136
146
|
end
|
137
147
|
|
138
148
|
def generate!(file_name = nil)
|
@@ -164,19 +174,37 @@ class JsRoutes
|
|
164
174
|
application.routes.named_routes.to_a
|
165
175
|
end
|
166
176
|
|
167
|
-
def
|
168
|
-
|
169
|
-
|
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)
|
170
199
|
end.compact
|
171
|
-
"{\n" + js_routes.join(",\n") + "}\n"
|
172
200
|
end
|
173
201
|
|
174
202
|
def mounted_app_routes(route)
|
175
203
|
rails_engine_app = get_app_from_route(route)
|
176
204
|
if rails_engine_app.respond_to?(:superclass) &&
|
177
205
|
rails_engine_app.superclass == Rails::Engine && !route.path.anchored
|
178
|
-
rails_engine_app.routes.named_routes.
|
179
|
-
|
206
|
+
rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
|
207
|
+
build_routes_if_match(engine_route, route)
|
180
208
|
end
|
181
209
|
else
|
182
210
|
[]
|
@@ -193,12 +221,17 @@ class JsRoutes
|
|
193
221
|
end
|
194
222
|
end
|
195
223
|
|
196
|
-
def
|
224
|
+
def build_routes_if_match(route, parent_route = nil)
|
197
225
|
if any_match?(route, parent_route, @configuration[:exclude]) ||
|
198
226
|
!any_match?(route, parent_route, @configuration[:include])
|
199
|
-
|
227
|
+
[]
|
200
228
|
else
|
201
|
-
|
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
|
202
235
|
end
|
203
236
|
end
|
204
237
|
|
@@ -209,59 +242,72 @@ class JsRoutes
|
|
209
242
|
matchers.any? { |regex| full_route =~ regex }
|
210
243
|
end
|
211
244
|
|
212
|
-
def
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
223
267
|
end
|
224
268
|
|
225
269
|
def route_js_arguments(route, parent_spec)
|
226
270
|
required_parts = route.required_parts
|
227
|
-
parts_table =
|
228
|
-
|
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
|
229
278
|
end
|
230
|
-
|
231
|
-
FILTERED_DEFAULT_PARTS.exclude?(part) &&
|
279
|
+
route.defaults.each do |part, value|
|
280
|
+
if FILTERED_DEFAULT_PARTS.exclude?(part) &&
|
232
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
|
233
286
|
end
|
234
287
|
[
|
235
|
-
|
236
|
-
# so array is a better choice.
|
237
|
-
parts_table.to_a,
|
238
|
-
default_options,
|
288
|
+
parts_table,
|
239
289
|
serialize(route.path.spec, parent_spec)
|
240
290
|
].map do |argument|
|
241
291
|
json(argument)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def generate_url_link(name, route_arguments)
|
246
|
-
return '' unless @configuration[:url_links]
|
247
|
-
|
248
|
-
<<-JS.strip!
|
249
|
-
#{generate_route_name(name, :url)}: Utils.route(#{route_arguments}, true)
|
250
|
-
JS
|
292
|
+
end
|
251
293
|
end
|
252
294
|
|
253
295
|
def generate_route_name(*parts)
|
254
|
-
|
255
|
-
@configuration[:camel_case] ? route_name.camelize(:lower) : route_name
|
296
|
+
apply_case(parts.compact.join('_'))
|
256
297
|
end
|
257
298
|
|
258
299
|
def json(string)
|
259
300
|
self.class.json(string)
|
260
301
|
end
|
261
302
|
|
303
|
+
def apply_case(value)
|
304
|
+
@configuration[:camel_case] ? value.to_s.camelize(:lower) : value
|
305
|
+
end
|
306
|
+
|
262
307
|
def build_params(required_parts)
|
263
|
-
|
264
|
-
|
308
|
+
required_parts.map do |param|
|
309
|
+
"\n * @param {any} #{apply_case(param)}"
|
310
|
+
end.join
|
265
311
|
end
|
266
312
|
|
267
313
|
# This function serializes Journey route into JSON structure
|
@@ -290,7 +336,7 @@ class JsRoutes
|
|
290
336
|
[
|
291
337
|
NODE_TYPES[spec.type],
|
292
338
|
serialize(spec.left, parent_spec),
|
293
|
-
spec.respond_to?(:right)
|
294
|
-
]
|
339
|
+
spec.respond_to?(:right) ? serialize(spec.right) : nil
|
340
|
+
].compact
|
295
341
|
end
|
296
342
|
end
|
data/lib/js_routes/engine.rb
CHANGED
@@ -47,7 +47,6 @@ class Engine < ::Rails::Engine
|
|
47
47
|
when -> (v) { v2.match?('', v) },
|
48
48
|
-> (v) { vgte3.match?('', v) }
|
49
49
|
|
50
|
-
# Other rails version, assumed newer
|
51
50
|
Rails.application.config.assets.configure do |config|
|
52
51
|
config.register_preprocessor(
|
53
52
|
"application/javascript",
|
data/lib/js_routes/version.rb
CHANGED
data/lib/routes.d.ts
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
/**
|
2
|
+
* File generated by js-routes RubyVariables.GEM_VERSION
|
3
|
+
* Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
|
4
|
+
*/
|
5
|
+
declare type RouteParameter = unknown;
|
6
|
+
declare type RouteParameters = Record<string, RouteParameter>;
|
7
|
+
declare type Serializer = (value: unknown) => string;
|
8
|
+
declare type RouteHelper = {
|
9
|
+
(...args: RouteParameter[]): string;
|
10
|
+
requiredParams(): string[];
|
11
|
+
toString(): string;
|
12
|
+
};
|
13
|
+
declare type RouteHelpers = Record<string, RouteHelper>;
|
14
|
+
declare type Configuration = {
|
15
|
+
prefix: string;
|
16
|
+
default_url_options: RouteParameters;
|
17
|
+
special_options_key: string;
|
18
|
+
serializer: Serializer;
|
19
|
+
};
|
20
|
+
declare type Optional<T> = {
|
21
|
+
[P in keyof T]?: T[P] | null;
|
22
|
+
};
|
23
|
+
interface RouterExposedMethods {
|
24
|
+
config(): Configuration;
|
25
|
+
configure(arg: Partial<Configuration>): Configuration;
|
26
|
+
serialize: Serializer;
|
27
|
+
}
|
28
|
+
declare type KeywordUrlOptions = Optional<{
|
29
|
+
host: string;
|
30
|
+
protocol: string;
|
31
|
+
subdomain: string;
|
32
|
+
port: string;
|
33
|
+
anchor: string;
|
34
|
+
trailing_slash: boolean;
|
35
|
+
}>;
|
36
|
+
declare type PartsTable = Record<
|
37
|
+
string,
|
38
|
+
{
|
39
|
+
r?: boolean;
|
40
|
+
d?: unknown;
|
41
|
+
}
|
42
|
+
>;
|
43
|
+
declare type ModuleType = "CJS" | "AMD" | "UMD" | "ESM";
|
44
|
+
declare const RubyVariables: {
|
45
|
+
PREFIX: string;
|
46
|
+
DEPRECATED_GLOBBING_BEHAVIOR: boolean;
|
47
|
+
SPECIAL_OPTIONS_KEY: string;
|
48
|
+
DEFAULT_URL_OPTIONS: RouteParameters;
|
49
|
+
SERIALIZER: Serializer;
|
50
|
+
NAMESPACE: string;
|
51
|
+
ROUTES_OBJECT: RouteHelpers;
|
52
|
+
MODULE_TYPE: ModuleType | null;
|
53
|
+
WRAPPER: <T>(callback: T) => T;
|
54
|
+
};
|
55
|
+
declare const define:
|
56
|
+
| undefined
|
57
|
+
| (((arg: unknown[], callback: () => unknown) => void) & {
|
58
|
+
amd?: unknown;
|
59
|
+
});
|
60
|
+
declare const module:
|
61
|
+
| {
|
62
|
+
exports: any;
|
63
|
+
}
|
64
|
+
| undefined;
|