js-routes 1.4.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.eslintrc.js +15 -0
  3. data/.gitignore +5 -0
  4. data/.nvmrc +1 -0
  5. data/.travis.yml +37 -30
  6. data/Appraisals +16 -13
  7. data/CHANGELOG.md +95 -0
  8. data/Rakefile +6 -2
  9. data/Readme.md +220 -88
  10. data/VERSION_2_UPGRADE.md +66 -0
  11. data/app/assets/javascripts/js-routes.js.erb +1 -1
  12. data/gemfiles/{rails40.gemfile → rails40_sprockets_2.gemfile} +1 -1
  13. data/gemfiles/{rails40_sprockets3.gemfile → rails40_sprockets_3.gemfile} +0 -0
  14. data/gemfiles/{rails41.gemfile → rails41_sprockets_2.gemfile} +1 -1
  15. data/gemfiles/{rails41_sprockets3.gemfile → rails41_sprockets_3.gemfile} +0 -0
  16. data/gemfiles/{rails32.gemfile → rails42_sprockets_2.gemfile} +2 -2
  17. data/gemfiles/{rails42_sprockets3.gemfile → rails42_sprockets_3.gemfile} +1 -1
  18. data/gemfiles/{rails50_sprockets3.gemfile → rails50_sprockets_3.gemfile} +1 -1
  19. data/gemfiles/rails51_sprockets_3.gemfile +8 -0
  20. data/gemfiles/rails52_sprockets_3.gemfile +8 -0
  21. data/js-routes.gemspec +9 -6
  22. data/lib/js_routes/engine.rb +6 -18
  23. data/lib/js_routes/version.rb +1 -1
  24. data/lib/js_routes.rb +329 -171
  25. data/lib/routes.d.ts +79 -0
  26. data/lib/routes.js +499 -485
  27. data/lib/routes.ts +732 -0
  28. data/lib/tasks/js_routes.rake +8 -2
  29. data/package.json +37 -0
  30. data/spec/dummy/app/assets/config/manifest.js +2 -0
  31. data/spec/js_routes/default_serializer_spec.rb +19 -3
  32. data/spec/js_routes/{amd_compatibility_spec.rb → module_types/amd_spec.rb} +1 -9
  33. data/spec/js_routes/module_types/cjs_spec.rb +15 -0
  34. data/spec/js_routes/module_types/dts/routes.spec.d.ts +114 -0
  35. data/spec/js_routes/module_types/dts/test.spec.ts +56 -0
  36. data/spec/js_routes/module_types/dts_spec.rb +111 -0
  37. data/spec/js_routes/module_types/esm_spec.rb +45 -0
  38. data/spec/js_routes/{generated_javascript_spec.rb → module_types/umd_spec.rb} +33 -27
  39. data/spec/js_routes/options_spec.rb +92 -50
  40. data/spec/js_routes/rails_routes_compatibility_spec.rb +107 -45
  41. data/spec/js_routes/zzz_last_post_rails_init_spec.rb +19 -8
  42. data/spec/spec_helper.rb +45 -42
  43. data/spec/support/routes.rb +19 -14
  44. data/spec/tsconfig.json +4 -0
  45. data/tsconfig.json +28 -0
  46. data/yarn.lock +2145 -0
  47. metadata +47 -34
  48. data/gemfiles/rails42.gemfile +0 -8
  49. data/gemfiles/rails50.gemfile +0 -8
  50. data/lib/routes.js.coffee +0 -386
