nuxt-typed-router 2.2.2-beta.2 → 2.3.0
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/README.md +2 -1
- package/dist/module.json +2 -2
- package/dist/module.mjs +117 -38
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
- `NuxtLink` route autocomplete and params type-check
|
|
22
22
|
- `useRouter`, `useRoute` and `navigateTo` route autocomplete and params type-check
|
|
23
23
|
- Supports optional params and catchAll routes
|
|
24
|
-
-
|
|
24
|
+
- Out of the box `i18n` support
|
|
25
25
|
- Supports routes extended by config and modules
|
|
26
26
|
|
|
27
27
|
> ⚠️ Since `v2.1.x`, `useTypedRouter` and `useTypedRoute` are no longer exported.
|
|
@@ -94,6 +94,7 @@ export default defineNuxtConfig({
|
|
|
94
94
|
- [ ] Add `path` autocomplete with TS string templates
|
|
95
95
|
- [ ] Enforce strong params typing depending of origin route
|
|
96
96
|
- [ ] Add support for `validate` in `definePageMeta`
|
|
97
|
+
- [ ] Add `strict` option to prevent path navigation
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
## Development
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -15,6 +15,8 @@ class ModuleOptionsStore {
|
|
|
15
15
|
this.strict = false;
|
|
16
16
|
this.autoImport = false;
|
|
17
17
|
this.rootDir = "";
|
|
18
|
+
this.i18n = false;
|
|
19
|
+
this.i18nLocales = [];
|
|
18
20
|
}
|
|
19
21
|
updateOptions(options) {
|
|
20
22
|
if (options.plugin != null)
|
|
@@ -25,6 +27,10 @@ class ModuleOptionsStore {
|
|
|
25
27
|
this.autoImport = options.autoImport;
|
|
26
28
|
if (options.rootDir != null)
|
|
27
29
|
this.rootDir = options.rootDir;
|
|
30
|
+
if (options.i18n != null)
|
|
31
|
+
this.i18n = options.i18n;
|
|
32
|
+
if (options.i18nLocales != null)
|
|
33
|
+
this.i18nLocales = options.i18nLocales;
|
|
28
34
|
}
|
|
29
35
|
getResolvedStrictOptions() {
|
|
30
36
|
let resolved;
|
|
@@ -171,8 +177,6 @@ function createRoutesTypesFile({
|
|
|
171
177
|
|
|
172
178
|
${createRoutesNamedLocationsResolvedExport(routesParams)}
|
|
173
179
|
|
|
174
|
-
|
|
175
|
-
|
|
176
180
|
export type RoutesNamesListRecord = ${routesDeclTemplate};
|
|
177
181
|
|
|
178
182
|
export const routesNames = ${routesObjectTemplate};
|
|
@@ -349,7 +353,7 @@ function createTypedRouterFile() {
|
|
|
349
353
|
}
|
|
350
354
|
|
|
351
355
|
function createTypedRouterDefinitionFile() {
|
|
352
|
-
const { plugin, autoImport } = moduleOptionStore;
|
|
356
|
+
const { plugin, autoImport, i18n } = moduleOptionStore;
|
|
353
357
|
const strictOptions = moduleOptionStore.getResolvedStrictOptions();
|
|
354
358
|
return (
|
|
355
359
|
/* typescript */
|
|
@@ -363,6 +367,7 @@ function createTypedRouterDefinitionFile() {
|
|
|
363
367
|
import { useRoute as _useRoute } from './__useTypedRoute';
|
|
364
368
|
import { useRouter as _useRouter } from './__useTypedRouter';
|
|
365
369
|
import { navigateTo as _navigateTo } from './__navigateTo';
|
|
370
|
+
import { useLocalePath as _useLocalePath, useLocaleRoute as _useLocaleRoute} from './__i18n-router';
|
|
366
371
|
|
|
367
372
|
declare global {
|
|
368
373
|
|
|
@@ -372,7 +377,16 @@ function createTypedRouterDefinitionFile() {
|
|
|
372
377
|
`
|
|
373
378
|
const useRoute: typeof _useRoute;
|
|
374
379
|
const useRouter: typeof _useRouter;
|
|
375
|
-
const navigateTo: typeof _navigateTo
|
|
380
|
+
const navigateTo: typeof _navigateTo;
|
|
381
|
+
${returnIfTrue(
|
|
382
|
+
i18n,
|
|
383
|
+
/* typescript */
|
|
384
|
+
`
|
|
385
|
+
const useLocalePath: typeof _useLocalePath;
|
|
386
|
+
const useLocaleRoute: typeof _useLocaleRoute;
|
|
387
|
+
`
|
|
388
|
+
)}
|
|
389
|
+
`
|
|
376
390
|
)}
|
|
377
391
|
}
|
|
378
392
|
|
|
@@ -432,31 +446,33 @@ function createTypedRouterDefinitionFile() {
|
|
|
432
446
|
}
|
|
433
447
|
|
|
434
448
|
function createIndexFile() {
|
|
449
|
+
const { i18n } = moduleOptionStore;
|
|
435
450
|
return (
|
|
436
451
|
/* typescript */
|
|
437
452
|
`
|
|
438
453
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
454
|
+
export type {
|
|
455
|
+
TypedLocationAsRelativeRaw,
|
|
456
|
+
TypedResolvedMatcherLocation,
|
|
457
|
+
TypedRoute,
|
|
458
|
+
TypedRouteFromName,
|
|
459
|
+
TypedRouteLocationFromName,
|
|
460
|
+
TypedRouteLocationRaw,
|
|
461
|
+
TypedRouteLocationRawFromName,
|
|
462
|
+
TypedRouter,
|
|
463
|
+
} from './__router';
|
|
464
|
+
export { routesNames } from './__routes';
|
|
465
|
+
export type {
|
|
466
|
+
RoutesNamedLocations,
|
|
467
|
+
RoutesNamedLocationsResolved,
|
|
468
|
+
RoutesNamesList,
|
|
469
|
+
RoutesNamesListRecord,
|
|
470
|
+
RoutesParamsRecord,
|
|
471
|
+
} from './__routes';
|
|
472
|
+
export { useRoute } from './__useTypedRoute';
|
|
473
|
+
export { useRouter } from './__useTypedRouter';
|
|
474
|
+
export { navigateTo } from './__navigateTo';
|
|
475
|
+
${returnIfTrue(i18n, `export {useLocalePath, useLocaleRoute} from './__i18n-router.ts';`)}
|
|
460
476
|
`
|
|
461
477
|
);
|
|
462
478
|
}
|
|
@@ -604,6 +620,35 @@ function createTypeUtilsRuntimeFile() {
|
|
|
604
620
|
);
|
|
605
621
|
}
|
|
606
622
|
|
|
623
|
+
function createi18nRouterFile() {
|
|
624
|
+
const { i18nLocales } = moduleOptionStore;
|
|
625
|
+
return (
|
|
626
|
+
/* typescript */
|
|
627
|
+
`
|
|
628
|
+
|
|
629
|
+
import { useLocalePath as _useLocalePath, useLocaleRoute as _useLocaleRoute} from 'vue-i18n-routing';
|
|
630
|
+
import type {TypedRouteLocationRawFromName, TypedRouteFromName} from './__router';
|
|
631
|
+
import type {RoutesNamesList} from './__routes';
|
|
632
|
+
|
|
633
|
+
export type I18nLocales = ${i18nLocales.length ? i18nLocales.map((loc) => `"${loc}"`).join("|") : "string"};
|
|
634
|
+
|
|
635
|
+
export type TypedToLocalePath = <T extends RoutesNamesList>(to: TypedRouteLocationRawFromName<T>, locale?: I18nLocales | undefined) => TypedRouteLocationRawFromName<T>;
|
|
636
|
+
|
|
637
|
+
export function useLocalePath(options?: Pick<NonNullable<Parameters<typeof _useLocalePath>[0]>, 'i18n'>): TypedToLocalePath {
|
|
638
|
+
return _useLocalePath(options) as any;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export type TypedLocaleRoute = <T extends RoutesNamesList>(to: TypedRouteLocationRawFromName<T>, locale?: I18nLocales | undefined) => TypedRouteFromName<T>;
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
export function useLocaleRoute(options?: Pick<NonNullable<Parameters<typeof _useLocaleRoute>[0]>, 'i18n'>): TypedLocaleRoute {
|
|
645
|
+
return _useLocaleRoute(options) as any;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
`
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
|
|
607
652
|
async function handleAddPlugin() {
|
|
608
653
|
const pluginName = "__typed-router.plugin.ts";
|
|
609
654
|
addPluginTemplate({
|
|
@@ -689,6 +734,7 @@ let previousGeneratedRoutes = "";
|
|
|
689
734
|
async function saveGeneratedFiles({
|
|
690
735
|
outputData: { routesDeclTemplate, routesList, routesObjectTemplate, routesParams }
|
|
691
736
|
}) {
|
|
737
|
+
const { i18n } = moduleOptionStore;
|
|
692
738
|
const filesMap = [
|
|
693
739
|
{
|
|
694
740
|
fileName: "__useTypedRouter.ts",
|
|
@@ -728,6 +774,12 @@ async function saveGeneratedFiles({
|
|
|
728
774
|
content: createIndexFile()
|
|
729
775
|
}
|
|
730
776
|
];
|
|
777
|
+
if (i18n) {
|
|
778
|
+
filesMap.push({
|
|
779
|
+
fileName: "__i18n-router.ts",
|
|
780
|
+
content: createi18nRouterFile()
|
|
781
|
+
});
|
|
782
|
+
}
|
|
731
783
|
await Promise.all(
|
|
732
784
|
filesMap.map(({ content, fileName }) => {
|
|
733
785
|
const waterMakeredContent = `
|
|
@@ -806,6 +858,22 @@ function extractChunkMain(chunkName) {
|
|
|
806
858
|
return chunkArray?.join("/");
|
|
807
859
|
}
|
|
808
860
|
|
|
861
|
+
function createKeyedName(route) {
|
|
862
|
+
const splittedPaths = route.path.split("/");
|
|
863
|
+
const parentPath = splittedPaths[splittedPaths.length - 1];
|
|
864
|
+
const nameKey = camelCase(parentPath || "index");
|
|
865
|
+
return nameKey;
|
|
866
|
+
}
|
|
867
|
+
function createNameKeyFromFullName(route, level, parentName) {
|
|
868
|
+
let splitted = [];
|
|
869
|
+
splitted = route.name?.split("-") ?? [];
|
|
870
|
+
splitted = splitted.slice(level, splitted.length);
|
|
871
|
+
if (splitted[0] === parentName) {
|
|
872
|
+
splitted.splice(0, 1);
|
|
873
|
+
}
|
|
874
|
+
const keyName = route.path === "" ? "index" : camelCase(splitted.join("-")) || "index";
|
|
875
|
+
return keyName;
|
|
876
|
+
}
|
|
809
877
|
function walkThoughRoutes({
|
|
810
878
|
route,
|
|
811
879
|
level,
|
|
@@ -822,9 +890,14 @@ function walkThoughRoutes({
|
|
|
822
890
|
const isRootSibling = lastChunkArray === "index";
|
|
823
891
|
if (route.children?.length && !haveMatchingSiblings || !route.children?.length && haveMatchingSiblings && isRootSibling) {
|
|
824
892
|
let childrenChunks = haveMatchingSiblings ? matchingSiblings : route.children;
|
|
825
|
-
|
|
826
|
-
const
|
|
827
|
-
|
|
893
|
+
let nameKey = createKeyedName(route);
|
|
894
|
+
const hasSamePathI18nSibling = siblings?.some((sibling) => {
|
|
895
|
+
const _name = createKeyedName(sibling);
|
|
896
|
+
return _name === nameKey;
|
|
897
|
+
});
|
|
898
|
+
if (hasSamePathI18nSibling) {
|
|
899
|
+
nameKey = camelCase(route.path.split("/").join("-"));
|
|
900
|
+
}
|
|
828
901
|
output.routesObjectTemplate += `${nameKey}:{`;
|
|
829
902
|
output.routesDeclTemplate += `"${nameKey}":{`;
|
|
830
903
|
const allRouteParams = extractRouteParamsFromPath(route.path, false, previousParams);
|
|
@@ -842,13 +915,14 @@ function walkThoughRoutes({
|
|
|
842
915
|
output.routesObjectTemplate += "},";
|
|
843
916
|
output.routesDeclTemplate += `}${isLast ? "" : ","}`;
|
|
844
917
|
} else if (route.name) {
|
|
845
|
-
let
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
918
|
+
let keyName = createNameKeyFromFullName(route, level, parentName);
|
|
919
|
+
const hasSameNameI18nSibling = siblings?.some((sibling) => {
|
|
920
|
+
const _name = createNameKeyFromFullName(sibling, level, parentName);
|
|
921
|
+
return _name === keyName;
|
|
922
|
+
});
|
|
923
|
+
if (hasSameNameI18nSibling) {
|
|
924
|
+
keyName = camelCase(route.name);
|
|
850
925
|
}
|
|
851
|
-
const keyName = route.path === "" ? "index" : camelCase(splitted.join("-")) || "index";
|
|
852
926
|
output.routesObjectTemplate += `'${keyName}': '${route.name}' as const,`;
|
|
853
927
|
output.routesDeclTemplate += `"${keyName}": "${route.name}"${isLast ? "" : ","}`;
|
|
854
928
|
output.routesList.push(route.name);
|
|
@@ -883,7 +957,7 @@ function constructRouteMap(routesConfig) {
|
|
|
883
957
|
}
|
|
884
958
|
function startGenerator({ output, routesConfig }) {
|
|
885
959
|
routesConfig.forEach((route, index) => {
|
|
886
|
-
const rootSiblingsRoutes = routesConfig.filter((rt) => rt.
|
|
960
|
+
const rootSiblingsRoutes = routesConfig.filter((rt) => rt.path !== route.path);
|
|
887
961
|
walkThoughRoutes({
|
|
888
962
|
route,
|
|
889
963
|
level: 0,
|
|
@@ -952,16 +1026,21 @@ const module = defineNuxtModule({
|
|
|
952
1026
|
meta: {
|
|
953
1027
|
name: "nuxt-typed-router",
|
|
954
1028
|
configKey: "nuxtTypedRouter",
|
|
955
|
-
compatibility: { nuxt: "^3.0.0
|
|
1029
|
+
compatibility: { nuxt: "^3.0.0", bridge: false }
|
|
956
1030
|
},
|
|
957
1031
|
defaults: {
|
|
958
1032
|
plugin: false,
|
|
959
1033
|
strict: false
|
|
960
1034
|
},
|
|
961
1035
|
setup(moduleOptions, nuxt) {
|
|
962
|
-
const rootDir = nuxt.options.rootDir;
|
|
963
|
-
moduleOptionStore.updateOptions(moduleOptions);
|
|
964
1036
|
const { resolve } = createResolver(import.meta.url);
|
|
1037
|
+
const rootDir = nuxt.options.rootDir;
|
|
1038
|
+
const hasi18nModuleRegistered = !!nuxt.options.modules.find((mod) => mod === "@nuxtjs/i18n");
|
|
1039
|
+
moduleOptionStore.updateOptions({
|
|
1040
|
+
...moduleOptions,
|
|
1041
|
+
i18n: hasi18nModuleRegistered,
|
|
1042
|
+
i18nLocales: nuxt.options?.i18n?.locales ?? []
|
|
1043
|
+
});
|
|
965
1044
|
nuxt.options.alias = {
|
|
966
1045
|
...nuxt.options.alias,
|
|
967
1046
|
"@typed-router": resolve(`${rootDir}/.nuxt/typed-router`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-typed-router",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Provide autocompletion for pages route names generated by Nuxt router",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/module.cjs",
|
|
@@ -71,12 +71,14 @@
|
|
|
71
71
|
"@nuxt/test-utils": "^3.1.1",
|
|
72
72
|
"@nuxt/types": "^2.15.8",
|
|
73
73
|
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
|
74
|
+
"@nuxtjs/web-vitals": "^0.2.2",
|
|
75
|
+
"@nuxtjs/i18n": "8.0.0-beta.9",
|
|
74
76
|
"@types/lodash-es": "^4.17.6",
|
|
75
77
|
"@types/mkdirp": "^1.0.2",
|
|
76
78
|
"@types/node": "^17.0.23",
|
|
77
79
|
"@types/prettier": "^2.7.2",
|
|
78
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
79
|
-
"@typescript-eslint/parser": "^5.
|
|
80
|
+
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
|
81
|
+
"@typescript-eslint/parser": "^5.50.0",
|
|
80
82
|
"@vue/test-utils": "^2.2.8",
|
|
81
83
|
"cross-env": "^7.0.3",
|
|
82
84
|
"eslint": "8.33.0",
|
|
@@ -84,7 +86,7 @@
|
|
|
84
86
|
"eslint-plugin-vue": "^9.9.0",
|
|
85
87
|
"nuxt": "3.1.1",
|
|
86
88
|
"playwright": "1.30.0",
|
|
87
|
-
"typescript": "^4.9.
|
|
89
|
+
"typescript": "^4.9.5",
|
|
88
90
|
"vitest": "^0.28.3",
|
|
89
91
|
"vue-eslint-parser": "^9.1.0",
|
|
90
92
|
"vue-router": "^4.1.6",
|