@bleedingdev/modern-js-runtime-extensions 3.9.0-ultramodern.11 → 3.9.0-ultramodern.12

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.
Files changed (66) hide show
  1. package/dist/cjs/localisedUrls/config.js +49 -0
  2. package/dist/cjs/localisedUrls/index.js +95 -0
  3. package/dist/cjs/localisedUrls/normalise.js +87 -0
  4. package/dist/cjs/localisedUrls/pathname.js +68 -0
  5. package/dist/cjs/localisedUrls/patterns.js +214 -0
  6. package/dist/cjs/localisedUrls/redirect.js +100 -0
  7. package/dist/cjs/localisedUrls/resolve.js +78 -0
  8. package/dist/cjs/localisedUrls/routeIdentity.js +92 -0
  9. package/dist/cjs/localisedUrls/routes.js +217 -0
  10. package/dist/cjs/localisedUrls/types.js +18 -0
  11. package/dist/cjs/routerState.js +48 -77
  12. package/dist/cjs/routerStatePlugin.js +36 -9
  13. package/dist/esm/localisedUrls/config.mjs +11 -0
  14. package/dist/esm/localisedUrls/index.mjs +8 -0
  15. package/dist/esm/localisedUrls/normalise.mjs +37 -0
  16. package/dist/esm/localisedUrls/pathname.mjs +24 -0
  17. package/dist/esm/localisedUrls/patterns.mjs +152 -0
  18. package/dist/esm/localisedUrls/redirect.mjs +53 -0
  19. package/dist/esm/localisedUrls/resolve.mjs +37 -0
  20. package/dist/esm/localisedUrls/routeIdentity.mjs +54 -0
  21. package/dist/esm/localisedUrls/routes.mjs +176 -0
  22. package/dist/esm/localisedUrls/types.mjs +0 -0
  23. package/dist/esm/routerState.mjs +49 -75
  24. package/dist/esm/routerStatePlugin.mjs +37 -10
  25. package/dist/esm-node/localisedUrls/config.mjs +12 -0
  26. package/dist/esm-node/localisedUrls/index.mjs +9 -0
  27. package/dist/esm-node/localisedUrls/normalise.mjs +38 -0
  28. package/dist/esm-node/localisedUrls/pathname.mjs +25 -0
  29. package/dist/esm-node/localisedUrls/patterns.mjs +153 -0
  30. package/dist/esm-node/localisedUrls/redirect.mjs +54 -0
  31. package/dist/esm-node/localisedUrls/resolve.mjs +38 -0
  32. package/dist/esm-node/localisedUrls/routeIdentity.mjs +55 -0
  33. package/dist/esm-node/localisedUrls/routes.mjs +177 -0
  34. package/dist/esm-node/localisedUrls/types.mjs +1 -0
  35. package/dist/esm-node/routerState.mjs +49 -75
  36. package/dist/esm-node/routerStatePlugin.mjs +37 -10
  37. package/dist/types/localisedUrls/config.d.ts +9 -0
  38. package/dist/types/localisedUrls/index.d.ts +10 -0
  39. package/dist/types/localisedUrls/normalise.d.ts +10 -0
  40. package/dist/types/localisedUrls/pathname.d.ts +4 -0
  41. package/dist/types/localisedUrls/patterns.d.ts +11 -0
  42. package/dist/types/localisedUrls/redirect.d.ts +19 -0
  43. package/dist/types/localisedUrls/resolve.d.ts +7 -0
  44. package/dist/types/localisedUrls/routeIdentity.d.ts +22 -0
  45. package/dist/types/localisedUrls/routes.d.ts +3 -0
  46. package/dist/types/localisedUrls/types.d.ts +14 -0
  47. package/dist/types/routeHydration.d.ts +2 -2
  48. package/dist/types/routerState.d.ts +5 -6
  49. package/dist/types/routerStateTypes.d.ts +47 -17
  50. package/package.json +16 -4
  51. package/src/localisedUrls/config.ts +18 -0
  52. package/src/localisedUrls/index.ts +25 -0
  53. package/src/localisedUrls/normalise.ts +62 -0
  54. package/src/localisedUrls/pathname.ts +60 -0
  55. package/src/localisedUrls/patterns.ts +283 -0
  56. package/src/localisedUrls/redirect.ts +107 -0
  57. package/src/localisedUrls/resolve.ts +106 -0
  58. package/src/localisedUrls/routeIdentity.ts +83 -0
  59. package/src/localisedUrls/routes.ts +451 -0
  60. package/src/localisedUrls/types.ts +18 -0
  61. package/src/routeHydration.ts +2 -2
  62. package/src/routerState.ts +52 -122
  63. package/src/routerStatePlugin.ts +49 -10
  64. package/src/routerStateTypes.ts +47 -17
  65. package/tests/localisedUrls.test.ts +560 -0
  66. package/tests/routerState.test.ts +7 -8
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ resolveCanonicalLocalisedPath: ()=>resolveCanonicalLocalisedPath,
32
+ resolveLocalisedPath: ()=>resolveLocalisedPath
33
+ });
34
+ const external_normalise_js_namespaceObject = require("./normalise.js");
35
+ const external_patterns_js_namespaceObject = require("./patterns.js");
36
+ const getCanonicalCandidates = (localisedUrls)=>(0, external_patterns_js_namespaceObject.sortPatternsBySpecificity)(Object.entries(localisedUrls).map(([canonicalPattern, localisedUrlEntry])=>({
37
+ pattern: canonicalPattern,
38
+ canonicalPattern,
39
+ localisedUrlEntry
40
+ })));
41
+ const resolveLocalisedUrlPath = (pathname, languages, localisedUrls, options)=>{
42
+ const normalizedPathname = (0, external_normalise_js_namespaceObject.normalisePathname)(pathname);
43
+ const canonicalCandidates = getCanonicalCandidates(localisedUrls);
44
+ const candidates = (0, external_patterns_js_namespaceObject.sortPatternsBySpecificity)(canonicalCandidates.flatMap(({ canonicalPattern, localisedUrlEntry })=>{
45
+ const targetPattern = 'localised' === options.mode ? localisedUrlEntry[options.targetLanguage] : canonicalPattern;
46
+ if (!targetPattern) return [];
47
+ const sourcePatterns = new Set([
48
+ canonicalPattern,
49
+ ...languages.map((language)=>localisedUrlEntry[language]).filter((sourcePattern)=>Boolean(sourcePattern))
50
+ ]);
51
+ return Array.from(sourcePatterns, (sourcePattern)=>({
52
+ pattern: sourcePattern,
53
+ sourcePattern,
54
+ targetPattern
55
+ }));
56
+ }));
57
+ for (const { sourcePattern, targetPattern } of candidates){
58
+ const params = (0, external_patterns_js_namespaceObject.matchPathPattern)(normalizedPathname, sourcePattern);
59
+ if (params) return (0, external_patterns_js_namespaceObject.buildPathFromPattern)(targetPattern, params);
60
+ }
61
+ return normalizedPathname;
62
+ };
63
+ const resolveLocalisedPath = (pathname, targetLanguage, languages, localisedUrls)=>resolveLocalisedUrlPath(pathname, languages, localisedUrls, {
64
+ mode: 'localised',
65
+ targetLanguage
66
+ });
67
+ const resolveCanonicalLocalisedPath = (pathname, languages, localisedUrls)=>resolveLocalisedUrlPath(pathname, languages, localisedUrls, {
68
+ mode: 'canonical'
69
+ });
70
+ exports.resolveCanonicalLocalisedPath = __webpack_exports__.resolveCanonicalLocalisedPath;
71
+ exports.resolveLocalisedPath = __webpack_exports__.resolveLocalisedPath;
72
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
73
+ "resolveCanonicalLocalisedPath",
74
+ "resolveLocalisedPath"
75
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
76
+ Object.defineProperty(exports, '__esModule', {
77
+ value: true
78
+ });
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ createLocalisedRouteRewrite: ()=>createLocalisedRouteRewrite
32
+ });
33
+ const external_normalise_js_namespaceObject = require("./normalise.js");
34
+ const external_patterns_js_namespaceObject = require("./patterns.js");
35
+ function rewritePath(url, mappings) {
36
+ for (const { from, to } of mappings){
37
+ const params = (0, external_patterns_js_namespaceObject.matchPathPattern)(url.pathname, from);
38
+ if (params) {
39
+ url.pathname = (0, external_patterns_js_namespaceObject.buildPathFromPattern)(to, params);
40
+ break;
41
+ }
42
+ }
43
+ return url;
44
+ }
45
+ function createLocalisedRouteRewrite(routes) {
46
+ const input = [];
47
+ const output = [];
48
+ const visit = (nodes, parent)=>{
49
+ for (const route of nodes){
50
+ const fullPath = (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${parent}/${route.path ?? ''}`);
51
+ const identity = route.modernLocalisedRoute;
52
+ if (identity?.paths && fullPath.endsWith(identity.canonicalPath)) {
53
+ const prefix = fullPath.slice(0, -identity.canonicalPath.length);
54
+ const hasLocale = prefix.split('/').some((segment)=>/^:(?:lang|locale|language)\??$/.test(segment));
55
+ for (const [language, localisedPath] of Object.entries(identity.paths)){
56
+ const localePrefix = prefix.split('/').map((segment)=>/^:(?:lang|locale|language)\??$/.test(segment) ? language : segment).join('/');
57
+ const canonical = (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${localePrefix}/${identity.canonicalPath}`);
58
+ const localised = (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${localePrefix}/${localisedPath}`);
59
+ if (canonical !== localised) {
60
+ input.push({
61
+ from: localised,
62
+ to: canonical
63
+ });
64
+ if (hasLocale) output.push({
65
+ from: canonical,
66
+ to: localised
67
+ });
68
+ }
69
+ }
70
+ }
71
+ if (route.children) visit(route.children, fullPath);
72
+ }
73
+ };
74
+ visit(routes, '');
75
+ if (0 === input.length) return;
76
+ const specificity = (pattern)=>pattern.split('/').filter((segment)=>segment && !segment.startsWith(':') && '*' !== segment).length;
77
+ for (const mappings of [
78
+ input,
79
+ output
80
+ ])mappings.sort((a, b)=>specificity(b.from) - specificity(a.from));
81
+ return {
82
+ input: ({ url })=>rewritePath(url, input),
83
+ output: ({ url })=>rewritePath(url, output)
84
+ };
85
+ }
86
+ exports.createLocalisedRouteRewrite = __webpack_exports__.createLocalisedRouteRewrite;
87
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
88
+ "createLocalisedRouteRewrite"
89
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
90
+ Object.defineProperty(exports, '__esModule', {
91
+ value: true
92
+ });
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ applyLocalisedUrlsToRoutes: ()=>applyLocalisedUrlsToRoutes,
32
+ validateLocalisedUrls: ()=>validateLocalisedUrls
33
+ });
34
+ const external_normalise_js_namespaceObject = require("./normalise.js");
35
+ const external_patterns_js_namespaceObject = require("./patterns.js");
36
+ const isLocalisableRoutePath = (path)=>{
37
+ const pathWithoutLocale = (0, external_normalise_js_namespaceObject.stripLeadingLocaleParam)(path);
38
+ if (!pathWithoutLocale || '/' === pathWithoutLocale || '*' === pathWithoutLocale) return false;
39
+ return true;
40
+ };
41
+ const joinPath = (parentPath, routePath)=>{
42
+ if (!isLocalisableRoutePath(routePath)) return parentPath;
43
+ const segment = (0, external_normalise_js_namespaceObject.normaliseRoutePath)((0, external_normalise_js_namespaceObject.stripLeadingLocaleParam)(routePath) || '');
44
+ return (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${parentPath}/${segment}`);
45
+ };
46
+ const isFrameworkInternalRoutePath = (canonicalPath)=>'/_mf' === canonicalPath || canonicalPath.startsWith('/_mf/');
47
+ const legalRouteIdPart = (value)=>value.replace(/[^a-zA-Z0-9_$-]+/g, '_').replace(/^_+|_+$/g, '') || 'index';
48
+ const formatParamSignature = (signature)=>signature.length > 0 ? signature.join(', ') : '(none)';
49
+ const validateLocalisedUrlPatterns = (languages, localisedUrls)=>{
50
+ const physicalPatterns = new Map();
51
+ const claimedPatterns = [];
52
+ const claimPhysicalPattern = (sourcePattern, canonicalPath, source)=>{
53
+ const physicalPattern = (0, external_patterns_js_namespaceObject.getPhysicalPathPattern)(sourcePattern);
54
+ const existing = physicalPatterns.get(physicalPattern);
55
+ if (existing && existing.canonicalPath !== canonicalPath) throw new Error(`localisedUrls["${existing.canonicalPath}"] ${existing.source} and localisedUrls["${canonicalPath}"] ${source} generate the same physical route pattern "${physicalPattern}". Localised route patterns must identify exactly one canonical route.`);
56
+ const overlapping = claimedPatterns.find((claimed)=>claimed.canonicalPath !== canonicalPath && (0, external_patterns_js_namespaceObject.haveEqualPatternSpecificity)(claimed.pattern, sourcePattern) && (0, external_patterns_js_namespaceObject.doPathPatternsOverlap)(claimed.pattern, sourcePattern));
57
+ if (overlapping) throw new Error(`localisedUrls["${overlapping.canonicalPath}"] ${overlapping.source} pattern "${overlapping.pattern}" and localisedUrls["${canonicalPath}"] ${source} pattern "${sourcePattern}" are equal-specificity overlapping route patterns. Localised route patterns must identify exactly one canonical route.`);
58
+ physicalPatterns.set(physicalPattern, {
59
+ canonicalPath,
60
+ source
61
+ });
62
+ claimedPatterns.push({
63
+ canonicalPath,
64
+ pattern: sourcePattern,
65
+ source
66
+ });
67
+ };
68
+ for (const [canonicalPath, entry] of Object.entries(localisedUrls).sort(([left], [right])=>left < right ? -1 : left > right ? 1 : 0)){
69
+ const canonicalIssue = (0, external_patterns_js_namespaceObject.getPathPatternValidationIssue)(canonicalPath);
70
+ if (canonicalIssue) throw new Error(`localisedUrls["${canonicalPath}"] canonical pattern has ${canonicalIssue}.`);
71
+ const expectedSignature = (0, external_patterns_js_namespaceObject.getPathParamSignature)(canonicalPath);
72
+ const expectedOrderedSignature = (0, external_patterns_js_namespaceObject.getOrderedPathParamSignature)(canonicalPath);
73
+ claimPhysicalPattern(canonicalPath, canonicalPath, 'canonical pattern');
74
+ for (const language of languages){
75
+ const localisedPattern = entry[language];
76
+ if (!localisedPattern) continue;
77
+ const localisedIssue = (0, external_patterns_js_namespaceObject.getPathPatternValidationIssue)(localisedPattern);
78
+ if (localisedIssue) throw new Error(`localisedUrls["${canonicalPath}"].${language} has ${localisedIssue}.`);
79
+ const actualSignature = (0, external_patterns_js_namespaceObject.getPathParamSignature)(localisedPattern);
80
+ if (actualSignature.length !== expectedSignature.length || actualSignature.some((parameter, index)=>parameter !== expectedSignature[index])) throw new Error(`localisedUrls["${canonicalPath}"].${language} must use the same parameter signature as "${canonicalPath}": expected ${formatParamSignature(expectedSignature)}; received ${formatParamSignature(actualSignature)}.`);
81
+ const actualOrderedSignature = (0, external_patterns_js_namespaceObject.getOrderedPathParamSignature)(localisedPattern);
82
+ if (expectedOrderedSignature.some((parameter)=>'*' === parameter || parameter.endsWith('?')) && actualOrderedSignature.some((parameter, index)=>parameter !== expectedOrderedSignature[index])) throw new Error(`localisedUrls["${canonicalPath}"].${language} must keep optional and splat parameters in canonical order: expected ${formatParamSignature(expectedOrderedSignature)}; received ${formatParamSignature(actualOrderedSignature)}.`);
83
+ claimPhysicalPattern(localisedPattern, canonicalPath, `.${language}`);
84
+ }
85
+ }
86
+ };
87
+ const ensureLocalisedUrlsForPath = (canonicalPath, languages, localisedUrls)=>{
88
+ const entry = localisedUrls[canonicalPath];
89
+ if (!entry) throw new Error(`localisedUrls is enabled, but route "${canonicalPath}" does not define localised URLs for languages: ${languages.join(', ')}. Add localisedUrls["${canonicalPath}"] or set localeDetection.localisedUrls to false.`);
90
+ const missingLanguages = languages.filter((language)=>!entry[language]);
91
+ if (missingLanguages.length > 0) throw new Error(`localisedUrls["${canonicalPath}"] is missing languages: ${missingLanguages.join(', ')}. Every configured language must have a localised URL.`);
92
+ return entry;
93
+ };
94
+ const validateLocalisedUrls = (routes, languages, localisedUrls)=>{
95
+ validateLocalisedUrlPatterns(languages, localisedUrls);
96
+ const visit = (route, parentPath)=>{
97
+ const canonicalPath = joinPath(parentPath, route.path);
98
+ if (isLocalisableRoutePath(route.path) && !isFrameworkInternalRoutePath(canonicalPath)) ensureLocalisedUrlsForPath(canonicalPath, languages, localisedUrls);
99
+ if ('children' in route && route.children) route.children.forEach((child)=>visit(child, canonicalPath));
100
+ };
101
+ routes.forEach((route)=>visit(route, ''));
102
+ };
103
+ const getLocalisedRouteIdSuffixes = (paths)=>{
104
+ const usedSuffixes = new Set();
105
+ return paths.map((path, index)=>{
106
+ if (0 === index) return;
107
+ const baseSuffix = legalRouteIdPart(path);
108
+ let suffix = baseSuffix;
109
+ let disambiguator = 2;
110
+ while(usedSuffixes.has(suffix))suffix = `${baseSuffix}_${disambiguator++}`;
111
+ usedSuffixes.add(suffix);
112
+ return suffix;
113
+ });
114
+ };
115
+ const getLocalisedRoutePaths = (canonicalPath, parentLocalisedPaths, languages, entry)=>{
116
+ const paths = languages.map((language)=>{
117
+ const fullPath = (0, external_normalise_js_namespaceObject.normalisePathPattern)(entry[language]);
118
+ const parentPath = (0, external_normalise_js_namespaceObject.normalisePathPattern)(parentLocalisedPaths[language] || '/');
119
+ if ('/' === parentPath) return (0, external_normalise_js_namespaceObject.normaliseRoutePath)(fullPath) || void 0;
120
+ const parentPrefix = `${parentPath}/`;
121
+ if (!fullPath.startsWith(parentPrefix)) throw new Error(`localisedUrls["${canonicalPath}"].${language} must be nested under "${parentPath}" because its parent route is localised there.`);
122
+ return (0, external_normalise_js_namespaceObject.normaliseRoutePath)(fullPath.slice(parentPath.length));
123
+ });
124
+ const uniquePaths = Array.from(new Set(paths.filter(Boolean)));
125
+ return uniquePaths;
126
+ };
127
+ const transformLocalisedRoute = (route, parentCanonicalPath, parentLocalisedPaths, languages, localisedUrls, projection)=>{
128
+ const isSplat = '*' === (0, external_normalise_js_namespaceObject.stripLeadingLocaleParam)(route.path);
129
+ const canonicalPath = isSplat ? (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${parentCanonicalPath}/*`) : joinPath(parentCanonicalPath, route.path);
130
+ const localisedUrlEntry = isLocalisableRoutePath(route.path) && !isFrameworkInternalRoutePath(canonicalPath) ? ensureLocalisedUrlsForPath(canonicalPath, languages, localisedUrls) : void 0;
131
+ const routeLocalisedPaths = localisedUrlEntry ? languages.reduce((acc, language)=>{
132
+ acc[language] = (0, external_normalise_js_namespaceObject.normalisePathPattern)(localisedUrlEntry[language]);
133
+ return acc;
134
+ }, {}) : isSplat ? Object.fromEntries(Object.entries(parentLocalisedPaths).map(([language, path])=>[
135
+ language,
136
+ (0, external_normalise_js_namespaceObject.normalisePathPattern)(`${path}/*`)
137
+ ])) : parentLocalisedPaths;
138
+ const children = 'children' in route && route.children ? route.children.flatMap((child)=>transformLocalisedRoute(child, canonicalPath, routeLocalisedPaths, languages, localisedUrls, projection)) : void 0;
139
+ const baseRoute = {
140
+ ...route,
141
+ ...!isFrameworkInternalRoutePath(canonicalPath) ? {
142
+ modernLocalisedRoute: {
143
+ id: route.id,
144
+ path: route.path,
145
+ canonicalPath,
146
+ paths: localisedUrlEntry ?? (isSplat ? routeLocalisedPaths : void 0)
147
+ }
148
+ } : {},
149
+ ...children ? {
150
+ children
151
+ } : {}
152
+ };
153
+ if (!localisedUrlEntry) return [
154
+ baseRoute
155
+ ];
156
+ const localisedPaths = getLocalisedRoutePaths(canonicalPath, parentLocalisedPaths, languages, localisedUrlEntry);
157
+ if ('canonical' === projection) return [
158
+ baseRoute
159
+ ];
160
+ const leadingLocaleParam = (0, external_normalise_js_namespaceObject.getLeadingLocaleParam)(route.path);
161
+ const routeIdPaths = leadingLocaleParam ? localisedPaths.map((path)=>(0, external_normalise_js_namespaceObject.normaliseRoutePath)(`${leadingLocaleParam}/${path}`)) : localisedPaths;
162
+ const routeIdSuffixes = getLocalisedRouteIdSuffixes(routeIdPaths);
163
+ return localisedPaths.map((localisedPath, index)=>cloneRouteWithLocalisedPath(baseRoute, localisedPath, routeIdSuffixes[index], canonicalPath));
164
+ };
165
+ const suffixRouteIds = (route, suffix)=>{
166
+ const children = 'children' in route && route.children ? route.children.map((child)=>suffixRouteIds(child, suffix)) : void 0;
167
+ return {
168
+ ...route,
169
+ ...route.id ? {
170
+ id: `${route.id}__localised_${suffix}`
171
+ } : {},
172
+ ...children ? {
173
+ children
174
+ } : {}
175
+ };
176
+ };
177
+ const collectRouteIdCounts = (routes, counts = new Map())=>{
178
+ for (const route of routes){
179
+ if (route.id) counts.set(route.id, (counts.get(route.id) ?? 0) + 1);
180
+ if ('children' in route && route.children) collectRouteIdCounts(route.children, counts);
181
+ }
182
+ return counts;
183
+ };
184
+ const validateNoNewRouteIdCollisions = (sourceRoutes, localisedRoutes)=>{
185
+ const sourceCounts = collectRouteIdCounts(sourceRoutes);
186
+ const localisedCounts = collectRouteIdCounts(localisedRoutes);
187
+ for (const [routeId, count] of localisedCounts)if (count > 1 && count > (sourceCounts.get(routeId) ?? 0)) throw new Error(`Localised route expansion generated duplicate route ID "${routeId}". Change the source route ID or localised path so every generated route remains identifiable.`);
188
+ };
189
+ const cloneRouteWithLocalisedPath = (route, path, routeIdSuffix, canonicalPath)=>{
190
+ const leadingLocaleParam = (0, external_normalise_js_namespaceObject.getLeadingLocaleParam)(route.path);
191
+ const localisedPath = leadingLocaleParam ? (0, external_normalise_js_namespaceObject.normaliseRoutePath)(`${leadingLocaleParam}/${path}`) : path;
192
+ const routeWithPath = {
193
+ ...route,
194
+ path: localisedPath
195
+ };
196
+ routeWithPath.modernCanonicalPath = canonicalPath;
197
+ return routeIdSuffix ? suffixRouteIds(routeWithPath, routeIdSuffix) : routeWithPath;
198
+ };
199
+ const applyLocalisedUrlsToRoutes = (routes, languages, localisedUrls, projection = 'physical')=>{
200
+ const rootLocalisedPaths = languages.reduce((acc, language)=>{
201
+ acc[language] = '/';
202
+ return acc;
203
+ }, {});
204
+ validateLocalisedUrls(routes, languages, localisedUrls);
205
+ const localisedRoutes = routes.flatMap((route)=>transformLocalisedRoute(route, '', rootLocalisedPaths, languages, localisedUrls, projection));
206
+ validateNoNewRouteIdCollisions(routes, localisedRoutes);
207
+ return localisedRoutes;
208
+ };
209
+ exports.applyLocalisedUrlsToRoutes = __webpack_exports__.applyLocalisedUrlsToRoutes;
210
+ exports.validateLocalisedUrls = __webpack_exports__.validateLocalisedUrls;
211
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
212
+ "applyLocalisedUrlsToRoutes",
213
+ "validateLocalisedUrls"
214
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
215
+ Object.defineProperty(exports, '__esModule', {
216
+ value: true
217
+ });
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.r = (exports1)=>{
5
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
6
+ value: 'Module'
7
+ });
8
+ Object.defineProperty(exports1, '__esModule', {
9
+ value: true
10
+ });
11
+ };
12
+ })();
13
+ var __webpack_exports__ = {};
14
+ __webpack_require__.r(__webpack_exports__);
15
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
16
+ Object.defineProperty(exports, '__esModule', {
17
+ value: true
18
+ });
@@ -31,7 +31,6 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  applyRouterRuntimeState: ()=>applyRouterRuntimeState,
32
32
  applyRouterServerPrepareResult: ()=>applyRouterServerPrepareResult,
33
33
  cleanupRouterRuntimeState: ()=>cleanupRouterRuntimeState,
34
- createRouterRuntimeState: ()=>createRouterRuntimeState,
35
34
  createRouterServerSnapshot: ()=>createRouterServerSnapshot,
36
35
  getRouterHydrationScripts: ()=>getRouterHydrationScripts,
37
36
  getRouterMatchedRouteIds: ()=>getRouterMatchedRouteIds,
@@ -48,66 +47,52 @@ function getRouterRuntimeState(runtimeContext) {
48
47
  function getRouterServerSnapshot(runtimeContext) {
49
48
  return routerServerSnapshotExtension.get(runtimeContext);
50
49
  }
51
- function toHydrationScripts(state) {
52
- if (state.hydrationScripts?.length) return state.hydrationScripts;
53
- return state.hydrationScript ? [
54
- state.hydrationScript
55
- ] : void 0;
56
- }
57
- function getMatchedRouteIdsFromMatches(matches) {
58
- const routeIds = matches?.map((match)=>match.assetRouteId ?? match.routeId).filter((routeId)=>'string' == typeof routeId);
59
- return routeIds?.length ? routeIds : void 0;
60
- }
61
- function createRouterServerSnapshot(state) {
62
- const hydrationScripts = toHydrationScripts(state);
63
- const matchedRouteIds = state.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
64
- return {
65
- ...state,
66
- ...hydrationScripts?.length ? {
67
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
68
- hydrationScripts
50
+ function createRouterServerSnapshot(snapshot) {
51
+ const matches = snapshot.matches?.map((match)=>Object.freeze({
52
+ ...match,
53
+ ...match.params ? {
54
+ params: Object.freeze({
55
+ ...match.params
56
+ })
57
+ } : {}
58
+ }));
59
+ const matchedRouteIds = snapshot.matchedRouteIds ?? matches?.map((match)=>match.assetRouteId ?? match.routeId);
60
+ return Object.freeze({
61
+ ...snapshot,
62
+ ...snapshot.hydrationScripts ? {
63
+ hydrationScripts: Object.freeze([
64
+ ...snapshot.hydrationScripts
65
+ ])
69
66
  } : {},
70
67
  ...matchedRouteIds ? {
71
- matchedRouteIds
72
- } : {}
73
- };
74
- }
75
- function createRouterRuntimeState(state) {
76
- const hasSnapshotState = Boolean(state.serverSnapshot) || Boolean(state.hydrationScript) || Boolean(state.hydrationScripts?.length) || Boolean(state.matchedRouteIds?.length) || Boolean(state.matches?.length);
77
- const serverSnapshot = state.serverSnapshot ? createRouterServerSnapshot({
78
- ...state.serverSnapshot,
79
- framework: state.serverSnapshot.framework ?? state.framework,
80
- basename: state.serverSnapshot.basename ?? state.basename,
81
- hydrationScript: state.serverSnapshot.hydrationScript ?? state.hydrationScript,
82
- hydrationScripts: state.serverSnapshot.hydrationScripts ?? state.hydrationScripts,
83
- matchedRouteIds: state.serverSnapshot.matchedRouteIds ?? state.matchedRouteIds,
84
- matches: state.serverSnapshot.matches ?? state.matches
85
- }) : hasSnapshotState ? createRouterServerSnapshot({
86
- framework: state.framework,
87
- basename: state.basename,
88
- hydrationScript: state.hydrationScript,
89
- hydrationScripts: state.hydrationScripts,
90
- matchedRouteIds: state.matchedRouteIds,
91
- matches: state.matches
92
- }) : void 0;
93
- const hydrationScripts = toHydrationScripts({
94
- hydrationScript: state.hydrationScript ?? serverSnapshot?.hydrationScript,
95
- hydrationScripts: state.hydrationScripts ?? serverSnapshot?.hydrationScripts
96
- });
97
- const matchedRouteIds = state.matchedRouteIds ?? serverSnapshot?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
98
- return {
99
- ...state,
100
- ...hydrationScripts?.length ? {
101
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
102
- hydrationScripts
68
+ matchedRouteIds: Object.freeze([
69
+ ...matchedRouteIds
70
+ ])
103
71
  } : {},
104
- ...matchedRouteIds ? {
105
- matchedRouteIds
72
+ ...matches ? {
73
+ matches: Object.freeze(matches)
74
+ } : {},
75
+ ...snapshot.errors ? {
76
+ errors: Object.freeze({
77
+ ...snapshot.errors
78
+ })
106
79
  } : {},
107
- ...serverSnapshot ? {
108
- serverSnapshot
80
+ ...snapshot.routerData ? {
81
+ routerData: Object.freeze({
82
+ ...snapshot.routerData,
83
+ ...snapshot.routerData.loaderData ? {
84
+ loaderData: Object.freeze({
85
+ ...snapshot.routerData.loaderData
86
+ })
87
+ } : {},
88
+ ...snapshot.routerData.errors ? {
89
+ errors: Object.freeze({
90
+ ...snapshot.routerData.errors
91
+ })
92
+ } : {}
93
+ })
109
94
  } : {}
110
- };
95
+ });
111
96
  }
112
97
  const routerRuntimeStateListeners = new WeakMap();
113
98
  function subscribeRouterRuntimeState(runtimeContext, listener) {
@@ -143,34 +128,22 @@ function notifyRouterRuntimeState(runtimeContext) {
143
128
  }
144
129
  function applyRouterRuntimeState(runtimeContext, state) {
145
130
  const previous = routerRuntimeStateExtension.get(runtimeContext);
146
- const normalized = createRouterRuntimeState(state);
147
- routerRuntimeStateExtension.set(runtimeContext, normalized);
148
- if (normalized.serverSnapshot) routerServerSnapshotExtension.set(runtimeContext, normalized.serverSnapshot);
149
- if (previous?.instance !== normalized.instance || previous?.framework !== normalized.framework) notifyRouterRuntimeState(runtimeContext);
131
+ routerRuntimeStateExtension.set(runtimeContext, state);
132
+ if (previous?.instance !== state.instance || previous?.framework !== state.framework || previous?.navigation !== state.navigation) notifyRouterRuntimeState(runtimeContext);
150
133
  return runtimeContext;
151
134
  }
152
135
  function applyRouterServerPrepareResult(runtimeContext, result) {
153
- const state = createRouterRuntimeState({
136
+ if (result.snapshot) routerServerSnapshotExtension.set(runtimeContext, createRouterServerSnapshot(result.snapshot));
137
+ return applyRouterRuntimeState(runtimeContext, {
154
138
  ...result.state,
155
- cleanup: result.cleanup ?? result.state.cleanup,
156
- serverSnapshot: result.snapshot ?? result.state.serverSnapshot
139
+ cleanup: result.cleanup ?? result.state.cleanup
157
140
  });
158
- applyRouterRuntimeState(runtimeContext, state);
159
- return runtimeContext;
160
141
  }
161
142
  function getRouterHydrationScripts(runtimeContext) {
162
- const serverSnapshot = getRouterServerSnapshot(runtimeContext);
163
- const runtimeState = getRouterRuntimeState(runtimeContext);
164
- return serverSnapshot?.hydrationScripts ?? toHydrationScripts({
165
- hydrationScript: serverSnapshot?.hydrationScript
166
- }) ?? runtimeState?.hydrationScripts ?? toHydrationScripts({
167
- hydrationScript: runtimeState?.hydrationScript
168
- }) ?? [];
143
+ return getRouterServerSnapshot(runtimeContext)?.hydrationScripts ?? [];
169
144
  }
170
145
  function getRouterMatchedRouteIds(runtimeContext) {
171
- const serverSnapshot = getRouterServerSnapshot(runtimeContext);
172
- const runtimeState = getRouterRuntimeState(runtimeContext);
173
- return serverSnapshot?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(serverSnapshot?.matches) ?? runtimeState?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(runtimeState?.matches);
146
+ return getRouterServerSnapshot(runtimeContext)?.matchedRouteIds;
174
147
  }
175
148
  async function cleanupRouterRuntimeState(runtimeContext) {
176
149
  try {
@@ -180,7 +153,6 @@ async function cleanupRouterRuntimeState(runtimeContext) {
180
153
  exports.applyRouterRuntimeState = __webpack_exports__.applyRouterRuntimeState;
181
154
  exports.applyRouterServerPrepareResult = __webpack_exports__.applyRouterServerPrepareResult;
182
155
  exports.cleanupRouterRuntimeState = __webpack_exports__.cleanupRouterRuntimeState;
183
- exports.createRouterRuntimeState = __webpack_exports__.createRouterRuntimeState;
184
156
  exports.createRouterServerSnapshot = __webpack_exports__.createRouterServerSnapshot;
185
157
  exports.getRouterHydrationScripts = __webpack_exports__.getRouterHydrationScripts;
186
158
  exports.getRouterMatchedRouteIds = __webpack_exports__.getRouterMatchedRouteIds;
@@ -191,7 +163,6 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
191
163
  "applyRouterRuntimeState",
192
164
  "applyRouterServerPrepareResult",
193
165
  "cleanupRouterRuntimeState",
194
- "createRouterRuntimeState",
195
166
  "createRouterServerSnapshot",
196
167
  "getRouterHydrationScripts",
197
168
  "getRouterMatchedRouteIds",
@@ -32,6 +32,25 @@ __webpack_require__.d(__webpack_exports__, {
32
32
  });
33
33
  const external_routerPrefetchPolicy_js_namespaceObject = require("./routerPrefetchPolicy.js");
34
34
  const external_routerState_js_namespaceObject = require("./routerState.js");
35
+ function createReactRouterNavigation(router, Link) {
36
+ let state;
37
+ let snapshot;
38
+ return {
39
+ Link,
40
+ getSnapshot () {
41
+ if (state !== router.state) {
42
+ state = router.state;
43
+ snapshot = {
44
+ location: state.location,
45
+ params: Object.assign({}, ...state.matches.map((match)=>match.params))
46
+ };
47
+ }
48
+ return snapshot;
49
+ },
50
+ subscribe: (listener)=>router.subscribe(listener),
51
+ navigate: (href, options)=>router.navigate(href, options)
52
+ };
53
+ }
35
54
  function createRouterStatePlugin({ registryHooks }) {
36
55
  return {
37
56
  name: '@modern-js/router-runtime-policy',
@@ -46,7 +65,7 @@ function createRouterStatePlugin({ registryHooks }) {
46
65
  if ('ssr-prepare' === event.phase) {
47
66
  const { routerContext } = event.runtimeContext;
48
67
  if (!routerContext) return;
49
- const serverSnapshot = (0, external_routerState_js_namespaceObject.createRouterServerSnapshot)({
68
+ const snapshot = {
50
69
  framework: event.framework,
51
70
  basename: event.basename,
52
71
  statusCode: routerContext.statusCode,
@@ -60,19 +79,27 @@ function createRouterStatePlugin({ registryHooks }) {
60
79
  routeId: match.route.id
61
80
  }
62
81
  ] : [])
82
+ };
83
+ (0, external_routerState_js_namespaceObject.applyRouterServerPrepareResult)(event.runtimeContext, {
84
+ snapshot,
85
+ state: {
86
+ framework: event.framework,
87
+ basename: event.basename,
88
+ instance: event.router
89
+ }
63
90
  });
91
+ } else if ('client-create' === event.phase) {
92
+ const router = event.router;
93
+ const { router: api } = event.runtimeContext;
64
94
  (0, external_routerState_js_namespaceObject.applyRouterRuntimeState)(event.runtimeContext, {
65
95
  framework: event.framework,
66
96
  basename: event.basename,
67
- instance: event.router,
68
- matchedRouteIds: serverSnapshot.matchedRouteIds,
69
- serverSnapshot
97
+ instance: router,
98
+ ...api?.Link ? {
99
+ navigation: createReactRouterNavigation(router, api.Link)
100
+ } : {}
70
101
  });
71
- } else if ('client-create' === event.phase) (0, external_routerState_js_namespaceObject.applyRouterRuntimeState)(event.runtimeContext, {
72
- framework: event.framework,
73
- basename: event.basename,
74
- instance: event.router
75
- });
102
+ }
76
103
  });
77
104
  }
78
105
  };
@@ -0,0 +1,11 @@
1
+ const resolveLocalisedUrlsConfig = (option)=>{
2
+ if (option && 'object' == typeof option && Object.keys(option).length > 0) return {
3
+ enabled: true,
4
+ map: option
5
+ };
6
+ return {
7
+ enabled: false,
8
+ map: {}
9
+ };
10
+ };
11
+ export { resolveLocalisedUrlsConfig };