data/lib/routes.js CHANGED
@@ -1,488 +1,502 @@
1
- /*
2
- File generated by js-routes GEM_VERSION
3
- Based on Rails 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 DeprecatedBehavior, NodeTypes, ParameterMissing, ReservedOptions, SpecialOptionsKey, Utils, root,
8
- hasProp = {}.hasOwnProperty,
9
- slice = [].slice;
10
-
11
- root = typeof exports !== "undefined" && exports !== null ? exports : this;
12
-
13
- ParameterMissing = function(message) {
14
- this.message = message;
15
- };
16
-
17
- ParameterMissing.prototype = new Error();
18
-
19
- NodeTypes = NODE_TYPES;
20
-
21
- SpecialOptionsKey = SPECIAL_OPTIONS_KEY;
22
-
23
- DeprecatedBehavior = DEPRECATED_BEHAVIOR;
24
-
25
- ReservedOptions = ['anchor', 'trailing_slash', 'host', 'port', 'protocol'];
26
-
27
- Utils = {
28
- configuration: {
29
- prefix: PREFIX,
30
- default_url_options: DEFAULT_URL_OPTIONS,
31
- special_options_key: SPECIAL_OPTIONS_KEY,
32
- serializer: SERIALIZER
33
- },
34
- default_serializer: function(object, prefix) {
35
- var element, i, j, key, len, prop, s;
36
- if (prefix == null) {
37
- prefix = null;
38
- }
39
- if (object == null) {
40
- return "";
41
- }
42
- if (!prefix && !(this.get_object_type(object) === "object")) {
43
- throw new Error("Url parameters should be a javascript hash");
44
- }
45
- s = [];
46
- switch (this.get_object_type(object)) {
47
- case "array":
48
- for (i = j = 0, len = object.length; j < len; i = ++j) {
49
- element = object[i];
50
- s.push(this.default_serializer(element, prefix + "[]"));
51
- }
52
- break;
53
- case "object":
54
- for (key in object) {
55
- if (!hasProp.call(object, key)) continue;
56
- prop = object[key];
57
- if ((prop == null) && (prefix != null)) {
58
- prop = "";
59
- }
60
- if (prop != null) {
61
- if (prefix != null) {
62
- key = prefix + "[" + key + "]";
63
- }
64
- s.push(this.default_serializer(prop, key));
65
- }
66
- }
67
- break;
68
- default:
69
- if (object != null) {
70
- s.push((encodeURIComponent(prefix.toString())) + "=" + (encodeURIComponent(object.toString())));
71
- }
72
- }
73
- if (!s.length) {
74
- return "";
75
- }
76
- return s.join("&");
77
- },
78
- serialize: function(object) {
79
- var custom_serializer;
80
- custom_serializer = this.configuration.serializer;
81
- if ((custom_serializer != null) && this.get_object_type(custom_serializer) === "function") {
82
- return custom_serializer(object);
83
- } else {
84
- return this.default_serializer(object);
85
- }
86
- },
87
- clean_path: function(path) {
88
- var last_index;
89
- path = path.split("://");
90
- last_index = path.length - 1;
91
- path[last_index] = path[last_index].replace(/\/+/g, "/");
92
- return path.join("://");
93
- },
94
- extract_options: function(number_of_params, args) {
95
- var last_el, options;
96
- last_el = args[args.length - 1];
97
- 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))) {
98
- options = args.pop() || {};
99
- delete options[this.configuration.special_options_key];
100
- return options;
101
- } else {
102
- return {};
103
- }
104
- },
105
- looks_like_serialized_model: function(object) {
106
- return !object[this.configuration.special_options_key] && ("id" in object || "to_param" in object);
107
- },
108
- path_identifier: function(object) {
109
- var property;
110
- if (object === 0) {
111
- return "0";
112
- }
113
- if (!object) {
114
- return "";
115
- }
116
- property = object;
117
- if (this.get_object_type(object) === "object") {
118
- if ("to_param" in object) {
119
- if (object.to_param == null) {
120
- throw new ParameterMissing("Route parameter missing: to_param");
121
- }
122
- property = object.to_param;
123
- } else if ("id" in object) {
124
- if (object.id == null) {
125
- throw new ParameterMissing("Route parameter missing: id");
126
- }
127
- property = object.id;
128
- } else {
129
- property = object;
130
- }
131
- if (this.get_object_type(property) === "function") {
132
- property = property.call(object);
133
- }
134
- }
135
- return property.toString();
136
- },
137
- clone: function(obj) {
138
- var attr, copy, key;
139
- if ((obj == null) || "object" !== this.get_object_type(obj)) {
140
- return obj;
141
- }
142
- copy = obj.constructor();
143
- for (key in obj) {
144
- if (!hasProp.call(obj, key)) continue;
145
- attr = obj[key];
146
- copy[key] = attr;
147
- }
148
- return copy;
149
- },
150
- merge: function() {
151
- var tap, xs;
152
- xs = 1 <= arguments.length ? slice.call(arguments, 0) : [];
153
- tap = function(o, fn) {
154
- fn(o);
155
- return o;
156
- };
157
- if ((xs != null ? xs.length : void 0) > 0) {
158
- return tap({}, function(m) {
159
- var j, k, len, results, v, x;
160
- results = [];
161
- for (j = 0, len = xs.length; j < len; j++) {
162
- x = xs[j];
163
- results.push((function() {
164
- var results1;
165
- results1 = [];
166
- for (k in x) {
167
- v = x[k];
168
- results1.push(m[k] = v);
169
- }
170
- return results1;
171
- })());
172
- }
173
- return results;
174
- });
175
- }
176
- },
177
- normalize_options: function(parts, required_parts, default_options, actual_parameters) {
178
- var i, j, key, len, options, part, parts_options, result, route_parts, url_parameters, use_all_parts, value;
179
- options = this.extract_options(parts.length, actual_parameters);
180
- if (actual_parameters.length > parts.length) {
181
- throw new Error("Too many parameters provided for path");
182
- }
183
- use_all_parts = DeprecatedBehavior || actual_parameters.length > required_parts.length;
184
- parts_options = {};
185
- for (key in options) {
186
- if (!hasProp.call(options, key)) continue;
187
- use_all_parts = true;
188
- if (this.indexOf(parts, key) >= 0) {
189
- parts_options[key] = value;
190
- }
191
- }
192
- options = this.merge(this.configuration.default_url_options, default_options, options);
193
- result = {};
194
- url_parameters = {};
195
- result['url_parameters'] = url_parameters;
196
- for (key in options) {
197
- if (!hasProp.call(options, key)) continue;
198
- value = options[key];
199
- if (this.indexOf(ReservedOptions, key) >= 0) {
200
- result[key] = value;
201
- } else {
202
- url_parameters[key] = value;
203
- }
204
- }
205
- route_parts = use_all_parts ? parts : required_parts;
206
- i = 0;
207
- for (j = 0, len = route_parts.length; j < len; j++) {
208
- part = route_parts[j];
209
- if (i < actual_parameters.length) {
210
- if (!parts_options.hasOwnProperty(part)) {
211
- url_parameters[part] = actual_parameters[i];
212
- ++i;
213
- }
214
- }
215
- }
216
- return result;
217
- },
218
- build_route: function(parts, required_parts, default_options, route, full_url, args) {
219
- var options, parameters, result, url, url_params;
220
- args = Array.prototype.slice.call(args);
221
- options = this.normalize_options(parts, required_parts, default_options, args);
222
- parameters = options['url_parameters'];
223
- result = "" + (this.get_prefix()) + (this.visit(route, parameters));
224
- url = Utils.clean_path(result);
225
- if (options['trailing_slash'] === true) {
226
- url = url.replace(/(.*?)[\/]?$/, "$1/");
227
- }
228
- if ((url_params = this.serialize(parameters)).length) {
229
- url += "?" + url_params;
230
- }
231
- url += options.anchor ? "#" + options.anchor : "";
232
- if (full_url) {
233
- url = this.route_url(options) + url;
234
- }
235
- return url;
236
- },
237
- visit: function(route, parameters, optional) {
238
- var left, left_part, right, right_part, type, value;
239
- if (optional == null) {
240
- optional = false;
241
- }
242
- type = route[0], left = route[1], right = route[2];
243
- switch (type) {
244
- case NodeTypes.GROUP:
245
- return this.visit(left, parameters, true);
246
- case NodeTypes.STAR:
247
- return this.visit_globbing(left, parameters, true);
248
- case NodeTypes.LITERAL:
249
- case NodeTypes.SLASH:
250
- case NodeTypes.DOT:
251
- return left;
252
- case NodeTypes.CAT:
253
- left_part = this.visit(left, parameters, optional);
254
- right_part = this.visit(right, parameters, optional);
255
- if (optional && ((this.is_optional_node(left[0]) && !left_part) || ((this.is_optional_node(right[0])) && !right_part))) {
256
- return "";
257
- }
258
- return "" + left_part + right_part;
259
- case NodeTypes.SYMBOL:
260
- value = parameters[left];
261
- if (value != null) {
262
- delete parameters[left];
263
- return this.path_identifier(value);
264
- }
265
- if (optional) {
266
- return "";
267
- } else {
268
- throw new ParameterMissing("Route parameter missing: " + left);
269
- }
270
- break;
271
- default:
272
- throw new Error("Unknown Rails node type");
273
- }
274
- },
275
- is_optional_node: function(node) {
276
- return this.indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0;
277
- },
278
- build_path_spec: function(route, wildcard) {
279
- var left, right, type;
280
- if (wildcard == null) {
281
- wildcard = false;
282
- }
283
- type = route[0], left = route[1], right = route[2];
284
- switch (type) {
285
- case NodeTypes.GROUP:
286
- return "(" + (this.build_path_spec(left)) + ")";
287
- case NodeTypes.CAT:
288
- return "" + (this.build_path_spec(left)) + (this.build_path_spec(right));
289
- case NodeTypes.STAR:
290
- return this.build_path_spec(left, true);
291
- case NodeTypes.SYMBOL:
292
- if (wildcard === true) {
293
- return "" + (left[0] === '*' ? '' : '*') + left;
294
- } else {
295
- return ":" + left;
296
- }
297
- break;
298
- case NodeTypes.SLASH:
299
- case NodeTypes.DOT:
300
- case NodeTypes.LITERAL:
301
- return left;
302
- default:
303
- throw new Error("Unknown Rails node type");
304
- }
305
- },
306
- visit_globbing: function(route, parameters, optional) {
307
- var left, right, type, value;
308
- type = route[0], left = route[1], right = route[2];
309
- if (left.replace(/^\*/i, "") !== left) {
310
- route[1] = left = left.replace(/^\*/i, "");
311
- }
312
- value = parameters[left];
313
- if (value == null) {
314
- return this.visit(route, parameters, optional);
315
- }
316
- parameters[left] = (function() {
317
- switch (this.get_object_type(value)) {
318
- case "array":
319
- return value.join("/");
320
- default:
321
- return value;
322
- }
323
- }).call(this);
324
- return this.visit(route, parameters, optional);
325
- },
326
- get_prefix: function() {
327
- var prefix;
328
- prefix = this.configuration.prefix;
329
- if (prefix !== "") {
330
- prefix = (prefix.match("/$") ? prefix : prefix + "/");
331
- }
332
- return prefix;
333
- },
334
- route: function(parts_table, default_options, route_spec, full_url) {
335
- var j, len, part, parts, path_fn, ref, required, required_parts;
336
- required_parts = [];
337
- parts = [];
338
- for (j = 0, len = parts_table.length; j < len; j++) {
339
- ref = parts_table[j], part = ref[0], required = ref[1];
340
- parts.push(part);
341
- if (required) {
342
- required_parts.push(part);
343
- }
344
- }
345
- path_fn = function() {
346
- return Utils.build_route(parts, required_parts, default_options, route_spec, full_url, arguments);
347
- };
348
- path_fn.required_params = required_parts;
349
- path_fn.toString = function() {
350
- return Utils.build_path_spec(route_spec);
351
- };
352
- return path_fn;
353
- },
354
- route_url: function(route_defaults) {
355
- var hostname, port, protocol;
356
- if (typeof route_defaults === 'string') {
357
- return route_defaults;
358
- }
359
- hostname = route_defaults.host || Utils.current_host();
360
- if (!hostname) {
361
- return '';
362
- }
363
- protocol = route_defaults.protocol || Utils.current_protocol();
364
- port = route_defaults.port || (!route_defaults.host ? Utils.current_port() : void 0);
365
- port = port ? ":" + port : '';
366
- return protocol + "://" + hostname + port;
367
- },
368
- has_location: function() {
369
- return (typeof window !== "undefined" && window !== null ? window.location : void 0) != null;
370
- },
371
- current_host: function() {
372
- if (this.has_location()) {
373
- return window.location.hostname;
374
- } else {
375
- return null;
376
- }
377
- },
378
- current_protocol: function() {
379
- if (this.has_location() && window.location.protocol !== '') {
380
- return window.location.protocol.replace(/:$/, '');
381
- } else {
382
- return 'http';
383
- }
384
- },
385
- current_port: function() {
386
- if (this.has_location() && window.location.port !== '') {
387
- return window.location.port;
388
- } else {
389
- return '';
390
- }
391
- },
392
- _classToTypeCache: null,
393
- _classToType: function() {
394
- var j, len, name, ref;
395
- if (this._classToTypeCache != null) {
396
- return this._classToTypeCache;
397
- }
398
- this._classToTypeCache = {};
399
- ref = "Boolean Number String Function Array Date RegExp Object Error".split(" ");
400
- for (j = 0, len = ref.length; j < len; j++) {
401
- name = ref[j];
402
- this._classToTypeCache["[object " + name + "]"] = name.toLowerCase();
403
- }
404
- return this._classToTypeCache;
405
- },
406
- get_object_type: function(obj) {
407
- if (root.jQuery && (root.jQuery.type != null)) {
408
- return root.jQuery.type(obj);
409
- }
410
- if (obj == null) {
411
- return "" + obj;
412
- }
413
- if (typeof obj === "object" || typeof obj === "function") {
414
- return this._classToType()[Object.prototype.toString.call(obj)] || "object";
415
- } else {
416
- return typeof obj;
417
- }
418
- },
419
- indexOf: function(array, element) {
420
- if (Array.prototype.indexOf) {
421
- return array.indexOf(element);
422
- } else {
423
- return this.indexOfImplementation(array, element);
424
- }
425
- },
426
- indexOfImplementation: function(array, element) {
427
- var el, i, j, len, result;
428
- result = -1;
429
- for (i = j = 0, len = array.length; j < len; i = ++j) {
430
- el = array[i];
431
- if (el === element) {
432
- result = i;
433
- }
434
- }
435
- return result;
436
- },
437
- namespace: function(root, namespace, routes) {
438
- var index, j, len, part, parts;
439
- parts = namespace.split(".");
440
- if (parts.length === 0) {
441
- return routes;
442
- }
443
- for (index = j = 0, len = parts.length; j < len; index = ++j) {
444
- part = parts[index];
445
- if (index < parts.length - 1) {
446
- root = (root[part] || (root[part] = {}));
447
- } else {
448
- return root[part] = routes;
449
- }
450
- }
451
- },
452
- configure: function(new_config) {
453
- return this.configuration = this.merge(this.configuration, new_config);
454
- },
455
- config: function() {
456
- return this.clone(this.configuration);
457
- },
458
- make: function() {
459
- var routes;
460
- routes = ROUTES;
461
- routes.configure = function(config) {
462
- return Utils.configure(config);
463
- };
464
- routes.config = function() {
465
- return Utils.config();
466
- };
467
- Object.defineProperty(routes, 'defaults', {
468
- get: function() {
469
- throw new Error(NAMESPACE + ".defaults is removed. Use " + NAMESPACE + ".configure() instead.");
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
+ define(routes) {
22
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
23
+ module.exports = routes;
24
+ },
25
+ isSupported() {
26
+ return typeof module === "object";
27
+ },
470
28
  },
471
- set: function(value) {}
472
- });
473
- routes.default_serializer = function(object, prefix) {
474
- return Utils.default_serializer(object, prefix);
475
- };
476
- return Utils.namespace(root, NAMESPACE, routes);
29
+ AMD: {
30
+ define(routes) {
31
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
32
+ define([], function () {
33
+ return routes;
34
+ });
35
+ },
36
+ isSupported() {
37
+ return typeof define === "function" && !!define.amd;
38
+ },
39
+ },
40
+ UMD: {
41
+ define(routes) {
42
+ if (ModuleReferences.AMD.isSupported()) {
43
+ ModuleReferences.AMD.define(routes);
44
+ }
45
+ else {
46
+ if (ModuleReferences.CJS.isSupported()) {
47
+ try {
48
+ ModuleReferences.CJS.define(routes);
49
+ }
50
+ catch (error) {
51
+ if (error.name !== "TypeError")
52
+ throw error;
53
+ }
54
+ }
55
+ }
56
+ },
57
+ isSupported() {
58
+ return (ModuleReferences.AMD.isSupported() ||
59
+ ModuleReferences.CJS.isSupported());
60
+ },
61
+ },
62
+ ESM: {
63
+ define() {
64
+ // Module can only be defined using ruby code generation
65
+ },
66
+ isSupported() {
67
+ // Its impossible to check if "export" keyword is supported
68
+ return true;
69
+ },
70
+ },
71
+ NIL: {
72
+ define(routes) {
73
+ Utils.namespace(Root, RubyVariables.NAMESPACE, routes);
74
+ },
75
+ isSupported() {
76
+ return !!Root;
77
+ },
78
+ },
79
+ DTS: {
80
+ // Acts the same as ESM
81
+ define(routes) {
82
+ ModuleReferences.ESM.define(routes);
83
+ },
84
+ isSupported() {
85
+ return ModuleReferences.ESM.isSupported();
86
+ },
87
+ },
88
+ };
89
+ class ParametersMissing extends Error {
90
+ constructor(...keys) {
91
+ super(`Route missing required keys: ${keys.join(", ")}`);
92
+ this.keys = keys;
93
+ Object.setPrototypeOf(this, Object.getPrototypeOf(this));
94
+ this.name = ParametersMissing.name;
95
+ }
477
96
  }
