js-routes 1.4.14 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
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 = {
@@ -42,7 +45,6 @@ class JsRoutes
42
45
  DOT: 8
43
46
  } #:nodoc:
44
47
 
45
- LAST_OPTIONS_KEY = "options".freeze #:nodoc:
46
48
  FILTERED_DEFAULT_PARTS = [:controller, :action] #:nodoc:
47
49
  URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain] #:nodoc:
48
50
 
@@ -72,6 +74,10 @@ class JsRoutes
72
74
  def to_hash
73
75
  Hash[*members.zip(values).flatten(1)].symbolize_keys
74
76
  end
77
+
78
+ def esm?
79
+ self.module_type === 'ESM'
80
+ end
75
81
  end
76
82
 
77
83
  #
@@ -83,11 +89,6 @@ class JsRoutes
83
89
  configuration.tap(&block) if block
84
90
  end
85
91
 
86
- def options
87
- ActiveSupport::Deprecation.warn('JsRoutes.options method is deprecated use JsRoutes.configuration instead')
88
- configuration
89
- end
90
-
91
92
  def configuration
92
93
  @configuration ||= Configuration.new
93
94
  end
@@ -125,8 +126,7 @@ class JsRoutes
125
126
 
126
127
  {
127
128
  'GEM_VERSION' => JsRoutes::VERSION,
128
- 'ROUTES' => js_routes,
129
- 'NODE_TYPES' => json(NODE_TYPES),
129
+ 'ROUTES_OBJECT' => routes_object,
130
130
  'RAILS_VERSION' => ActionPack.version,
131
131
  'DEPRECATED_GLOBBING_BEHAVIOR' => ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR == 0,
132
132
 
@@ -136,9 +136,12 @@ class JsRoutes
136
136
  'PREFIX' => json(@configuration.prefix),
137
137
  'SPECIAL_OPTIONS_KEY' => json(@configuration.special_options_key),
138
138
  'SERIALIZER' => @configuration.serializer || json(nil),
139
+ 'MODULE_TYPE' => json(@configuration.module_type),
140
+ 'WRAPPER' => @configuration.esm? ? 'const __jsr = ' : '',
139
141
  }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)|
140
- js.gsub!(key, value.to_s)
141
- end
142
+ js.gsub!("RubyVariables.#{key}", value.to_s) ||
143
+ raise("Missing key #{key} in JS template")
144
+ end + routes_export
142
145
  end
143
146
 
144
147
  def generate!(file_name = nil)
@@ -166,23 +169,45 @@ class JsRoutes
166
169
  @configuration.application
167
170
  end
168
171
 
172
+ def json(string)
173
+ self.class.json(string)
174
+ end
175
+
169
176
  def named_routes
170
177
  application.routes.named_routes.to_a
171
178
  end
172
179
 
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)
180
+ def routes_object
181
+ return json({}) if @configuration.esm?
182
+ properties = routes_list.map do |comment, name, body|
183
+ "#{comment}#{name}: #{body}".indent(2)
184
+ end
185
+ "{\n" + properties.join(",\n\n") + "}\n"
186
+ end
187
+
188
+ STATIC_EXPORTS = [:configure, :config, :serialize].map do |name|
189
+ ["", name, "__jsr.#{name}"]
190
+ end
191
+
192
+ 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")
197
+ end
198
+
199
+ def routes_list
200
+ named_routes.sort_by(&:first).flat_map do |_, route|
201
+ route_helpers_if_match(route) + mounted_app_routes(route)
176
202
  end.compact
177
- "{\n" + js_routes.join(",\n") + "}\n"
178
203
  end
179
204
 
180
205
  def mounted_app_routes(route)
181
206
  rails_engine_app = get_app_from_route(route)
182
207
  if rails_engine_app.respond_to?(:superclass) &&
183
208
  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)
209
+ rails_engine_app.routes.named_routes.flat_map do |_, engine_route|
210
+ route_helpers_if_match(engine_route, route)
186
211
  end
187
212
  else
188
213
  []
@@ -199,104 +224,149 @@ class JsRoutes
199
224
  end
200
225
  end
201
226
 
202
- def build_route_if_match(route, parent_route = nil)
203
- if any_match?(route, parent_route, @configuration[:exclude]) ||
204
- !any_match?(route, parent_route, @configuration[:include])
205
- nil
206
- else
207
- build_js(route, parent_route)
208
- end
227
+ def route_helpers_if_match(route, parent_route = nil)
228
+ JsRoute.new(@configuration, route, parent_route).helpers
209
229
  end
210
230
 
211
- def any_match?(route, parent_route, matchers)
212
- full_route = [parent_route.try(:name), route.name].compact.join('_')
231
+ class JsRoute #:nodoc:
232
+ attr_reader :configuration, :route, :parent_route
213
233
 
214
- matchers = Array(matchers)
215
- matchers.any? { |regex| full_route =~ regex }
216
- end
234
+ def initialize(configuration, route, parent_route = nil)
235
+ @configuration = configuration
236
+ @route = route
237
+ @parent_route = parent_route
238
+ end
217
239
 
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
229
- end
240
+ 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
248
+ end
249
+ end
230
250
 
231
- def route_js_arguments(route, parent_spec)
232
- required_parts = route.required_parts
233
- parts_table = route.parts.each_with_object({}) do |part, hash|
234
- hash[part] = required_parts.include?(part)
235
- end
236
- default_options = route.defaults.select do |part, _|
237
- FILTERED_DEFAULT_PARTS.exclude?(part) &&
238
- URL_OPTIONS.include?(part) || parts_table[part]
239
- end
240
- [
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,
245
- serialize(route.path.spec, parent_spec)
246
- ].map do |argument|
247
- json(argument)
248
- end.join(', ')
249
- end
251
+ def body(absolute)
252
+ "__jsr.r(#{arguments(absolute).join(', ')})"
253
+ end
250
254
 
