@koine/next 1.0.66 → 1.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config/index.d.ts CHANGED
@@ -4,6 +4,11 @@ declare type Route = string | {
4
4
  [key: string]: Route | string;
5
5
  };
6
6
  declare type Routes = Record<string, Route>;
7
+ declare type RoutesMapRoute = {
8
+ template: string;
9
+ pathname: string;
10
+ wildcard?: boolean;
11
+ };
7
12
  /**
8
13
  * Normalise pathname
9
14
  *
@@ -34,14 +39,14 @@ export declare function encodePathname(pathname?: string): string;
34
39
  /**
35
40
  * Get path rewrite
36
41
  */
37
- export declare function getPathRewrite(pathname: string, template: string): {
42
+ export declare function getPathRewrite(route: RoutesMapRoute): {
38
43
  source: string;
39
44
  destination: string;
40
45
  };
41
46
  /**
42
47
  * Get path redirect
43
48
  */
44
- export declare function getPathRedirect(locale: string | undefined, pathname: string, template: string, permanent?: boolean): {
49
+ export declare function getPathRedirect(locale: string | undefined, route: RoutesMapRoute, permanent?: boolean): {
45
50
  source: string;
46
51
  destination: string;
47
52
  permanent: boolean;
@@ -89,12 +94,34 @@ declare type KoineNextConfig = {
89
94
  * }
90
95
  * ```
91
96
  *
97
+ * Here we also account for wildcards, those should only be defined in the
98
+ * pathname part of the JSON file, e.g.:
99
+ *
100
+ * ```json
101
+ * {
102
+ * "category": {
103
+ * "[slug]": {
104
+ * "[id]": "/categories/{{ slug }}/{{ id* }}"
105
+ * }
106
+ * }
107
+ * }
108
+ * ```
109
+ * This might be desired when we want to have param-based pagination, e.g. when
110
+ * we have the following folder structure:
111
+ *
112
+ * ```yml
113
+ * |__/category
114
+ * |__/[slug]
115
+ * |__/[id]
116
+ * |__/[[...page]].tsx
117
+ * ```
118
+ *
92
119
  * NOTE1:
93
120
  * You cannot name your dynamic template file "index.tsx" when they have nested
94
121
  * segments or the rewrites won't work. So while this is allowed:
95
122
  * `/pages/cats/[category]/index.tsx` it is not when you also have e.g.:
96
123
  * `/pages/cats/[category]/reviews.tsx`
97
- * TODO: This might be fixable?
124
+ * TODO: This might be fixable? Is this fixed now?
98
125
  *
99
126
  * NOTE2:
100
127
  * When `routes` is used be sure to pass before than the `i18n.defaultLocale`
package/config/index.js CHANGED
@@ -52,47 +52,52 @@ export function encodePathname(pathname) {
52
52
  .join("/");
53
53
  }
54
54
  /**
55
- * It replaces `/{{ slug }}/` with the given replacer.
55
+ * Transform the route translated defintion into a `pathname` and a `template`.
56
+ *
57
+ * Here we add the wildcard flag maybe found in the pathname to the template
58
+ * name too, this is because we do not want to have the wildcard in the JSON
59
+ * keys as those are also used to construct the links through `useTo` hook and
60
+ * handling asterisks there might become cumbersome.
61
+ *
62
+ * @see https://nextjs.org/docs/messages/invalid-multi-match
56
63
  */
57
- function transformRoutePathname(rawPathname) {
58
- var pathNameParts = rawPathname.split("/").filter(function (part) { return !!part; });
59
- return pathNameParts
60
- .map(function (part, _idx) {
61
- var _a;
64
+ function transformRoute(route) {
65
+ var rawPathname = route.pathname, rawTemplate = route.template;
66
+ var pathnameParts = rawPathname.split("/").filter(function (part) { return !!part; });
67
+ var templateParts = rawTemplate.split("/").filter(function (part) { return !!part; });
68
+ var mapPartsByIdx = {};
69
+ var pathname = pathnameParts
70
+ .map(function (part) {
71
+ var _a, _b;
62
72
  var isDynamic = part.startsWith("{{") && part.endsWith("}}");
63
- var replacer = isDynamic
64
- ? ":".concat((_a = part.match(/{{(.+)}}/)) === null || _a === void 0 ? void 0 : _a[1].trim())
65
- : "";
66
- part = isDynamic ? replacer : part;
67
- // if (isDynamic && _idx === pathNameParts.length - 1) {
68
- // part += "*";
69
- // }
70
- return isDynamic ? part : encodeURIComponent(part);
73
+ var asValue = isDynamic
74
+ ? (_b = (_a = part.match(/{{(.+)}}/)) === null || _a === void 0 ? void 0 : _a[1].trim()) !== null && _b !== void 0 ? _b : ""
75
+ : part.trim();
76
+ var hasWildcard = part.includes("*");
77
+ var asPath = encodeURIComponent(asValue.replace("*", "")) + (hasWildcard ? "*" : "");
78
+ mapPartsByIdx[asValue.replace("*", "")] = {
79
+ isDynamic: isDynamic,
80
+ hasWildcard: hasWildcard,
81
+ };
82
+ return isDynamic ? ":".concat(asPath) : asPath;
71
83
  })
72
84
  .join("/");
73
- }
74
- /**
75
- * It replaces `/[slug]/` with the given replacer.
76
- */
77
- function transformRouteTemplate(rawPathname) {
78
- var pathNameParts = rawPathname.split("/").filter(function (part) { return !!part; });
79
- return pathNameParts
80
- .map(function (part, _idx) {
81
- var _a;
85
+ var template = templateParts
86
+ .map(function (part) {
87
+ var _a, _b, _c;
82
88
  var isDynamic = part.startsWith("[") && part.endsWith("]");
83
- var replacer = isDynamic
84
- ? ":".concat((_a = part.match(/\[(.+)\]/)) === null || _a === void 0 ? void 0 : _a[1].trim())
85
- : "";
86
- part = isDynamic ? replacer : part;
87
- // if (isDynamic && _idx === pathNameParts.length - 1) {
88
- // part += "*";
89
- // }
90
- return isDynamic ? part : encodeURIComponent(part);
89
+ var asValue = isDynamic
90
+ ? (_b = (_a = part.match(/\[(.+)\]/)) === null || _a === void 0 ? void 0 : _a[1].trim()) !== null && _b !== void 0 ? _b : ""
91
+ : part.trim();
92
+ var hasWildcard = (_c = mapPartsByIdx[asValue]) === null || _c === void 0 ? void 0 : _c.hasWildcard;
93
+ var asPath = encodeURIComponent(asValue.replace("*", "")) + (hasWildcard ? "*" : "");
94
+ return isDynamic ? ":".concat(asPath) : asPath;
91
95
  })
92
96
  .join("/");
97
+ return { pathname: pathname, template: template };
93
98
  }
94
99
  /**
95
- * Get flat key/value routes map dictionary
100
+ * Get routes map dictionary
96
101
  */
97
102
  function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
98
103
  if (map === void 0) { map = {}; }
@@ -102,7 +107,11 @@ function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
102
107
  var pathOrNestedRoutes = routes[key];
103
108
  var template = "".concat(templateBuffer, "/").concat(key);
104
109
  if (typeof pathOrNestedRoutes === "string") {
105
- map[template] = pathOrNestedRoutes;
110
+ map[template] = {
111
+ template: template,
112
+ pathname: pathOrNestedRoutes,
113
+ wildcard: pathOrNestedRoutes.includes("*"),
114
+ };
106
115
  }
107
116
  else {
108
117
  getRoutesMap(map, pathOrNestedRoutes, pathnameBuffer, template);
@@ -113,9 +122,8 @@ function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
113
122
  /**
114
123
  * Get path rewrite
115
124
  */
116
- export function getPathRewrite(pathname, template) {
117
- pathname = transformRoutePathname(pathname);
118
- template = transformRouteTemplate(template);
125
+ export function getPathRewrite(route) {
126
+ var _a = transformRoute(route), pathname = _a.pathname, template = _a.template;
119
127
  var source = "/".concat(normaliseUrlPathname(pathname));
120
128
  var destination = "/".concat(normaliseUrlPathname(template));
121
129
  // console.log(`rewrite pathname "${source}" to template "${destination}"`);
@@ -127,10 +135,9 @@ export function getPathRewrite(pathname, template) {
127
135
  /**
128
136
  * Get path redirect
129
137
  */
130
- export function getPathRedirect(locale, pathname, template, permanent) {
138
+ export function getPathRedirect(locale, route, permanent) {
131
139
  if (locale === void 0) { locale = ""; }
132
- template = transformRouteTemplate(template);
133
- pathname = transformRoutePathname(pathname);
140
+ var _a = transformRoute(route), template = _a.template, pathname = _a.pathname;
134
141
  var source = "/".concat(normaliseUrlPathname((locale ? "/".concat(locale, "/") : "/") + template));
135
142
  var destination = "/".concat(normaliseUrlPathname(pathname));
136
143
  // console.log(`redirect template "${source}" to pathname "${destination}"`);
@@ -150,10 +157,10 @@ export function getRedirects(defaultLocale, routes, permanent, debug) {
150
157
  redirects = [];
151
158
  routesMap = getRoutesMap({}, routes);
152
159
  Object.keys(routesMap).forEach(function (template) {
153
- var pathname = routesMap[template];
154
- if (pathname !== template) {
155
- redirects.push(getPathRedirect(defaultLocale, pathname, template, permanent));
156
- redirects.push(getPathRedirect("", pathname, template, permanent));
160
+ var route = routesMap[template];
161
+ if (route.pathname !== template) {
162
+ redirects.push(getPathRedirect(defaultLocale, route, permanent));
163
+ redirects.push(getPathRedirect("", route, permanent));
157
164
  }
158
165
  });
159
166
  if (debug)
@@ -171,9 +178,9 @@ export function getRewrites(routes, debug) {
171
178
  rewrites = [];
172
179
  routesMap = getRoutesMap({}, routes);
173
180
  Object.keys(routesMap).forEach(function (template) {
174
- var pathname = routesMap[template];
175
- if (pathname !== template) {
176
- rewrites.push(getPathRewrite(pathname, template));
181
+ var route = routesMap[template];
182
+ if (route.pathname !== template) {
183
+ rewrites.push(getPathRewrite(route));
177
184
  }
178
185
  });
179
186
  if (debug)
package/load.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Utility to load a component with an optional pre-determined delay.
3
3
  *
4
- * This was designed to improve anti spam wit async form loading.
4
+ * This was designed to improve anti spam with async form loading.
5
5
  *
6
6
  * @see https://github.com/vercel/next.js/blob/main/packages/next/next-server/lib/dynamic.tsx
7
7
  * @see https://github.com/vercel/next.js/blob/canary/examples/with-dynamic-import/pages/index.js
package/load.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Utility to load a component with an optional pre-determined delay.
3
3
  *
4
- * This was designed to improve anti spam wit async form loading.
4
+ * This was designed to improve anti spam with async form loading.
5
5
  *
6
6
  * @see https://github.com/vercel/next.js/blob/main/packages/next/next-server/lib/dynamic.tsx
7
7
  * @see https://github.com/vercel/next.js/blob/canary/examples/with-dynamic-import/pages/index.js
@@ -58,47 +58,52 @@ function encodePathname(pathname) {
58
58
  }
59
59
  exports.encodePathname = encodePathname;
60
60
  /**
61
- * It replaces `/{{ slug }}/` with the given replacer.
61
+ * Transform the route translated defintion into a `pathname` and a `template`.
62
+ *
63
+ * Here we add the wildcard flag maybe found in the pathname to the template
64
+ * name too, this is because we do not want to have the wildcard in the JSON
65
+ * keys as those are also used to construct the links through `useTo` hook and
66
+ * handling asterisks there might become cumbersome.
67
+ *
68
+ * @see https://nextjs.org/docs/messages/invalid-multi-match
62
69
  */
63
- function transformRoutePathname(rawPathname) {
64
- var pathNameParts = rawPathname.split("/").filter(function (part) { return !!part; });
65
- return pathNameParts
66
- .map(function (part, _idx) {
67
- var _a;
70
+ function transformRoute(route) {
71
+ var rawPathname = route.pathname, rawTemplate = route.template;
72
+ var pathnameParts = rawPathname.split("/").filter(function (part) { return !!part; });
73
+ var templateParts = rawTemplate.split("/").filter(function (part) { return !!part; });
74
+ var mapPartsByIdx = {};
75
+ var pathname = pathnameParts
76
+ .map(function (part) {
77
+ var _a, _b;
68
78
  var isDynamic = part.startsWith("{{") && part.endsWith("}}");
69
- var replacer = isDynamic
70
- ? ":".concat((_a = part.match(/{{(.+)}}/)) === null || _a === void 0 ? void 0 : _a[1].trim())
71
- : "";
72
- part = isDynamic ? replacer : part;
73
- // if (isDynamic && _idx === pathNameParts.length - 1) {
74
- // part += "*";
75
- // }
76
- return isDynamic ? part : encodeURIComponent(part);
79
+ var asValue = isDynamic
80
+ ? (_b = (_a = part.match(/{{(.+)}}/)) === null || _a === void 0 ? void 0 : _a[1].trim()) !== null && _b !== void 0 ? _b : ""
81
+ : part.trim();
82
+ var hasWildcard = part.includes("*");
83
+ var asPath = encodeURIComponent(asValue.replace("*", "")) + (hasWildcard ? "*" : "");
84
+ mapPartsByIdx[asValue.replace("*", "")] = {
85
+ isDynamic: isDynamic,
86
+ hasWildcard: hasWildcard,
87
+ };
88
+ return isDynamic ? ":".concat(asPath) : asPath;
77
89
  })
78
90
  .join("/");
79
- }
80
- /**
81
- * It replaces `/[slug]/` with the given replacer.
82
- */
83
- function transformRouteTemplate(rawPathname) {
84
- var pathNameParts = rawPathname.split("/").filter(function (part) { return !!part; });
85
- return pathNameParts
86
- .map(function (part, _idx) {
87
- var _a;
91
+ var template = templateParts
92
+ .map(function (part) {
93
+ var _a, _b, _c;
88
94
  var isDynamic = part.startsWith("[") && part.endsWith("]");
89
- var replacer = isDynamic
90
- ? ":".concat((_a = part.match(/\[(.+)\]/)) === null || _a === void 0 ? void 0 : _a[1].trim())
91
- : "";
92
- part = isDynamic ? replacer : part;
93
- // if (isDynamic && _idx === pathNameParts.length - 1) {
94
- // part += "*";
95
- // }
96
- return isDynamic ? part : encodeURIComponent(part);
95
+ var asValue = isDynamic
96
+ ? (_b = (_a = part.match(/\[(.+)\]/)) === null || _a === void 0 ? void 0 : _a[1].trim()) !== null && _b !== void 0 ? _b : ""
97
+ : part.trim();
98
+ var hasWildcard = (_c = mapPartsByIdx[asValue]) === null || _c === void 0 ? void 0 : _c.hasWildcard;
99
+ var asPath = encodeURIComponent(asValue.replace("*", "")) + (hasWildcard ? "*" : "");
100
+ return isDynamic ? ":".concat(asPath) : asPath;
97
101
  })
98
102
  .join("/");
103
+ return { pathname: pathname, template: template };
99
104
  }
100
105
  /**
101
- * Get flat key/value routes map dictionary
106
+ * Get routes map dictionary
102
107
  */
103
108
  function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
104
109
  if (map === void 0) { map = {}; }
@@ -108,7 +113,11 @@ function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
108
113
  var pathOrNestedRoutes = routes[key];
109
114
  var template = "".concat(templateBuffer, "/").concat(key);
110
115
  if (typeof pathOrNestedRoutes === "string") {
111
- map[template] = pathOrNestedRoutes;
116
+ map[template] = {
117
+ template: template,
118
+ pathname: pathOrNestedRoutes,
119
+ wildcard: pathOrNestedRoutes.includes("*"),
120
+ };
112
121
  }
113
122
  else {
114
123
  getRoutesMap(map, pathOrNestedRoutes, pathnameBuffer, template);
@@ -119,9 +128,8 @@ function getRoutesMap(map, routes, pathnameBuffer, templateBuffer) {
119
128
  /**
120
129
  * Get path rewrite
121
130
  */
122
- function getPathRewrite(pathname, template) {
123
- pathname = transformRoutePathname(pathname);
124
- template = transformRouteTemplate(template);
131
+ function getPathRewrite(route) {
132
+ var _a = transformRoute(route), pathname = _a.pathname, template = _a.template;
125
133
  var source = "/".concat(normaliseUrlPathname(pathname));
126
134
  var destination = "/".concat(normaliseUrlPathname(template));
127
135
  // console.log(`rewrite pathname "${source}" to template "${destination}"`);
@@ -134,10 +142,9 @@ exports.getPathRewrite = getPathRewrite;
134
142
  /**
135
143
  * Get path redirect
136
144
  */
137
- function getPathRedirect(locale, pathname, template, permanent) {
145
+ function getPathRedirect(locale, route, permanent) {
138
146
  if (locale === void 0) { locale = ""; }
139
- template = transformRouteTemplate(template);
140
- pathname = transformRoutePathname(pathname);
147
+ var _a = transformRoute(route), template = _a.template, pathname = _a.pathname;
141
148
  var source = "/".concat(normaliseUrlPathname((locale ? "/".concat(locale, "/") : "/") + template));
142
149
  var destination = "/".concat(normaliseUrlPathname(pathname));
143
150
  // console.log(`redirect template "${source}" to pathname "${destination}"`);
@@ -158,10 +165,10 @@ function getRedirects(defaultLocale, routes, permanent, debug) {
158
165
  redirects = [];
159
166
  routesMap = getRoutesMap({}, routes);
160
167
  Object.keys(routesMap).forEach(function (template) {
161
- var pathname = routesMap[template];
162
- if (pathname !== template) {
163
- redirects.push(getPathRedirect(defaultLocale, pathname, template, permanent));
164
- redirects.push(getPathRedirect("", pathname, template, permanent));
168
+ var route = routesMap[template];
169
+ if (route.pathname !== template) {
170
+ redirects.push(getPathRedirect(defaultLocale, route, permanent));
171
+ redirects.push(getPathRedirect("", route, permanent));
165
172
  }
166
173
  });
167
174
  if (debug)
@@ -180,9 +187,9 @@ function getRewrites(routes, debug) {
180
187
  rewrites = [];
181
188
  routesMap = getRoutesMap({}, routes);
182
189
  Object.keys(routesMap).forEach(function (template) {
183
- var pathname = routesMap[template];
184
- if (pathname !== template) {
185
- rewrites.push(getPathRewrite(pathname, template));
190
+ var route = routesMap[template];
191
+ if (route.pathname !== template) {
192
+ rewrites.push(getPathRewrite(route));
186
193
  }
187
194
  });
188
195
  if (debug)
package/node/load.js CHANGED
@@ -4,7 +4,7 @@ exports.load = void 0;
4
4
  /**
5
5
  * Utility to load a component with an optional pre-determined delay.
6
6
  *
7
- * This was designed to improve anti spam wit async form loading.
7
+ * This was designed to improve anti spam with async form loading.
8
8
  *
9
9
  * @see https://github.com/vercel/next.js/blob/main/packages/next/next-server/lib/dynamic.tsx
10
10
  * @see https://github.com/vercel/next.js/blob/canary/examples/with-dynamic-import/pages/index.js
package/package.json CHANGED
@@ -18,9 +18,9 @@
18
18
  "peerDependencies": {
19
19
  "react": "^16.8 || ^17 || ^18",
20
20
  "next": "^12.2.3",
21
- "@koine/utils": "1.0.66",
21
+ "@koine/utils": "1.0.69",
22
22
  "framer-motion": "^6.5.1",
23
- "@koine/react": "1.0.66",
23
+ "@koine/react": "1.0.69",
24
24
  "styled-components": "^5.3.5",
25
25
  "@mui/base": "^5.0.0-alpha.90",
26
26
  "react-icons": "^4.4.0",
@@ -41,7 +41,7 @@
41
41
  "next-seo": "^5.5.0",
42
42
  "@hookform/resolvers": "^2.9.6"
43
43
  },
44
- "version": "1.0.66",
44
+ "version": "1.0.69",
45
45
  "module": "./index.js",
46
46
  "types": "./index.d.ts"
47
47
  }
package/to.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { TranslateNamespaced, TranslatedRoute } from "./types-i18n";
2
- declare type OnlyStatic<T extends string> = T extends `${string}.[${string}]` | `[${string}].${string}` | `[${string}]` ? never : T;
3
- declare type OnlyDynamic<T extends string> = T extends `${string}.[${string}]` | `[${string}].${string}` | `[${string}]` ? T : never;
2
+ declare type OnlyStatic<T extends string> = T extends `${string}.[${string}].${string}` | `${string}.[${string}]` | `[${string}].${string}` | `[${string}]` ? never : T;
3
+ declare type OnlyDynamic<T extends string> = T extends `${string}.[${string}].${string}` | `${string}.[${string}]` | `[${string}].${string}` | `[${string}]` ? T : never;
4
4
  /**
5
5
  * @borrows [awesome-template-literal-types](https://github.com/ghoullier/awesome-template-literal-types#router-params-parsing)
6
6
  */
package/types-i18n.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * ```ts
13
13
  * declare namespace Koine {
14
- * interface NextTranslations {
14
+ * interface Translations {
15
15
  * "~": typeof import("./locales/en/~.json");
16
16
  * "_": typeof import("./locales/en/_.json");
17
17
  * "$team": typeof import("./locales/en/$team.json");
@@ -43,7 +43,7 @@
43
43
  * would use a `~my~account-settings.json` file.
44
44
  * - `ComponentName.json`: pascal cased for **components** specific data
45
45
  */
46
- export declare type TranslationsDictionary = Koine.NextTranslations;
46
+ export declare type TranslationsDictionary = Koine.Translations;
47
47
  export declare type TranslateNamespace = Extract<keyof TranslationsDictionary, string>;
48
48
  declare type Join<S1, S2> = S1 extends string ? S2 extends string ? `${S1}.${S2}` : S1 : never;
49
49
  export declare type TranslationsPaths<T, TAddRoot extends true | undefined = undefined> = {
@@ -109,4 +109,16 @@ export declare type TranslateLoose = (s?: any, q?: TranslationQuery, o?: Transla
109
109
  * localised pathname (even with dynamic portions).
110
110
  */
111
111
  export declare type TranslatedRoute = TranslationsPaths<TranslationsDictionary["~"]>;
112
+ /**
113
+ * Utility standalone type to extract all (max two level depth) children routes
114
+ * that starts with the given string.
115
+ *
116
+ * This is useful to get the subroutes of an application area, e.g. all subroutes
117
+ * of a dashboard, using it with:
118
+ *
119
+ * ```
120
+ * type DashboardRoutes = TranslatedRoutesChildrenOf<"dashboard">;
121
+ * ```
122
+ */
123
+ export declare type TranslatedRoutesChildrenOf<TStarts extends string, T extends string = TranslatedRoute> = T extends `${TStarts}.${infer First}.${infer Second}` ? First | `${First}.${Second}` : T extends `${TStarts}.${infer First}` ? First : never;
112
124
  export {};
package/typings.d.ts CHANGED
@@ -64,7 +64,7 @@ declare namespace Koine {
64
64
  *
65
65
  * ```ts
66
66
  * declare namespace Koine {
67
- * interface NextTranslations {
67
+ * interface Translations {
68
68
  * "~": typeof import("./locales/en/~.json");
69
69
  * "_": typeof import("./locales/en/_.json");
70
70
  * "$team": typeof import("./locales/en/$team.json");
@@ -82,7 +82,7 @@ declare namespace Koine {
82
82
  * - `{route-name}`: lower cased for **route** specific data
83
83
  * - `{ComponentName}`: pascal cased for **components** specific data
84
84
  */
85
- interface NextTranslations {
85
+ interface Translations {
86
86
  [key: string]: any;
87
87
  }
88
88
  }