js-routes 2.0.6 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/routes.js CHANGED
@@ -18,25 +18,32 @@ RubyVariables.WRAPPER((that) => {
18
18
  const Root = that;
19
19
  const ModuleReferences = {
20
20
  CJS: {
21
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22
- define: (routes) => (module.exports = routes),
23
- support: () => typeof module === "object",
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
+ },
24
28
  },
25
29
  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,
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
+ },
32
39
  },
33
40
  UMD: {
34
- define: (routes) => {
35
- if (ModuleReferences.AMD.support()) {
41
+ define(routes) {
42
+ if (ModuleReferences.AMD.isSupported()) {
36
43
  ModuleReferences.AMD.define(routes);
37
44
  }
38
45
  else {
39
- if (ModuleReferences.CJS.support()) {
46
+ if (ModuleReferences.CJS.isSupported()) {
40
47
  try {
41
48
  ModuleReferences.CJS.define(routes);
42
49
  }
@@ -47,11 +54,36 @@ RubyVariables.WRAPPER((that) => {
47
54
  }
48
55
  }
49
56
  },
50
- support: () => ModuleReferences.AMD.support() || ModuleReferences.CJS.support(),
57
+ isSupported() {
58
+ return (ModuleReferences.AMD.isSupported() ||
59
+ ModuleReferences.CJS.isSupported());
60
+ },
51
61
  },
52
62
  ESM: {
53
- define: () => null,
54
- support: () => true,
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
+ },
55
87
  },
56
88
  };
57
89
  class ParametersMissing extends Error {
@@ -62,7 +94,6 @@ RubyVariables.WRAPPER((that) => {
62
94
  this.name = ParametersMissing.name;
63
95
  }
64
96
  }
65
- const DeprecatedGlobbingBehavior = RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR;
66
97
  const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
67
98
  const ReservedOptions = [
68
99
  "anchor",
@@ -140,7 +171,7 @@ RubyVariables.WRAPPER((that) => {
140
171
  }
141
172
  looks_like_serialized_model(object) {
142
173
  return (this.is_object(object) &&
143
- !object[this.configuration.special_options_key] &&
174
+ !(this.configuration.special_options_key in object) &&
144
175
  ("id" in object || "to_param" in object || "toParam" in object));
145
176
  }
146
177
  path_identifier(object) {
@@ -298,9 +329,7 @@ RubyVariables.WRAPPER((that) => {
298
329
  }
299
330
  }
300
331
  encode_segment(segment) {
301
- return segment.replace(UriEncoderSegmentRegex, function (str) {
302
- return encodeURIComponent(str);
303
- });
332
+ return segment.replace(UriEncoderSegmentRegex, (str) => encodeURIComponent(str));
304
333
  }
305
334
  is_optional_node(node) {
306
335
  return [NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT].includes(node);
@@ -342,7 +371,9 @@ RubyVariables.WRAPPER((that) => {
342
371
  value = value.join("/");
343
372
  }
344
373
  const result = this.path_identifier(value);
345
- return DeprecatedGlobbingBehavior ? result : encodeURI(result);
374
+ return RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR
375
+ ? result
376
+ : encodeURI(result);
346
377
  }
347
378
  get_prefix() {
348
379
  const prefix = this.configuration.prefix;
@@ -386,32 +417,17 @@ RubyVariables.WRAPPER((that) => {
386
417
  port = port ? ":" + port : "";
387
418
  return protocol + "://" + subdomain + hostname + port;
388
419
  }
389
- has_location() {
390
- return this.is_not_nullable(window) && !!window.location;
391
- }
392
420
  current_host() {
393
- if (this.has_location()) {
394
- return window.location.hostname;
395
- }
396
- else {
397
- return null;
398
- }
421
+ var _a;
422
+ return ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname) || "";
399
423
  }
400
424
  current_protocol() {
401
- if (this.has_location() && window.location.protocol !== "") {
402
- return window.location.protocol.replace(/:$/, "");
403
- }
404
- else {
405
- return "http";
406
- }
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";
407
427
  }
408
428
  current_port() {
409
- if (this.has_location() && window.location.port !== "") {
410
- return window.location.port;
411
- }
412
- else {
413
- return "";
414
- }
429
+ var _a;
430
+ return ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.port) || "";
415
431
  }
416
432
  is_object(value) {
417
433
  return (typeof value === "object" &&
@@ -449,7 +465,7 @@ RubyVariables.WRAPPER((that) => {
449
465
  return { ...this.configuration };
450
466
  }
451
467
  is_module_supported(name) {
452
- return ModuleReferences[name].support();
468
+ return ModuleReferences[name].isSupported();
453
469
  }
454
470
  ensure_module_supported(name) {
455
471
  if (!this.is_module_supported(name)) {
@@ -457,9 +473,6 @@ RubyVariables.WRAPPER((that) => {
457
473
  }
458
474
  }
459
475
  define_module(name, module) {
460
- if (!name) {
461
- return;
462
- }
463
476
  this.ensure_module_supported(name);
464
477
  ModuleReferences[name].define(module);
465
478
  }
@@ -484,10 +497,6 @@ RubyVariables.WRAPPER((that) => {
484
497
  },
485
498
  ...RubyVariables.ROUTES_OBJECT,
486
499
  };
487
- Utils.namespace(Root, RubyVariables.NAMESPACE, result);
488
- if (RubyVariables.MODULE_TYPE) {
489
- Utils.define_module(RubyVariables.MODULE_TYPE, result);
490
- }
500
+ Utils.define_module(RubyVariables.MODULE_TYPE, result);
491
501
  return result;
492
502
  })(this);
493
- //# sourceMappingURL=routes.js.map
data/lib/routes.ts CHANGED
@@ -3,15 +3,51 @@
3
3
  * Based on Rails RubyVariables.RAILS_VERSION routes of RubyVariables.APP_CLASS
4
4
  */
5
5
 
6
- type RouteParameter = unknown;
7
- type RouteParameters = Record<string, RouteParameter>;
8
- type Serializer = (value: unknown) => string;
9
- type RouteHelper = {
10
- (...args: RouteParameter[]): string;
6
+ type Optional<T> = { [P in keyof T]?: T[P] | null };
7
+ type BaseRouteParameter = string | boolean | Date | number;
8
+ type MethodRouteParameter = BaseRouteParameter | (() => BaseRouteParameter);
9
+ type ModelRouteParameter =
10
+ | { id: MethodRouteParameter }
11
+ | { to_param: MethodRouteParameter }
12
+ | { toParam: MethodRouteParameter };
13
+ type RequiredRouteParameter = BaseRouteParameter | ModelRouteParameter;
14
+ type OptionalRouteParameter = undefined | null | RequiredRouteParameter;
15
+ type QueryRouteParameter =
16
+ | OptionalRouteParameter
17
+ | QueryRouteParameter[]
18
+ | { [k: string]: QueryRouteParameter };
19
+ type RouteParameters = Record<string, QueryRouteParameter>;
20
+
21
+ type Serializable = Record<string, unknown>;
22
+ type Serializer = (value: Serializable) => string;
23
+ type RouteHelperExtras = {
11
24
  requiredParams(): string[];
12
25
  toString(): string;
13
26
  };
14
27
 
28
+ type RequiredParameters<T extends number> = T extends 1
29
+ ? [RequiredRouteParameter]
30
+ : T extends 2
31
+ ? [RequiredRouteParameter, RequiredRouteParameter]
32
+ : T extends 3
33
+ ? [RequiredRouteParameter, RequiredRouteParameter, RequiredRouteParameter]
34
+ : T extends 4
35
+ ? [
36
+ RequiredRouteParameter,
37
+ RequiredRouteParameter,
38
+ RequiredRouteParameter,
39
+ RequiredRouteParameter
40
+ ]
41
+ : RequiredRouteParameter[];
42
+
43
+ type RouteHelperOptions<T extends string> = RouteOptions &
44
+ Optional<Record<T, OptionalRouteParameter>>;
45
+
46
+ type RouteHelper<T extends number = number, U extends string = string> = ((
47
+ ...args: [...RequiredParameters<T>, RouteHelperOptions<U>]
48
+ ) => string) &
49
+ RouteHelperExtras;
50
+
15
51
  type RouteHelpers = Record<string, RouteHelper>;
16
52
 
17
53
  type Configuration = {
@@ -21,7 +57,6 @@ type Configuration = {
21
57
  serializer: Serializer;
22
58
  };
23
59
 
24
- type Optional<T> = { [P in keyof T]?: T[P] | null };
25
60
  interface RouterExposedMethods {
26
61
  config(): Configuration;
27
62
  configure(arg: Partial<Configuration>): Configuration;
@@ -32,14 +67,16 @@ type KeywordUrlOptions = Optional<{
32
67
  host: string;
33
68
  protocol: string;
34
69
  subdomain: string;
35
- port: string;
70
+ port: string | number;
36
71
  anchor: string;
37
72
  trailing_slash: boolean;
38
73
  }>;
39
74
 
40
- type PartsTable = Record<string, { r?: boolean; d?: unknown }>;
75
+ type RouteOptions = KeywordUrlOptions & RouteParameters;
41
76
 
42
- type ModuleType = "CJS" | "AMD" | "UMD" | "ESM";
77
+ type PartsTable = Record<string, { r?: boolean; d?: OptionalRouteParameter }>;
78
+
79
+ type ModuleType = "CJS" | "AMD" | "UMD" | "ESM" | "DTS" | "NIL";
43
80
 
44
81
  declare const RubyVariables: {
45
82
  PREFIX: string;
@@ -49,7 +86,7 @@ declare const RubyVariables: {
49
86
  SERIALIZER: Serializer;
50
87
  NAMESPACE: string;
51
88
  ROUTES_OBJECT: RouteHelpers;
52
- MODULE_TYPE: ModuleType | null;
89
+ MODULE_TYPE: ModuleType;
53
90
  WRAPPER: <T>(callback: T) => T;
54
91
  };
55
92
 
@@ -93,29 +130,36 @@ RubyVariables.WRAPPER(
93
130
 
94
131
  const Root = that;
95
132
  type ModuleDefinition = {
96
- define: (routes: unknown) => void;
97
- support: () => boolean;
133
+ define: (routes: RouterExposedMethods) => void;
134
+ isSupported: () => boolean;
98
135
  };
99
136
  const ModuleReferences: Record<ModuleType, ModuleDefinition> = {
100
137
  CJS: {
101
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102
- define: (routes) => (module!.exports = routes),
103
- support: () => typeof module === "object",
138
+ define(routes) {
139
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
140
+ module!.exports = routes;
141
+ },
142
+ isSupported() {
143
+ return typeof module === "object";
144
+ },
104
145
  },
105
146
  AMD: {
106
- define: (routes) =>
147
+ define(routes) {
107
148
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
108
149
  define!([], function () {
109
150
  return routes;
110
- }),
111
- support: () => typeof define === "function" && !!define.amd,
151
+ });
152
+ },
153
+ isSupported() {
154
+ return typeof define === "function" && !!define.amd;
155
+ },
112
156
  },
113
157
  UMD: {
114
- define: (routes) => {
115
- if (ModuleReferences.AMD.support()) {
158
+ define(routes) {
159
+ if (ModuleReferences.AMD.isSupported()) {
116
160
  ModuleReferences.AMD.define(routes);
117
161
  } else {
118
- if (ModuleReferences.CJS.support()) {
162
+ if (ModuleReferences.CJS.isSupported()) {
119
163
  try {
120
164
  ModuleReferences.CJS.define(routes);
121
165
  } catch (error) {
@@ -124,12 +168,38 @@ RubyVariables.WRAPPER(
124
168
  }
125
169
  }
126
170
  },
127
- support: () =>
128
- ModuleReferences.AMD.support() || ModuleReferences.CJS.support(),
171
+ isSupported() {
172
+ return (
173
+ ModuleReferences.AMD.isSupported() ||
174
+ ModuleReferences.CJS.isSupported()
175
+ );
176
+ },
129
177
  },
130
178
  ESM: {
131
- define: () => null,
132
- support: () => true,
179
+ define() {
180
+ // Module can only be defined using ruby code generation
181
+ },
182
+ isSupported() {
183
+ // Its impossible to check if "export" keyword is supported
184
+ return true;
185
+ },
186
+ },
187
+ NIL: {
188
+ define(routes) {
189
+ Utils.namespace(Root, RubyVariables.NAMESPACE, routes);
190
+ },
191
+ isSupported() {
192
+ return !!Root;
193
+ },
194
+ },
195
+ DTS: {
196
+ // Acts the same as ESM
197
+ define(routes) {
198
+ ModuleReferences.ESM.define(routes);
199
+ },
200
+ isSupported() {
201
+ return ModuleReferences.ESM.isSupported();
202
+ },
133
203
  },
134
204
  };
135
205
 
@@ -143,9 +213,6 @@ RubyVariables.WRAPPER(
143
213
  }
144
214
  }
145
215
 
146
- const DeprecatedGlobbingBehavior =
147
- RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR;
148
-
149
216
  const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
150
217
 
151
218
  const ReservedOptions = [
@@ -204,16 +271,16 @@ RubyVariables.WRAPPER(
204
271
  return result.join("&");
205
272
  }
206
273
 
207
- serialize(object: unknown): string {
274
+ serialize(object: Serializable): string {
208
275
  return this.configuration.serializer(object);
209
276
  }
210
277
 
211
278
  extract_options(
212
279
  number_of_params: number,
213
- args: RouteParameter[]
280
+ args: OptionalRouteParameter[]
214
281
  ): {
215
- args: RouteParameter[];
216
- options: KeywordUrlOptions & RouteParameters;
282
+ args: OptionalRouteParameter[];
283
+ options: RouteOptions;
217
284
  } {
218
285
  const last_el = args[args.length - 1];
219
286
  if (
@@ -226,32 +293,27 @@ RubyVariables.WRAPPER(
226
293
  }
227
294
  return {
228
295
  args: args.slice(0, args.length - 1),
229
- options: last_el as KeywordUrlOptions & RouteParameters,
296
+ options: (last_el as any) as RouteOptions,
230
297
  };
231
298
  } else {
232
299
  return { args, options: {} };
233
300
  }
234
301
  }
235
302
 
236
- looks_like_serialized_model(
237
- object: any
238
- ): object is
239
- | { id: unknown }
240
- | { to_param: unknown }
241
- | { toParam: unknown } {
303
+ looks_like_serialized_model(object: any): object is ModelRouteParameter {
242
304
  return (
243
305
  this.is_object(object) &&
244
- !object[this.configuration.special_options_key] &&
306
+ !(this.configuration.special_options_key in object) &&
245
307
  ("id" in object || "to_param" in object || "toParam" in object)
246
308
  );
247
309
  }
248
310
 
249
- path_identifier(object: unknown): string {
311
+ path_identifier(object: QueryRouteParameter): string {
250
312
  const result = this.unwrap_path_identifier(object);
251
313
  return this.is_nullable(result) || result === false ? "" : "" + result;
252
314
  }
253
315
 
254
- unwrap_path_identifier(object: any): unknown {
316
+ unwrap_path_identifier(object: QueryRouteParameter): unknown {
255
317
  let result: any = object;
256
318
  if (!this.is_object(object)) {
257
319
  return object;
@@ -272,7 +334,7 @@ RubyVariables.WRAPPER(
272
334
  parts: string[],
273
335
  required_params: string[],
274
336
  default_options: RouteParameters,
275
- call_arguments: RouteParameter[]
337
+ call_arguments: OptionalRouteParameter[]
276
338
  ): {
277
339
  keyword_parameters: KeywordUrlOptions;
278
340
  query_parameters: RouteParameters;
@@ -336,7 +398,7 @@ RubyVariables.WRAPPER(
336
398
  default_options: RouteParameters,
337
399
  route: RouteTree,
338
400
  absolute: boolean,
339
- args: RouteParameter[]
401
+ args: OptionalRouteParameter[]
340
402
  ): string {
341
403
  const {
342
404
  keyword_parameters,
@@ -446,9 +508,9 @@ RubyVariables.WRAPPER(
446
508
  }
447
509
 
448
510
  encode_segment(segment: string): string {
449
- return segment.replace(UriEncoderSegmentRegex, function (str) {
450
- return encodeURIComponent(str);
451
- });
511
+ return segment.replace(UriEncoderSegmentRegex, (str) =>
512
+ encodeURIComponent(str)
513
+ );
452
514
  }
453
515
 
454
516
  is_optional_node(node: NodeTypes): boolean {
@@ -498,7 +560,9 @@ RubyVariables.WRAPPER(
498
560
  value = value.join("/");
499
561
  }
500
562
  const result = this.path_identifier(value as any);
501
- return DeprecatedGlobbingBehavior ? result : encodeURI(result);
563
+ return RubyVariables.DEPRECATED_GLOBBING_BEHAVIOR
564
+ ? result
565
+ : encodeURI(result);
502
566
  }
503
567
 
504
568
  get_prefix(): string {
@@ -527,7 +591,7 @@ RubyVariables.WRAPPER(
527
591
  default_options[part] = value;
528
592
  }
529
593
  }
530
- const result = (...args: RouteParameter[]): string => {
594
+ const result = (...args: OptionalRouteParameter[]): string => {
531
595
  return this.build_route(
532
596
  parts,
533
597
  required_params,
@@ -541,7 +605,7 @@ RubyVariables.WRAPPER(
541
605
  result.toString = () => {
542
606
  return this.build_path_spec(route_spec);
543
607
  };
544
- return result;
608
+ return result as any;
545
609
  }
546
610
 
547
611
  route_url(route_defaults: KeywordUrlOptions): string {
@@ -560,31 +624,16 @@ RubyVariables.WRAPPER(
560
624
  return protocol + "://" + subdomain + hostname + port;
561
625
  }
562
626
 
563
- has_location(): boolean {
564
- return this.is_not_nullable(window) && !!window.location;
565
- }
566
-
567
- current_host(): string | null {
568
- if (this.has_location()) {
569
- return window.location.hostname;
570
- } else {
571
- return null;
572
- }
627
+ current_host(): string {
628
+ return window?.location?.hostname || "";
573
629
  }
574
630
 
575
631
  current_protocol(): string {
576
- if (this.has_location() && window.location.protocol !== "") {
577
- return window.location.protocol.replace(/:$/, "");
578
- } else {
579
- return "http";
580
- }
632
+ return window?.location?.protocol?.replace(/:$/, "") || "http";
581
633
  }
634
+
582
635
  current_port(): string {
583
- if (this.has_location() && window.location.port !== "") {
584
- return window.location.port;
585
- } else {
586
- return "";
587
- }
636
+ return window?.location?.port || "";
588
637
  }
589
638
 
590
639
  is_object(value: unknown): value is Record<string, unknown> {
@@ -635,7 +684,7 @@ RubyVariables.WRAPPER(
635
684
  }
636
685
 
637
686
  is_module_supported(name: ModuleType): boolean {
638
- return ModuleReferences[name].support();
687
+ return ModuleReferences[name].isSupported();
639
688
  }
640
689
 
641
690
  ensure_module_supported(name: ModuleType): void {
@@ -644,13 +693,7 @@ RubyVariables.WRAPPER(
644
693
  }
645
694
  }
646
695
 
647
- define_module(
648
- name: ModuleType | null,
649
- module: RouterExposedMethods
650
- ): void {
651
- if (!name) {
652
- return;
653
- }
696
+ define_module(name: ModuleType, module: RouterExposedMethods): void {
654
697
  this.ensure_module_supported(name);
655
698
  ModuleReferences[name].define(module);
656
699
  }
@@ -677,17 +720,13 @@ RubyVariables.WRAPPER(
677
720
  config: (): Configuration => {
678
721
  return Utils.config();
679
722
  },
680
- serialize: (object: unknown): string => {
723
+ serialize: (object: Serializable): string => {
681
724
  return Utils.serialize(object);
682
725
  },
683
726
  ...RubyVariables.ROUTES_OBJECT,
684
727
  };
685
728
 
686
- Utils.namespace(Root, RubyVariables.NAMESPACE, result);
687
-
688
- if (RubyVariables.MODULE_TYPE) {
689
- Utils.define_module(RubyVariables.MODULE_TYPE, result);
690
- }
729
+ Utils.define_module(RubyVariables.MODULE_TYPE, result);
691
730
  return result;
692
731
  }
693
732
  )(this);
@@ -1,8 +1,14 @@
1
1
  namespace :js do
2
- desc "Make a js file that will have functions that will return restful routes/urls."
2
+ desc "Make a js file with all rails route URL helpers"
3
3
  task routes: :environment do
4
4
  require "js-routes"
5
-
6
5
  JsRoutes.generate!
7
6
  end
7
+
8
+ namespace :routes do
9
+ desc "Make a js file with all rails route URL helpers and typescript definitions for them"
10
+ task typescript: "js:routes" do
11
+ JsRoutes.definitions!
12
+ end
13
+ end
8
14
  end
@@ -0,0 +1,11 @@
1
+ module.exports = {
2
+ module: {
3
+ rules: [
4
+ {
5
+ test: /\.erb$/,
6
+ enforce: 'pre',
7
+ loader: 'rails-erb-loader'
8
+ },
9
+ ]
10
+ }
11
+ };
@@ -0,0 +1,5 @@
1
+ JsRoutes.setup do |c|
2
+ # Setup your JS module system:
3
+ # ESM, CJS, AMD, UMD or nil
4
+ # c.module_type = "ESM"
5
+ end
@@ -0,0 +1 @@
1
+ <%= JsRoutes.generate %>
data/package.json CHANGED
@@ -21,6 +21,7 @@
21
21
  "prettier": "^2.2.1"
22
22
  },
23
23
  "scripts": {
24
+ "build": "tsc && yarn lint:fix",
24
25
  "lint:fix": "yarn eslint --fix && yarn prettier --write lib/routes.ts",
25
26
  "postinstall": "yarn husky-upgrade"
26
27
  },
@@ -30,7 +31,7 @@
30
31
  }
31
32
  },
32
33
  "lint-staged": {
33
- "*.ts": ["yarn lint:fix" ]
34
+ "./lib/routes.ts": ["yarn lint:fix" ]
34
35
  }
35
36
 
36
37
  }