251
- def generate_url_link(name, route_arguments)
252
- return '' unless @configuration[:url_links]
255
+ def arguments(absolute)
256
+ absolute ? base_arguments + [json(true)] : base_arguments
257
+ end
253
258
 
254
- <<-JS.strip!
255
- #{generate_route_name(name, :url)}: Utils.route(#{route_arguments}, true)
256
- JS
257
- end
259
+ def match_configuration?
260
+ !match?(@configuration[:exclude]) && match?(@configuration[:include])
261
+ end
258
262
 
259
- def generate_route_name(*parts)
260
- route_name = parts.compact.join('_')
261
- @configuration[:camel_case] ? route_name.camelize(:lower) : route_name
262
- end
263
+ def base_name
264
+ @base_name ||= apply_case(parent_route&.name, route.name)
265
+ end
263
266
 
264
- def json(string)
265
- self.class.json(string)
266
- end
267
+ def parent_spec
268
+ parent_route&.path&.spec
269
+ end
267
270
 
268
- def build_params(required_parts)
269
- params = required_parts + [LAST_OPTIONS_KEY]
270
- params.join(', ')
271
- end
271
+ def spec
272
+ route.path.spec
273
+ end
272
274
 
273
- # This function serializes Journey route into JSON structure
274
- # We do not use Hash for human readable serialization
275
- # And preffer Array serialization because it is shorter.
276
- # Routes.js file will be smaller.
277
- def serialize(spec, parent_spec=nil)
278
- return nil unless spec
279
- # Rails 4 globbing requires * removal
280
- return spec.tr(':*', '') if spec.is_a?(String)
281
-
282
- result = serialize_spec(spec, parent_spec)
283
- if parent_spec && result[1].is_a?(String)
284
- result = [
285
- # We encode node symbols as integer
286
- # to reduce the routes.js file size
287
- NODE_TYPES[:CAT],
288
- serialize_spec(parent_spec),
289
- result
290
- ]
291
- end
292
- result
293
- end
275
+ def json(value)
276
+ JsRoutes.json(value)
277
+ end
294
278
 
295
- def serialize_spec(spec, parent_spec = nil)
296
- [
297
- NODE_TYPES[spec.type],
298
- serialize(spec.left, parent_spec),
299
- spec.respond_to?(:right) && serialize(spec.right)
300
- ]
279
+ def helper_name(absolute)
280
+ suffix = absolute ? :url : @configuration[:compact] ? nil : :path
281
+ suffix ? apply_case(base_name, suffix) : base_name
282
+ end
283
+
284
+ def documentation
285
+ return nil unless @configuration[:documentation]
286
+ <<-JS
287
+ /**
288
+ * Generates rails route to
289
+ * #{parent_spec}#{spec}#{documentation_params}
290
+ * @param {object | undefined} options
291
+ * @returns {string} route path
292
+ */
293
+ JS
294
+ end
295
+
296
+ def required_parts
297
+ route.required_parts
298
+ end
299
+
300
+ protected
301
+
302
+ def base_arguments
303
+ return @base_arguments if defined?(@base_arguments)
304
+ parts_table = {}
305
+ route.parts.each do |part, hash|
306
+ parts_table[part] ||= {}
307
+ if required_parts.include?(part)
308
+ # Using shortened keys to reduce js file size
309
+ parts_table[part][:r] = true
310
+ end
311
+ end
312
+ route.defaults.each do |part, value|
313
+ if FILTERED_DEFAULT_PARTS.exclude?(part) &&
314
+ URL_OPTIONS.include?(part) || parts_table[part]
315
+ parts_table[part] ||= {}
316
+ # Using shortened keys to reduce js file size
317
+ parts_table[part][:d] = value
318
+ end
319
+ end
320
+ @base_arguments = [
321
+ parts_table, serialize(spec, parent_spec)
322
+ ].map do |argument|
323
+ json(argument)
324
+ end
325
+ end
326
+
327
+ def documentation_params
328
+ required_parts.map do |param|
329
+ "\n * @param {any} #{apply_case(param)}"
330
+ end.join
331
+ end
332
+
333
+ def match?(matchers)
334
+ Array(matchers).any? { |regex| base_name =~ regex }
335
+ end
336
+
337
+ def apply_case(*values)
338
+ value = values.compact.map(&:to_s).join('_')
339
+ @configuration[:camel_case] ? value.camelize(:lower) : value
340
+ end
341
+
342
+ # This function serializes Journey route into JSON structure
343
+ # We do not use Hash for human readable serialization
344
+ # And preffer Array serialization because it is shorter.
345
+ # Routes.js file will be smaller.
346
+ def serialize(spec, parent_spec=nil)
347
+ return nil unless spec
348
+ # Rails 4 globbing requires * removal
349
+ return spec.tr(':*', '') if spec.is_a?(String)
350
+
351
+ result = serialize_spec(spec, parent_spec)
352
+ if parent_spec && result[1].is_a?(String) && parent_spec.type != :SLASH
353
+ result = [
354
+ # We encode node symbols as integer
355
+ # to reduce the routes.js file size
356
+ NODE_TYPES[:CAT],
357
+ serialize_spec(parent_spec),
358
+ result
359
+ ]
360
+ end
361
+ result
362
+ end
363
+
364
+ def serialize_spec(spec, parent_spec = nil)
365
+ [
366
+ NODE_TYPES[spec.type],
367
+ serialize(spec.left, parent_spec),
368
+ spec.respond_to?(:right) ? serialize(spec.right) : nil
369
+ ].compact
370
+ end
301
371
  end
302
372
  end
@@ -1,3 +1,3 @@
1
1
  class JsRoutes
2
- VERSION = "1.4.14"
2
+ VERSION = "2.0.4"
3
3
  end
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;
data/lib/routes.js CHANGED
@@ -1,528 +1,493 @@
1
- /*
2
- File generated by js-routes GEM_VERSION
3
- Based on Rails RAILS_VERSION routes of APP_CLASS
1
+ /**
2
+ * File generated by js-routes RubyVariables.GEM_VERSION
3
+ * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
4
  */