478
- };
479
-
480
- if (typeof define === "function" && define.amd) {
481
- define([], function() {
482
- return Utils.make();
483
- });
484
- } else {
485
- Utils.make();
486
- }
487
-
488
- }).call(this);
97
+ const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
98
+ const ReservedOptions = [
99
+ "anchor",
100
+ "trailing_slash",
101
+ "subdomain",
102
+ "host",
103
+ "port",
104
+ "protocol",
105
+ ];
106
+ class UtilsClass {
107
+ constructor() {
108
+ this.configuration = {
109
+ prefix: RubyVariables.PREFIX,
110
+ default_url_options: RubyVariables.DEFAULT_URL_OPTIONS,
111
+ special_options_key: RubyVariables.SPECIAL_OPTIONS_KEY,
112
+ serializer: RubyVariables.SERIALIZER || this.default_serializer.bind(this),
113
+ };
114
+ }
115
+ default_serializer(value, prefix) {
116
+ if (this.is_nullable(value)) {
117
+ return "";
118
+ }
119
+ if (!prefix && !this.is_object(value)) {
120
+ throw new Error("Url parameters should be a javascript hash");
121
+ }
122
+ prefix = prefix || "";
123
+ const result = [];
124
+ if (this.is_array(value)) {
125
+ for (const element of value) {
126
+ result.push(this.default_serializer(element, prefix + "[]"));
127
+ }
128
+ }
129
+ else if (this.is_object(value)) {
130
+ for (let key in value) {
131
+ if (!hasProp(value, key))
132
+ continue;
133
+ let prop = value[key];
134
+ if (this.is_nullable(prop) && prefix) {
135
+ prop = "";
136
+ }
137
+ if (this.is_not_nullable(prop)) {
138
+ if (prefix) {
139
+ key = prefix + "[" + key + "]";
140
+ }
141
+ result.push(this.default_serializer(prop, key));
142
+ }
143
+ }
144
+ }
145
+ else {
146
+ if (this.is_not_nullable(value)) {
147
+ result.push(encodeURIComponent(prefix) + "=" + encodeURIComponent("" + value));
148
+ }
149
+ }
150
+ return result.join("&");
151
+ }
152
+ serialize(object) {
153
+ return this.configuration.serializer(object);
154
+ }
155
+ extract_options(number_of_params, args) {
156
+ const last_el = args[args.length - 1];
157
+ if ((args.length > number_of_params && last_el === 0) ||
158
+ (this.is_object(last_el) &&
159
+ !this.looks_like_serialized_model(last_el))) {
160
+ if (this.is_object(last_el)) {
161
+ delete last_el[this.configuration.special_options_key];
162
+ }
163
+ return {
164
+ args: args.slice(0, args.length - 1),
165
+ options: last_el,
166
+ };
167
+ }
168
+ else {
169
+ return { args, options: {} };
170
+ }
171
+ }
172
+ looks_like_serialized_model(object) {
173
+ return (this.is_object(object) &&
174
+ !(this.configuration.special_options_key in object) &&
175
+ ("id" in object || "to_param" in object || "toParam" in object));
176
+ }
177
+ path_identifier(object) {
178
+ const result = this.unwrap_path_identifier(object);
179
+ return this.is_nullable(result) || result === false ? "" : "" + result;
180
+ }
181
+ unwrap_path_identifier(object) {
182
+ let result = object;
183
+ if (!this.is_object(object)) {
184
+ return object;
185
+ }
186
+ if ("to_param" in object) {
187
+ result = object.to_param;
188
+ }
189
+ else if ("toParam" in object) {
190
+ result = object.toParam;
191
+ }
192
+ else if ("id" in object) {
193
+ result = object.id;
194
+ }
195
+ else {
196
+ result = object;
197
+ }
198
+ return this.is_callable(result) ? result.call(object) : result;
199
+ }
200
+ partition_parameters(parts, required_params, default_options, call_arguments) {
201
+ // eslint-disable-next-line prefer-const
202
+ let { args, options } = this.extract_options(parts.length, call_arguments);
203
+ if (args.length > parts.length) {
204
+ throw new Error("Too many parameters provided for path");
205
+ }
206
+ let use_all_parts = args.length > required_params.length;
207
+ const parts_options = {};
208
+ for (const key in options) {
209
+ const value = options[key];
210
+ if (!hasProp(options, key))
211
+ continue;
212
+ use_all_parts = true;
213
+ if (parts.includes(key)) {
214
+ parts_options[key] = value;
215
+ }
216
+ }
217
+ options = {
218
+ ...this.configuration.default_url_options,
219
+ ...default_options,
220
+ ...options,
221
+ };
222
+ const keyword_parameters = {};
223
+ const query_parameters = {};
224
+ for (const key in options) {
225
+ if (!hasProp(options, key))
226
+ continue;
227
+ const value = options[key];
228
+ if (this.is_reserved_option(key)) {
229
+ keyword_parameters[key] = value;
230
+ }
231
+ else {
232
+ if (!this.is_nullable(value) &&
233
+ (value !== default_options[key] || required_params.includes(key))) {
234
+ query_parameters[key] = value;
235
+ }
236
+ }
237
+ }
238
+ const route_parts = use_all_parts ? parts : required_params;
239
+ let i = 0;
240
+ for (const part of route_parts) {
241
+ if (i < args.length) {
242
+ const value = args[i];
243
+ if (!hasProp(parts_options, part)) {
244
+ query_parameters[part] = value;
245
+ ++i;
246
+ }
247
+ }
248
+ }
249
+ return { keyword_parameters, query_parameters };
250
+ }
251
+ build_route(parts, required_params, default_options, route, absolute, args) {
252
+ const { keyword_parameters, query_parameters, } = this.partition_parameters(parts, required_params, default_options, args);
253
+ const missing_params = required_params.filter((param) => !hasProp(query_parameters, param) ||
254
+ this.is_nullable(query_parameters[param]));
255
+ if (missing_params.length) {
256
+ throw new ParametersMissing(...missing_params);
257
+ }
258
+ let result = this.get_prefix() + this.visit(route, query_parameters);
259
+ if (keyword_parameters.trailing_slash) {
260
+ result = result.replace(/(.*?)[/]?$/, "$1/");
261
+ }
262
+ const url_params = this.serialize(query_parameters);
263
+ if (url_params.length) {
264
+ result += "?" + url_params;
265
+ }
266
+ result += keyword_parameters.anchor
267
+ ? "#" + keyword_parameters.anchor
268
+ : "";
269
+ if (absolute) {
270
+ result = this.route_url(keyword_parameters) + result;
271
+ }
272
+ return result;
273
+ }
274
+ visit(route, parameters, optional = false) {
275
+ switch (route[0]) {
276
+ case NodeTypes.GROUP:
277
+ return this.visit(route[1], parameters, true);
278
+ case NodeTypes.CAT:
279
+ return this.visit_cat(route, parameters, optional);
280
+ case NodeTypes.SYMBOL:
281
+ return this.visit_symbol(route, parameters, optional);
282
+ case NodeTypes.STAR:
283
+ return this.visit_globbing(route[1], parameters, true);
284
+ case NodeTypes.LITERAL:
285
+ case NodeTypes.SLASH:
286
+ case NodeTypes.DOT:
287
+ return route[1];
288
+ default:
289
+ throw new Error("Unknown Rails node type");
290
+ }
291
+ }
292
+ is_not_nullable(object) {
293
+ return !this.is_nullable(object);
294
+ }
295
+ is_nullable(object) {
296
+ return object === undefined || object === null;
297
+ }
298
+ visit_cat(
299
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
300
+ [_type, left, right], parameters, optional) {
301
+ const left_part = this.visit(left, parameters, optional);
302
+ let right_part = this.visit(right, parameters, optional);
303
+ if (optional &&
304
+ ((this.is_optional_node(left[0]) && !left_part) ||
305
+ (this.is_optional_node(right[0]) && !right_part))) {
306
+ return "";
307
+ }
308
+ // if left_part ends on '/' and right_part starts on '/'
309
+ if (left_part[left_part.length - 1] === "/" && right_part[0] === "/") {
310
+ // strip slash from right_part
311
+ // to prevent double slash
312
+ right_part = right_part.substring(1);
313
+ }
314
+ return left_part + right_part;
315
+ }
316
+ visit_symbol(
317
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
318
+ [_type, key], parameters, optional) {
319
+ const value = this.path_identifier(parameters[key]);
320
+ delete parameters[key];
321
+ if (value.length) {
322
+ return this.encode_segment(value);
323
+ }
324
+ if (optional) {
325
+ return "";
326
+ }
327
+ else {
328
+ throw new ParametersMissing(key);
329
+ }
330
+ }
331
+ encode_segment(segment) {
332
+ return segment.replace(UriEncoderSegmentRegex, (str) => encodeURIComponent(str));
333
+ }
334
+ is_optional_node(node) {
335
+ return [NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT].includes(node);
336
+ }
337
+ build_path_spec(route, wildcard = false) {
338
+ let key;
339
+ switch (route[0]) {
340
+ case NodeTypes.GROUP:
341
+ return "(" + this.build_path_spec(route[1]) + ")";
342
+ case NodeTypes.CAT:
343
+ return (this.build_path_spec(route[1]) + this.build_path_spec(route[2]));
344
+ case NodeTypes.STAR:
345
+ return this.build_path_spec(route[1], true);
346
+ case NodeTypes.SYMBOL:
347
+ key = route[1];
348
+ if (wildcard) {
349
+ return (key.startsWith("*") ? "" : "*") + key;
350
+ }
351
+ else {
352
+ return ":" + key;
353
+ }
354
+ break;
355
+ case NodeTypes.SLASH:
356
+ case NodeTypes.DOT:
357
+ case NodeTypes.LITERAL:
358
+ return route[1];
359
+ default:
360
+ throw new Error("Unknown Rails node type");
361
+ }
362
+ }
363
+ visit_globbing(route, parameters, optional) {
364
+ const key = route[1];
365
+ let value = parameters[key];
366
+ delete parameters[key];
367
+ if (this.is_nullable(value)) {
368
+ return this.visit(route, parameters, optional);
369
+ }
370
+ if (this.is_array(value)) {
371
+ value = value.join("/");
372
+ }
373
+ const result = this.path_identifier(value);
374
+ return RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR
375
+ ? result
376
+ : encodeURI(result);
377
+ }
378
+ get_prefix() {
379
+ const prefix = this.configuration.prefix;
380
+ return prefix.match("/$")
381
+ ? prefix.substring(0, prefix.length - 1)
382
+ : prefix;
383
+ }
384
+ route(parts_table, route_spec, absolute = false) {
385
+ const required_params = [];
386
+ const parts = [];
387
+ const default_options = {};
388
+ for (const [part, { r: required, d: value }] of Object.entries(parts_table)) {
389
+ parts.push(part);
390
+ if (required) {
391
+ required_params.push(part);
392
+ }
393
+ if (this.is_not_nullable(value)) {
394
+ default_options[part] = value;
395
+ }
396
+ }
397
+ const result = (...args) => {
398
+ return this.build_route(parts, required_params, default_options, route_spec, absolute, args);
399
+ };
400
+ result.requiredParams = () => required_params;
401
+ result.toString = () => {
402
+ return this.build_path_spec(route_spec);
403
+ };
404
+ return result;
405
+ }
406
+ route_url(route_defaults) {
407
+ const hostname = route_defaults.host || this.current_host();
408
+ if (!hostname) {
409
+ return "";
410
+ }
411
+ const subdomain = route_defaults.subdomain
412
+ ? route_defaults.subdomain + "."
413
+ : "";
414
+ const protocol = route_defaults.protocol || this.current_protocol();
415
+ let port = route_defaults.port ||
416
+ (!route_defaults.host ? this.current_port() : undefined);
417
+ port = port ? ":" + port : "";
418
+ return protocol + "://" + subdomain + hostname + port;
419
+ }
420
+ current_host() {
421
+ var _a;
422
+ return ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname) || "";
423
+ }
424
+ current_protocol() {
425
+ var _a, _b;
426
+ return ((_b = (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.protocol) === null || _b === void 0 ? void 0 : _b.replace(/:$/, "")) || "http";
427
+ }
428
+ current_port() {
429
+ var _a;
430
+ return ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.port) || "";
431
+ }
432
+ is_object(value) {
433
+ return (typeof value === "object" &&
434
+ Object.prototype.toString.call(value) === "[object Object]");
435
+ }
436
+ is_array(object) {
437
+ return object instanceof Array;
438
+ }
439
+ is_callable(object) {
440
+ return typeof object === "function" && !!object.call;
441
+ }
442
+ is_reserved_option(key) {
443
+ return ReservedOptions.includes(key);
444
+ }
445
+ namespace(object, namespace, routes) {
446
+ const parts = (namespace === null || namespace === void 0 ? void 0 : namespace.split(".")) || [];
447
+ if (parts.length === 0) {
448
+ return routes;
449
+ }
450
+ for (let index = 0; index < parts.length; index++) {
451
+ const part = parts[index];
452
+ if (index < parts.length - 1) {
453
+ object = object[part] || (object[part] = {});
454
+ }
455
+ else {
456
+ return (object[part] = routes);
457
+ }
458
+ }
459
+ }
460
+ configure(new_config) {
461
+ this.configuration = { ...this.configuration, ...new_config };
462
+ return this.configuration;
463
+ }
464
+ config() {
465
+ return { ...this.configuration };
466
+ }
467
+ is_module_supported(name) {
468
+ return ModuleReferences[name].isSupported();
469
+ }
470
+ ensure_module_supported(name) {
471
+ if (!this.is_module_supported(name)) {
472
+ throw new Error(`${name} is not supported by runtime`);
473
+ }
474
+ }
475
+ define_module(name, module) {
476
+ this.ensure_module_supported(name);
477
+ ModuleReferences[name].define(module);
478
+ }
479
+ }
480
+ const Utils = new UtilsClass();
481
+ // We want this helper name to be short
482
+ const __jsr = {
483
+ r(parts_table, route_spec, absolute) {
484
+ return Utils.route(parts_table, route_spec, absolute);
485
+ },
486
+ };
487
+ const result = {
488
+ ...__jsr,
489
+ configure: (config) => {
490
+ return Utils.configure(config);
491
+ },
492
+ config: () => {
493
+ return Utils.config();
494
+ },
495
+ serialize: (object) => {
496
+ return Utils.serialize(object);
497
+ },
498
+ ...RubyVariables.ROUTES_OBJECT,
499
+ };
500
+ Utils.define_module(RubyVariables.MODULE_TYPE, result);
501
+ return result;
502
+ })(this);