5
-
6
- (function() {
7
- var DeprecatedGlobbingBehavior, NodeTypes, ParameterMissing, ReservedOptions, SpecialOptionsKey, UriEncoderSegmentRegex, Utils, error, result,
8
- hasProp = {}.hasOwnProperty,
9
- slice = [].slice;
10
-
11
- ParameterMissing = function(message, fileName, lineNumber) {
12
- var instance;
13
- instance = new Error(message, fileName, lineNumber);
14
- if (Object.setPrototypeOf) {
15
- Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
16
- } else {
17
- instance.__proto__ = this.__proto__;
18
- }
19
- if (Error.captureStackTrace) {
20
- Error.captureStackTrace(instance, ParameterMissing);
21
- }
22
- return instance;
23
- };
24
-
25
- ParameterMissing.prototype = Object.create(Error.prototype, {
26
- constructor: {
27
- value: Error,
28
- enumerable: false,
29
- writable: true,
30
- configurable: true
5
+ RubyVariables.WRAPPER((that) => {
6
+ const hasProp = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
7
+ let NodeTypes;
8
+ (function (NodeTypes) {
9
+ NodeTypes[NodeTypes["GROUP"] = 1] = "GROUP";
10
+ NodeTypes[NodeTypes["CAT"] = 2] = "CAT";
11
+ NodeTypes[NodeTypes["SYMBOL"] = 3] = "SYMBOL";
12
+ NodeTypes[NodeTypes["OR"] = 4] = "OR";
13
+ NodeTypes[NodeTypes["STAR"] = 5] = "STAR";
14
+ NodeTypes[NodeTypes["LITERAL"] = 6] = "LITERAL";
15
+ NodeTypes[NodeTypes["SLASH"] = 7] = "SLASH";
16
+ NodeTypes[NodeTypes["DOT"] = 8] = "DOT";
17
+ })(NodeTypes || (NodeTypes = {}));
18
+ const Root = that;
19
+ const ModuleReferences = {
20
+ CJS: {
21
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22
+ define: (routes) => (module.exports = routes),
23
+ support: () => typeof module === "object",
24
+ },
25
+ AMD: {
26
+ define: (routes) =>
27
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28
+ define([], function () {
29
+ return routes;
30
+ }),
31
+ support: () => typeof define === "function" && !!define.amd,
32
+ },
33
+ UMD: {
34
+ define: (routes) => {
35
+ if (ModuleReferences.AMD.support()) {
36
+ ModuleReferences.AMD.define(routes);
37
+ }
38
+ else {
39
+ if (ModuleReferences.CJS.support()) {
40
+ try {
41
+ ModuleReferences.CJS.define(routes);
42
+ }
43
+ catch (error) {
44
+ if (error.name !== "TypeError")
45
+ throw error;
46
+ }
47
+ }
48
+ }
49
+ },
50
+ support: () => ModuleReferences.AMD.support() || ModuleReferences.CJS.support(),
51
+ },
52
+ ESM: {
53
+ define: () => null,
54
+ support: () => true,
55
+ },
56
+ };
57
+ class ParametersMissing extends Error {
58
+ constructor(...keys) {
59
+ super(`Route missing required keys: ${keys.join(", ")}`);
60
+ this.keys = keys;
61
+ Object.setPrototypeOf(this, Object.getPrototypeOf(this));
62
+ this.name = ParametersMissing.name;
63
+ }
31
64
  }
32
- });
33
-
34
- if (Object.setPrototypeOf) {
35
- Object.setPrototypeOf(ParameterMissing, Error);
36
- } else {
37
- ParameterMissing.__proto__ = Error;
38
- }
39
-
40
- NodeTypes = NODE_TYPES;
41
-
42
- DeprecatedGlobbingBehavior = DEPRECATED_GLOBBING_BEHAVIOR;
43
-
44
- SpecialOptionsKey = SPECIAL_OPTIONS_KEY;
45
-
46
- UriEncoderSegmentRegex = /[^a-zA-Z0-9\-\._~!\$&'\(\)\*\+,;=:@]/g;
47
-
48
- ReservedOptions = ['anchor', 'trailing_slash', 'subdomain', 'host', 'port', 'protocol'];
49
-
50
- Utils = {
51
- configuration: {
52
- prefix: PREFIX,
53
- default_url_options: DEFAULT_URL_OPTIONS,
54
- special_options_key: SPECIAL_OPTIONS_KEY,
55
- serializer: SERIALIZER
56
- },
57
- default_serializer: function(object, prefix) {
58
- var element, i, j, key, len, prop, s;
59
- if (prefix == null) {
60
- prefix = null;
61
- }
62
- if (object == null) {
63
- return "";
64
- }
65
- if (!prefix && !(this.get_object_type(object) === "object")) {
66
- throw new Error("Url parameters should be a javascript hash");
67
- }
68
- s = [];
69
- switch (this.get_object_type(object)) {
70
- case "array":
71
- for (i = j = 0, len = object.length; j < len; i = ++j) {
72
- element = object[i];
73
- s.push(this.default_serializer(element, prefix + "[]"));
74
- }
75
- break;
76
- case "object":
77
- for (key in object) {
78
- if (!hasProp.call(object, key)) continue;
79
- prop = object[key];
80
- if ((prop == null) && (prefix != null)) {
81
- prop = "";
82
- }
83
- if (prop != null) {
84
- if (prefix != null) {
85
- key = prefix + "[" + key + "]";
86
- }
87
- s.push(this.default_serializer(prop, key));
88
- }
89
- }
90
- break;
91
- default:
92
- if (object != null) {
93
- s.push((encodeURIComponent(prefix.toString())) + "=" + (encodeURIComponent(object.toString())));
94
- }
95
- }
96
- if (!s.length) {
97
- return "";
98
- }
99
- return s.join("&");
100
- },
101
- serialize: function(object) {
102
- var custom_serializer;
103
- custom_serializer = this.configuration.serializer;
104
- if ((custom_serializer != null) && this.get_object_type(custom_serializer) === "function") {
105
- return custom_serializer(object);
106
- } else {
107
- return this.default_serializer(object);
108
- }
109
- },
110
- clean_path: function(path) {
111
- var last_index;
112
- path = path.split("://");
113
- last_index = path.length - 1;
114
- path[last_index] = path[last_index].replace(/\/+/g, "/");
115
- return path.join("://");
116
- },
117
- extract_options: function(number_of_params, args) {
118
- var last_el, options;
119
- last_el = args[args.length - 1];
120
- if ((args.length > number_of_params && last_el === void 0) || ((last_el != null) && "object" === this.get_object_type(last_el) && !this.looks_like_serialized_model(last_el))) {
121
- options = args.pop() || {};
122
- delete options[this.configuration.special_options_key];
123
- return options;
124
- } else {
125
- return {};
126
- }
127
- },
128
- looks_like_serialized_model: function(object) {
129
- return !object[this.configuration.special_options_key] && ("id" in object || "to_param" in object);
130
- },
131
- path_identifier: function(object) {
132
- var property;
133
- if (object === 0) {
134
- return "0";
135
- }
136
- if (!object) {
137
- return "";
138
- }
139
- property = object;
140
- if (this.get_object_type(object) === "object") {
141
- if ("to_param" in object) {
142
- if (object.to_param == null) {
143
- throw new ParameterMissing("Route parameter missing: to_param");
144
- }
145
- property = object.to_param;
146
- } else if ("id" in object) {
147
- if (object.id == null) {
148
- throw new ParameterMissing("Route parameter missing: id");
149
- }
150
- property = object.id;
151
- } else {
152
- property = object;
153
- }
154
- if (this.get_object_type(property) === "function") {
155
- property = property.call(object);
156
- }
157
- }
158
- return property.toString();
159
- },
160
- clone: function(obj) {
161
- var attr, copy, key;
162
- if ((obj == null) || "object" !== this.get_object_type(obj)) {
163
- return obj;
164
- }
165
- copy = obj.constructor();
166
- for (key in obj) {
167
- if (!hasProp.call(obj, key)) continue;
168
- attr = obj[key];
169
- copy[key] = attr;
170
- }
171
- return copy;
172
- },
173
- merge: function() {
174
- var tap, xs;
175
- xs = 1 <= arguments.length ? slice.call(arguments, 0) : [];
176
- tap = function(o, fn) {
177
- fn(o);
178
- return o;
179
- };
180
- if ((xs != null ? xs.length : void 0) > 0) {
181
- return tap({}, function(m) {
182
- var j, k, len, results, v, x;
183
- results = [];
184
- for (j = 0, len = xs.length; j < len; j++) {
185
- x = xs[j];
186
- results.push((function() {
187
- var results1;
188
- results1 = [];
189
- for (k in x) {
190
- v = x[k];
191
- results1.push(m[k] = v);
192
- }
193
- return results1;
194
- })());
195
- }
196
- return results;
197
- });
198
- }
199
- },
200
- normalize_options: function(parts, required_parts, default_options, actual_parameters) {
201
- var i, j, key, len, options, part, parts_options, result, route_parts, url_parameters, use_all_parts, value;
202
- options = this.extract_options(parts.length, actual_parameters);
203
- if (actual_parameters.length > parts.length) {
204
- throw new Error("Too many parameters provided for path");
205
- }
206
- use_all_parts = actual_parameters.length > required_parts.length;
207
- parts_options = {};
208
- for (key in options) {
209
- if (!hasProp.call(options, key)) continue;
210
- use_all_parts = true;
211
- if (this.indexOf(parts, key) >= 0) {
212
- parts_options[key] = value;
213
- }
214
- }
215
- options = this.merge(this.configuration.default_url_options, default_options, options);
216
- result = {};
217
- url_parameters = {};
218
- result['url_parameters'] = url_parameters;
219
- for (key in options) {
220
- if (!hasProp.call(options, key)) continue;
221
- value = options[key];
222
- if (this.indexOf(ReservedOptions, key) >= 0) {
223
- result[key] = value;
224
- } else {
225
- url_parameters[key] = value;
226
- }
227
- }
228
- route_parts = use_all_parts ? parts : required_parts;
229
- i = 0;
230
- for (j = 0, len = route_parts.length; j < len; j++) {
231
- part = route_parts[j];
232
- if (i < actual_parameters.length) {
233
- if (!parts_options.hasOwnProperty(part)) {
234
- url_parameters[part] = actual_parameters[i];
235
- ++i;
236
- }
237
- }
238
- }
239
- return result;
240
- },
241
- build_route: function(parts, required_parts, default_options, route, full_url, args) {
242
- var options, parameters, result, url, url_params;
243
- args = Array.prototype.slice.call(args);
244
- options = this.normalize_options(parts, required_parts, default_options, args);
245
- parameters = options['url_parameters'];
246
- result = "" + (this.get_prefix()) + (this.visit(route, parameters));
247
- url = Utils.clean_path(result);
248
- if (options['trailing_slash'] === true) {
249
- url = url.replace(/(.*?)[\/]?$/, "$1/");
250
- }
251
- if ((url_params = this.serialize(parameters)).length) {
252
- url += "?" + url_params;
253
- }
254
- url += options.anchor ? "#" + options.anchor : "";
255
- if (full_url) {
256
- url = this.route_url(options) + url;
257
- }
258
- return url;
259
- },
260
- visit: function(route, parameters, optional) {
261
- var left, left_part, right, right_part, type, value;
262
- if (optional == null) {
263
- optional = false;
264
- }
265
- type = route[0], left = route[1], right = route[2];
266
- switch (type) {
267
- case NodeTypes.GROUP:
268
- return this.visit(left, parameters, true);
269
- case NodeTypes.STAR:
270
- return this.visit_globbing(left, parameters, true);
271
- case NodeTypes.LITERAL:
272
- case NodeTypes.SLASH:
273
- case NodeTypes.DOT:
274
- return left;
275
- case NodeTypes.CAT:
276
- left_part = this.visit(left, parameters, optional);
277
- right_part = this.visit(right, parameters, optional);
278
- if (optional && ((this.is_optional_node(left[0]) && !left_part) || ((this.is_optional_node(right[0])) && !right_part))) {
279
- return "";
280
- }
281
- return "" + left_part + right_part;
282
- case NodeTypes.SYMBOL:
283
- value = parameters[left];
284
- delete parameters[left];
285
- if (value != null) {
286
- return this.encode_segment(this.path_identifier(value));
287
- }
288
- if (optional) {
289
- return "";
290
- } else {
291
- throw new ParameterMissing("Route parameter missing: " + left);
292
- }
293
- break;
294
- default:
295
- throw new Error("Unknown Rails node type");
296
- }
297
- },
298
- encode_segment: function(segment) {
299
- return segment.replace(UriEncoderSegmentRegex, function(str) {
300
- return encodeURIComponent(str);
301
- });
302
- },
303
- is_optional_node: function(node) {
304
- return this.indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0;
305
- },
306
- build_path_spec: function(route, wildcard) {
307
- var left, right, type;
308
- if (wildcard == null) {
309
- wildcard = false;
310
- }
311
- type = route[0], left = route[1], right = route[2];
312
- switch (type) {
313
- case NodeTypes.GROUP:
314
- return "(" + (this.build_path_spec(left)) + ")";
315
- case NodeTypes.CAT:
316
- return "" + (this.build_path_spec(left)) + (this.build_path_spec(right));
317
- case NodeTypes.STAR:
318
- return this.build_path_spec(left, true);
319
- case NodeTypes.SYMBOL:
320
- if (wildcard === true) {
321
- return "" + (left[0] === '*' ? '' : '*') + left;
322
- } else {
323
- return ":" + left;
324
- }
325
- break;
326
- case NodeTypes.SLASH:
327
- case NodeTypes.DOT:
328
- case NodeTypes.LITERAL:
329
- return left;
330
- default:
331
- throw new Error("Unknown Rails node type");
332
- }
333
- },
334
- visit_globbing: function(route, parameters, optional) {
335
- var left, right, type, value;
336
- type = route[0], left = route[1], right = route[2];
337
- value = parameters[left];
338
- delete parameters[left];
339
- if (value == null) {
340
- return this.visit(route, parameters, optional);
341
- }
342
- value = (function() {
343
- switch (this.get_object_type(value)) {
344
- case "array":
345
- return value.join("/");
346
- default:
347
- return value;
348
- }
349
- }).call(this);
350
- if (DeprecatedGlobbingBehavior) {
351
- return this.path_identifier(value);
352
- } else {
353
- return encodeURI(this.path_identifier(value));
354
- }
355
- },
356
- get_prefix: function() {
357
- var prefix;
358
- prefix = this.configuration.prefix;
359
- if (prefix !== "") {
360
- prefix = (prefix.match("/$") ? prefix : prefix + "/");
361
- }
362
- return prefix;
363
- },
364
- route: function(parts_table, default_options, route_spec, full_url) {
365
- var j, len, part, parts, path_fn, ref, required, required_parts;
366
- required_parts = [];
367
- parts = [];
368
- for (j = 0, len = parts_table.length; j < len; j++) {
369
- ref = parts_table[j], part = ref[0], required = ref[1];
370
- parts.push(part);
371
- if (required) {
372
- required_parts.push(part);
373
- }
374
- }
375
- path_fn = function() {
376
- return Utils.build_route(parts, required_parts, default_options, route_spec, full_url, arguments);
377
- };
378
- path_fn.required_params = required_parts;
379
- path_fn.toString = function() {
380
- return Utils.build_path_spec(route_spec);
381
- };
382
- return path_fn;
383
- },
384
- route_url: function(route_defaults) {
385
- var hostname, port, protocol, subdomain;
386
- if (typeof route_defaults === 'string') {
387
- return route_defaults;
388
- }
389
- hostname = route_defaults.host || Utils.current_host();
390
- if (!hostname) {
391
- return '';
392
- }
393
- subdomain = route_defaults.subdomain ? route_defaults.subdomain + '.' : '';
394
- protocol = route_defaults.protocol || Utils.current_protocol();
395
- port = route_defaults.port || (!route_defaults.host ? Utils.current_port() : void 0);
396
- port = port ? ":" + port : '';
397
- return protocol + "://" + subdomain + hostname + port;
398
- },
399
- has_location: function() {
400
- return (typeof window !== "undefined" && window !== null ? window.location : void 0) != null;
401
- },
402
- current_host: function() {
403
- if (this.has_location()) {
404
- return window.location.hostname;
405
- } else {
406
- return null;
407
- }
408
- },
409
- current_protocol: function() {
410
- if (this.has_location() && window.location.protocol !== '') {
411
- return window.location.protocol.replace(/:$/, '');
412
- } else {
413
- return 'http';
414
- }
415
- },
416
- current_port: function() {
417
- if (this.has_location() && window.location.port !== '') {
418
- return window.location.port;
419
- } else {
420
- return '';
421
- }
422
- },
423
- _classToTypeCache: null,
424
- _classToType: function() {
425
- var j, len, name, ref;
426
- if (this._classToTypeCache != null) {
427
- return this._classToTypeCache;
428
- }
429
- this._classToTypeCache = {};
430
- ref = "Boolean Number String Function Array Date RegExp Object Error".split(" ");
431
- for (j = 0, len = ref.length; j < len; j++) {
432
- name = ref[j];
433
- this._classToTypeCache["[object " + name + "]"] = name.toLowerCase();
434
- }
435
- return this._classToTypeCache;
436
- },
437
- get_object_type: function(obj) {
438
- if (this.jQuery && (this.jQuery.type != null)) {
439
- return this.jQuery.type(obj);
440
- }
441
- if (obj == null) {
442
- return "" + obj;
443
- }
444
- if (typeof obj === "object" || typeof obj === "function") {
445
- return this._classToType()[Object.prototype.toString.call(obj)] || "object";
446
- } else {
447
- return typeof obj;
448
- }
449
- },
450
- indexOf: function(array, element) {
451
- if (Array.prototype.indexOf) {
452
- return array.indexOf(element);
453
- } else {
454
- return this.indexOfImplementation(array, element);
455
- }
456
- },
457
- indexOfImplementation: function(array, element) {
458
- var el, i, j, len, result;
459
- result = -1;
460
- for (i = j = 0, len = array.length; j < len; i = ++j) {
461
- el = array[i];
462
- if (el === element) {
463
- result = i;
464
- }
465
- }
466
- return result;
467
- },
468
- namespace: function(root, namespace, routes) {
469
- var index, j, len, part, parts;
470
- parts = namespace ? namespace.split(".") : [];
471
- if (parts.length === 0) {
472
- return routes;
473
- }
474
- for (index = j = 0, len = parts.length; j < len; index = ++j) {
475
- part = parts[index];
476
- if (index < parts.length - 1) {
477
- root = (root[part] || (root[part] = {}));
478
- } else {
479
- return root[part] = routes;
480
- }
481
- }
482
- },
483
- configure: function(new_config) {
484
- return this.configuration = this.merge(this.configuration, new_config);
485
- },
486
- config: function() {
487
- return this.clone(this.configuration);
488
- },
489
- make: function() {
490
- var routes;
491
- routes = ROUTES;
492
- routes.configure = function(config) {
493
- return Utils.configure(config);
494
- };
495
- routes.config = function() {
496
- return Utils.config();
497
- };
498
- routes.default_serializer = function(object, prefix) {
499
- return Utils.default_serializer(object, prefix);
500
- };
501
- return Object.assign({
502
- "default": routes
503
- }, routes);
65
+ const DeprecatedGlobbingBehavior = RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR;
66
+ const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
67
+ const ReservedOptions = [
68
+ "anchor",
69
+ "trailing_slash",
70
+ "subdomain",
71
+ "host",
72
+ "port",
73
+ "protocol",
74
+ ];
75
+ class UtilsClass {
76
+ constructor() {
77
+ this.configuration = {
78
+ prefix: RubyVariables.PREFIX,
79
+ default_url_options: RubyVariables.DEFAULT_URL_OPTIONS,
80
+ special_options_key: RubyVariables.SPECIAL_OPTIONS_KEY,
81
+ serializer: RubyVariables.SERIALIZER || this.default_serializer.bind(this),
82
+ };
83
+ }
84
+ default_serializer(value, prefix) {
85
+ if (this.is_nullable(value)) {
86
+ return "";
87
+ }
88
+ if (!prefix && !this.is_object(value)) {
89
+ throw new Error("Url parameters should be a javascript hash");
90
+ }
91
+ prefix = prefix || "";
92
+ const result = [];
93
+ if (this.is_array(value)) {
94
+ for (const element of value) {
95
+ result.push(this.default_serializer(element, prefix + "[]"));
96
+ }
97
+ }
98
+ else if (this.is_object(value)) {
99
+ for (let key in value) {
100
+ if (!hasProp(value, key))
101
+ continue;
102
+ let prop = value[key];
103
+ if (this.is_nullable(prop) && prefix) {
104
+ prop = "";
105
+ }
106
+ if (this.is_not_nullable(prop)) {
107
+ if (prefix) {
108
+ key = prefix + "[" + key + "]";
109
+ }
110
+ result.push(this.default_serializer(prop, key));
111
+ }
112
+ }
113
+ }
114
+ else {
115
+ if (this.is_not_nullable(value)) {
116
+ result.push(encodeURIComponent(prefix) + "=" + encodeURIComponent("" + value));
117
+ }
118
+ }
119
+ return result.join("&");
120
+ }
121
+ serialize(object) {
122
+ return this.configuration.serializer(object);
123
+ }
124
+ extract_options(number_of_params, args) {
125
+ const last_el = args[args.length - 1];
126
+ if ((args.length > number_of_params && last_el === 0) ||
127
+ (this.is_object(last_el) &&
128
+ !this.looks_like_serialized_model(last_el))) {
129
+ if (this.is_object(last_el)) {
130
+ delete last_el[this.configuration.special_options_key];
131
+ }
132
+ return {
133
+ args: args.slice(0, args.length - 1),
134
+ options: last_el,
135
+ };
136
+ }
137
+ else {
138
+ return { args, options: {} };
139
+ }
140
+ }
141
+ looks_like_serialized_model(object) {
142
+ return (this.is_object(object) &&
143
+ !object[this.configuration.special_options_key] &&
144
+ ("id" in object || "to_param" in object || "toParam" in object));
145
+ }
146
+ path_identifier(object) {
147
+ const result = this.unwrap_path_identifier(object);
148
+ return this.is_nullable(result) || result === false ? "" : "" + result;
149
+ }
150
+ unwrap_path_identifier(object) {
151
+ let result = object;
152
+ if (!this.is_object(object)) {
153
+ return object;
154
+ }
155
+ if ("to_param" in object) {
156
+ result = object.to_param;
157
+ }
158
+ else if ("toParam" in object) {
159
+ result = object.toParam;
160
+ }
161
+ else if ("id" in object) {
162
+ result = object.id;
163
+ }
164
+ else {
165
+ result = object;
166
+ }
167
+ return this.is_callable(result) ? result.call(object) : result;
168
+ }
169
+ partition_parameters(parts, required_params, default_options, call_arguments) {
170
+ // eslint-disable-next-line prefer-const
171
+ let { args, options } = this.extract_options(parts.length, call_arguments);
172
+ if (args.length > parts.length) {
173
+ throw new Error("Too many parameters provided for path");
174
+ }
175
+ let use_all_parts = args.length > required_params.length;
176
+ const parts_options = {};
177
+ for (const key in options) {
178
+ const value = options[key];
179
+ if (!hasProp(options, key))
180
+ continue;
181
+ use_all_parts = true;
182
+ if (parts.includes(key)) {
183
+ parts_options[key] = value;
184
+ }
185
+ }
186
+ options = {
187
+ ...this.configuration.default_url_options,
188
+ ...default_options,
189
+ ...options,
190
+ };
191
+ const keyword_parameters = {};
192
+ const query_parameters = {};
193
+ for (const key in options) {
194
+ if (!hasProp(options, key))
195
+ continue;
196
+ const value = options[key];
197
+ if (this.is_reserved_option(key)) {
198
+ keyword_parameters[key] = value;
199
+ }
200
+ else {
201
+ if (!this.is_nullable(value) &&
202
+ (value !== default_options[key] || required_params.includes(key))) {
203
+ query_parameters[key] = value;
204
+ }
205
+ }
206
+ }
207
+ const route_parts = use_all_parts ? parts : required_params;
208
+ let i = 0;
209
+ for (const part of route_parts) {
210
+ if (i < args.length) {
211
+ const value = args[i];
212
+ if (!hasProp(parts_options, part)) {
213
+ query_parameters[part] = value;
214
+ ++i;
215
+ }
216
+ }
217
+ }
218
+ return { keyword_parameters, query_parameters };
219
+ }
220
+ build_route(parts, required_params, default_options, route, absolute, args) {
221
+ const { keyword_parameters, query_parameters, } = this.partition_parameters(parts, required_params, default_options, args);
222
+ const missing_params = required_params.filter((param) => !hasProp(query_parameters, param) ||
223
+ this.is_nullable(query_parameters[param]));
224
+ if (missing_params.length) {
225
+ throw new ParametersMissing(...missing_params);
226
+ }
227
+ let result = this.get_prefix() + this.visit(route, query_parameters);
228
+ if (keyword_parameters.trailing_slash) {
229
+ result = result.replace(/(.*?)[/]?$/, "$1/");
230
+ }
231
+ const url_params = this.serialize(query_parameters);
232
+ if (url_params.length) {
233
+ result += "?" + url_params;
234
+ }
235
+ result += keyword_parameters.anchor
236
+ ? "#" + keyword_parameters.anchor
237
+ : "";
238
+ if (absolute) {
239
+ result = this.route_url(keyword_parameters) + result;
240
+ }
241
+ return result;
242
+ }
243
+ visit(route, parameters, optional = false) {
244
+ switch (route[0]) {
245
+ case NodeTypes.GROUP:
246
+ return this.visit(route[1], parameters, true);
247
+ case NodeTypes.CAT:
248
+ return this.visit_cat(route, parameters, optional);
249
+ case NodeTypes.SYMBOL:
250
+ return this.visit_symbol(route, parameters, optional);
251
+ case NodeTypes.STAR:
252
+ return this.visit_globbing(route[1], parameters, true);
253
+ case NodeTypes.LITERAL:
254
+ case NodeTypes.SLASH:
255
+ case NodeTypes.DOT:
256
+ return route[1];
257
+ default:
258
+ throw new Error("Unknown Rails node type");
259
+ }
260
+ }
261
+ is_not_nullable(object) {
262
+ return !this.is_nullable(object);
263
+ }
264
+ is_nullable(object) {
265
+ return object === undefined || object === null;
266
+ }
267
+ visit_cat(
268
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
269
+ [_type, left, right], parameters, optional) {
270
+ const left_part = this.visit(left, parameters, optional);
271
+ let right_part = this.visit(right, parameters, optional);
272
+ if (optional &&
273
+ ((this.is_optional_node(left[0]) && !left_part) ||
274
+ (this.is_optional_node(right[0]) && !right_part))) {
275
+ return "";
276
+ }
277
+ // if left_part ends on '/' and right_part starts on '/'
278
+ if (left_part[left_part.length - 1] === '/' && right_part[0] === '/') {
279
+ // strip slash from right_part
280
+ // to prevent double slash
281
+ right_part = right_part.substring(1);
282
+ }
283
+ return left_part + right_part;
284
+ }
285
+ visit_symbol(
286
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
287
+ [_type, key], parameters, optional) {
288
+ const value = this.path_identifier(parameters[key]);
289
+ delete parameters[key];
290
+ if (value.length) {
291
+ return this.encode_segment(value);
292
+ }
293
+ if (optional) {
294
+ return "";
295
+ }
296
+ else {
297
+ throw new ParametersMissing(key);
298
+ }
299
+ }
300
+ encode_segment(segment) {
301
+ return segment.replace(UriEncoderSegmentRegex, function (str) {
302
+ return encodeURIComponent(str);
303
+ });
304
+ }
305
+ is_optional_node(node) {
306
+ return [NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT].includes(node);
307
+ }
308
+ build_path_spec(route, wildcard = false) {
309
+ let key;
310
+ switch (route[0]) {
311
+ case NodeTypes.GROUP:
312
+ return "(" + this.build_path_spec(route[1]) + ")";
313
+ case NodeTypes.CAT:
314
+ return (this.build_path_spec(route[1]) + this.build_path_spec(route[2]));
315
+ case NodeTypes.STAR:
316
+ return this.build_path_spec(route[1], true);
317
+ case NodeTypes.SYMBOL:
318
+ key = route[1];
319
+ if (wildcard) {
320
+ return (key.startsWith("*") ? "" : "*") + key;
321
+ }
322
+ else {
323
+ return ":" + key;
324
+ }
325
+ break;
326
+ case NodeTypes.SLASH:
327
+ case NodeTypes.DOT:
328
+ case NodeTypes.LITERAL:
329
+ return route[1];
330
+ default:
331
+ throw new Error("Unknown Rails node type");
332
+ }
333
+ }
334
+ visit_globbing(route, parameters, optional) {
335
+ const key = route[1];
336
+ let value = parameters[key];
337
+ delete parameters[key];
338
+ if (this.is_nullable(value)) {
339
+ return this.visit(route, parameters, optional);
340
+ }
341
+ if (this.is_array(value)) {
342
+ value = value.join("/");
343
+ }
344
+ const result = this.path_identifier(value);
345
+ return DeprecatedGlobbingBehavior ? result : encodeURI(result);
346
+ }
347
+ get_prefix() {
348
+ const prefix = this.configuration.prefix;
349
+ return prefix.match("/$")
350
+ ? prefix.substring(0, prefix.length - 1)
351
+ : prefix;
352
+ }
353
+ route(parts_table, route_spec, absolute = false) {
354
+ const required_params = [];
355
+ const parts = [];
356
+ const default_options = {};
357
+ for (const [part, { r: required, d: value }] of Object.entries(parts_table)) {
358
+ parts.push(part);
359
+ if (required) {
360
+ required_params.push(part);
361
+ }
362
+ if (this.is_not_nullable(value)) {
363
+ default_options[part] = value;
364
+ }
365
+ }
366
+ const result = (...args) => {
367
+ return this.build_route(parts, required_params, default_options, route_spec, absolute, args);
368
+ };
369
+ result.requiredParams = () => required_params;
370
+ result.toString = () => {
371
+ return this.build_path_spec(route_spec);
372
+ };
373
+ return result;
374
+ }
375
+ route_url(route_defaults) {
376
+ const hostname = route_defaults.host || this.current_host();
377
+ if (!hostname) {
378
+ return "";
379
+ }
380
+ const subdomain = route_defaults.subdomain
381
+ ? route_defaults.subdomain + "."
382
+ : "";
383
+ const protocol = route_defaults.protocol || this.current_protocol();
384
+ let port = route_defaults.port ||
385
+ (!route_defaults.host ? this.current_port() : undefined);
386
+ port = port ? ":" + port : "";
387
+ return protocol + "://" + subdomain + hostname + port;
388
+ }
389
+ has_location() {
390
+ return this.is_not_nullable(window) && !!window.location;
391
+ }
392
+ current_host() {
393
+ if (this.has_location()) {
394
+ return window.location.hostname;
395
+ }
396
+ else {
397
+ return null;
398
+ }
399
+ }
400
+ current_protocol() {
401
+ if (this.has_location() && window.location.protocol !== "") {
402
+ return window.location.protocol.replace(/:$/, "");
403
+ }
404
+ else {
405
+ return "http";
406
+ }
407
+ }
408
+ current_port() {
409
+ if (this.has_location() && window.location.port !== "") {
410
+ return window.location.port;
411
+ }
412
+ else {
413
+ return "";
414
+ }
415
+ }
416
+ is_object(value) {
417
+ return (typeof value === "object" &&
418
+ Object.prototype.toString.call(value) === "[object Object]");
419
+ }
420
+ is_array(object) {
421
+ return object instanceof Array;
422
+ }
423
+ is_callable(object) {
424
+ return typeof object === "function" && !!object.call;
425
+ }
426
+ is_reserved_option(key) {
427
+ return ReservedOptions.includes(key);
428
+ }
429
+ namespace(object, namespace, routes) {
430
+ const parts = (namespace === null || namespace === void 0 ? void 0 : namespace.split(".")) || [];
431
+ if (parts.length === 0) {
432
+ return routes;
433
+ }
434
+ for (let index = 0; index < parts.length; index++) {
435
+ const part = parts[index];
436
+ if (index < parts.length - 1) {
437
+ object = object[part] || (object[part] = {});
438
+ }
439
+ else {
440
+ return (object[part] = routes);
441
+ }
442
+ }
443
+ }
444
+ configure(new_config) {
445
+ this.configuration = { ...this.configuration, ...new_config };
446
+ return this.configuration;
447
+ }
448
+ config() {
449
+ return { ...this.configuration };
450
+ }
451
+ is_module_supported(name) {
452
+ return ModuleReferences[name].support();
453
+ }
454
+ ensure_module_supported(name) {
455
+ if (!this.is_module_supported(name)) {
456
+ throw new Error(`${name} is not supported by runtime`);
457
+ }
458
+ }
459
+ define_module(name, module) {
460
+ if (!name) {
461
+ return;
462
+ }
463
+ this.ensure_module_supported(name);
464
+ ModuleReferences[name].define(module);
465
+ }
504
466
  }
505
- };
506
-
507
- result = Utils.make();
508
-
509
- if (typeof define === "function" && define.amd) {
510
- define([], function() {
511
- return result;
512
- });
513
- } else if (typeof module !== "undefined" && module !== null) {
514
- try {
515
- module.exports = result;
516
- } catch (error1) {
517
- error = error1;
518
- if (error.name !== 'TypeError') {
519
- throw error;
520
- }
467
+ const Utils = new UtilsClass();
468
+ // We want this helper name to be short
469
+ const __jsr = {
470
+ r(parts_table, route_spec, absolute) {
471
+ return Utils.route(parts_table, route_spec, absolute);
472
+ },
473
+ };
474
+ const result = {
475
+ ...__jsr,
476
+ configure: (config) => {
477
+ return Utils.configure(config);
478
+ },
479
+ config: () => {
480
+ return Utils.config();
481
+ },
482
+ serialize: (object) => {
483
+ return Utils.serialize(object);
484
+ },
485
+ ...RubyVariables.ROUTES_OBJECT,
486
+ };
487
+ Utils.namespace(Root, RubyVariables.NAMESPACE, result);
488
+ if (RubyVariables.MODULE_TYPE) {
489
+ Utils.define_module(RubyVariables.MODULE_TYPE, result);
521
490
  }
522
- } else {
523
- Utils.namespace(this, NAMESPACE, result);
524
- }
525
-
526
- return result;
527
-
528
- }).call(this);
491
+ return result;
492
+ })(this);
493
+ //# sourceMappingURL=routes.js.map