nuxt-typed-router 3.3.1 → 3.3.3

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.
@@ -0,0 +1,84 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ interface ModuleOptions {
4
+ /**
5
+ *
6
+ * Enables path autocomplete and path validity for programmatic validation
7
+ *
8
+ * @default true
9
+ */
10
+ pathCheck?: boolean;
11
+ /**
12
+ * Set to false if you don't want a plugin generated
13
+ * @default false
14
+ */
15
+ plugin?: boolean;
16
+ /**
17
+ * Customise Route location arguments strictness for `NuxtLink` or `router`
18
+ * All strict options are disabled by default.
19
+ * You can tweak options to add strict router navigation options.
20
+ *
21
+ * By passing `true` you can enable all of them
22
+ *
23
+ * @default false
24
+ */
25
+ strict?: boolean | StrictOptions;
26
+ /**
27
+ * Remove Nuxt definitions to avoid conflicts
28
+ * @default true
29
+ */
30
+ experimentalRemoveNuxtDefs?: boolean;
31
+ /**
32
+ * ⚠️ Experimental
33
+ *
34
+ * Exclude certain routes from being included into the generated types
35
+ * Ex: 404 routes or catchAll routes
36
+ */
37
+ experimentalIgnoreRoutes?: string[];
38
+ }
39
+ interface StrictOptions {
40
+ NuxtLink?: StrictParamsOptions;
41
+ router?: StrictParamsOptions;
42
+ }
43
+ interface StrictParamsOptions {
44
+ /**
45
+ * Prevent passing string path to the RouteLocation argument.
46
+ *
47
+ * Ex:
48
+ * ```vue
49
+ * <template>
50
+ * <NuxtLink to='/login'/> // Error ❌
51
+ * </template>
52
+ * ```
53
+ * Or
54
+ * ```ts
55
+ * router.push('/login'); // Error ❌
56
+ * navigateTo('/login'); // Error ❌
57
+ * ```
58
+ *
59
+ * @default false
60
+ */
61
+ strictToArgument?: boolean;
62
+ /**
63
+ * Prevent passing a `params` property in the RouteLocation argument.
64
+ *
65
+ * Ex:
66
+ * ```vue
67
+ * <template>
68
+ * <NuxtLink :to='{path: "/login"}'/> // Error ❌
69
+ * </template>
70
+ * ```
71
+ * Or
72
+ * ```ts
73
+ * router.push({path: "/login"}); // Error ❌
74
+ * navigateTo({path: "/login"}); // Error ❌
75
+ * ```
76
+ *
77
+ * @default false
78
+ */
79
+ strictRouteLocation?: boolean;
80
+ }
81
+
82
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
83
+
84
+ export { type ModuleOptions, _default as default };
package/dist/module.d.ts CHANGED
@@ -81,4 +81,4 @@ interface StrictParamsOptions {
81
81
 
82
82
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
83
83
 
84
- export { ModuleOptions, _default as default };
84
+ export { type ModuleOptions, _default as default };
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "nuxt": "^3.0.0",
6
6
  "bridge": false
7
7
  },
8
- "version": "3.3.1"
8
+ "version": "3.3.3"
9
9
  }
package/dist/module.mjs CHANGED
@@ -13,20 +13,18 @@ import { camelCase } from 'lodash-es';
13
13
  import { readFile } from 'fs/promises';
14
14
 
15
15
  class ModuleOptionsStore {
16
- constructor() {
17
- this.plugin = false;
18
- this.strict = false;
19
- this.pathCheck = true;
20
- this.autoImport = false;
21
- this.rootDir = "";
22
- this.buildDir = "";
23
- this.srcDir = "";
24
- this.pagesDir = "";
25
- this.i18n = false;
26
- this.i18nOptions = null;
27
- this.i18nLocales = [];
28
- this.experimentalIgnoreRoutes = [];
29
- }
16
+ plugin = false;
17
+ strict = false;
18
+ pathCheck = true;
19
+ autoImport = false;
20
+ rootDir = "";
21
+ buildDir = "";
22
+ srcDir = "";
23
+ pagesDir = "";
24
+ i18n = false;
25
+ i18nOptions = null;
26
+ i18nLocales = [];
27
+ experimentalIgnoreRoutes = [];
30
28
  updateOptions(options) {
31
29
  if (options.plugin != null)
32
30
  this.plugin = options.plugin;
@@ -214,7 +212,7 @@ function createLocaleRoutePathSchema(routePaths) {
214
212
  ${routePaths.filter((f) => !!f.path && !f.isLocale).map((route) => `"${route.path}"`).join("|")}
215
213
  `;
216
214
  }
217
- function createValidatePathTypes(pathElements, withLocale = false) {
215
+ function createValidatePathTypes(pathElements, routesList, withLocale = false) {
218
216
  let pathConditions = pathElements.map(createTypeValidatePathCondition).filter((f) => {
219
217
  if (withLocale) {
220
218
  return !f.isLocale;
@@ -237,14 +235,14 @@ function createValidatePathTypes(pathElements, withLocale = false) {
237
235
  : ${pathConditions.length ? `\`Error: \${${pathConditions.map((t) => `${t.typeName}<T>`).join("|")}}\`` : "never"}
238
236
  : never;
239
237
 
240
-
238
+ // RouteNameFromPath, RouteNameFromLocalePath
241
239
  export type RouteNameFrom${returnIfTrue(
242
240
  withLocale,
243
241
  "Locale"
244
242
  )}Path<T extends string> = T extends string
245
243
  ? T extends '/'
246
244
  ? "index"
247
- ${pathConditions.length ? `: ${pathConditions.map((t) => `${t.typeName}<T> extends true ? "${t.routeName}"`).join(": ")} : never` : ": never"}
245
+ ${pathConditions.length ? `: ${pathConditions.filter((f) => routesList.includes(f.routeName)).map((t) => `${t.typeName}<T> extends true ? "${t.routeName}"`).join(": ")} : never` : ": never"}
248
246
  : never;
249
247
 
250
248
  `;
@@ -535,6 +533,7 @@ function createTypedRouterDefinitionFile() {
535
533
  import type {TypedRouter, TypedRoute, TypedRouteLocationRawFromName, TypedLocationAsRelativeRaw} from './__router';
536
534
  import { useRoute as _useRoute } from './__useTypedRoute';
537
535
  import { useRouter as _useRouter } from './__useTypedRouter';
536
+ import { useLink as _useLink } from './__useTypedLink';
538
537
  import { navigateTo as _navigateTo } from './__navigateTo';
539
538
  ${returnIfTrue(
540
539
  i18n,
@@ -554,6 +553,7 @@ function createTypedRouterDefinitionFile() {
554
553
  `
555
554
  const useRoute: typeof _useRoute;
556
555
  const useRouter: typeof _useRouter;
556
+ const useLink: typeof _useLink;
557
557
  const navigateTo: typeof _navigateTo;
558
558
  const definePageMeta: typeof _definePageMeta;
559
559
 
@@ -655,6 +655,7 @@ function createIndexFile() {
655
655
  } from './__routes';
656
656
  export { useRoute } from './__useTypedRoute';
657
657
  export { useRouter } from './__useTypedRouter';
658
+ export { useLink } from './__useTypedLink';
658
659
  export { navigateTo } from './__navigateTo';
659
660
  export { definePageMeta } from './__definePageMeta';
660
661
  export { helpers } from './__helpers';
@@ -682,7 +683,7 @@ function createPluginFile() {
682
683
  /* typescript */
683
684
  `
684
685
 
685
- import { defineNuxtPlugin, useRouter, useRoute } from '#app';
686
+ import { defineNuxtPlugin, useRouter, useRoute } from '#imports';
686
687
  import {TypedRouter, TypedRoute, routesNames} from '@typed-router';
687
688
 
688
689
  export default defineNuxtPlugin(() => {
@@ -705,7 +706,7 @@ function createUseTypedRouteFile() {
705
706
  return (
706
707
  /* typescript */
707
708
  `
708
- import { useRoute as defaultRoute } from '#app';
709
+ import { useRoute as defaultRoute } from '#imports';
709
710
  import type { RoutesNamesList } from './__routes';
710
711
  import type {TypedRoute, TypedRouteFromName} from './__router'
711
712
 
@@ -746,7 +747,7 @@ function createUseTypedRouterFile() {
746
747
  /* typescript */
747
748
  `
748
749
 
749
- import { useRouter as defaultRouter } from '#app';
750
+ import { useRouter as defaultRouter } from '#imports';
750
751
  import type { TypedRouter } from './__router';
751
752
 
752
753
  /**
@@ -768,13 +769,76 @@ function createUseTypedRouterFile() {
768
769
  );
769
770
  }
770
771
 
772
+ function createUseTypedLinkFile() {
773
+ const strictOptions = moduleOptionStore.getResolvedStrictOptions();
774
+ const { pathCheck } = moduleOptionStore;
775
+ return (
776
+ /* typescript */
777
+ `
778
+
779
+ import { useLink as defaultLink } from '#imports';
780
+ import type {MaybeRef} from 'vue';
781
+ import type { NavigateToOptions } from 'nuxt/dist/app/composables/router';
782
+ import type { NavigationFailure } from 'vue-router';
783
+ import type { TypedRouteLocationRawFromName, TypedRouteFromName, TypedRoute } from './__router';
784
+ import type { RoutesNamesList } from './__routes';
785
+ ${returnIfTrue(
786
+ pathCheck,
787
+ `import type {TypedPathParameter, RouteNameFromPath} from './__paths';`
788
+ )}
789
+
790
+
791
+ type LinkedRoute<T extends RoutesNamesList> = {
792
+ route: ComputedRef<TypedRouteFromName<T> & {
793
+ href: string;
794
+ }>;
795
+ href: ComputedRef<string>;
796
+ isActive: ComputedRef<boolean>;
797
+ isExactActive: ComputedRef<boolean>;
798
+ navigate: (e?: MouseEvent) => Promise<void | NavigationFailure>;
799
+ };
800
+
801
+
802
+ interface UseLinkFunction {
803
+ <T extends RoutesNamesList, P extends string>(
804
+ props: {
805
+ to: MaybeRef<TypedRouteLocationRawFromName<T, P>>,
806
+ replace?: MaybeRef<boolean>
807
+ }
808
+ ) : LinkedRoute<T>
809
+ ${returnIfTrue(
810
+ pathCheck && !strictOptions.router.strictToArgument,
811
+ `<T extends string>(
812
+ props: {
813
+ to: MaybeRef<TypedPathParameter<T>>,
814
+ replace?: MaybeRef<boolean>
815
+ }
816
+ ) : LinkedRoute<RouteNameFromPath<T>>`
817
+ )}
818
+ }
819
+
820
+ /**
821
+ * Typed clone of \`useLink\`
822
+ *
823
+ * @exemple
824
+ *
825
+ * \`\`\`ts
826
+ * const router = useLink(props);
827
+ * \`\`\`
828
+ */
829
+ export const useLink: UseLinkFunction = defaultLink as any;
830
+
831
+ `
832
+ );
833
+ }
834
+
771
835
  function createNavigateToFile() {
772
836
  const { router } = moduleOptionStore.getResolvedStrictOptions();
773
837
  const { pathCheck } = moduleOptionStore;
774
838
  return (
775
839
  /* typescript */
776
840
  `
777
- import { navigateTo as defaultNavigateTo } from '#app';
841
+ import { navigateTo as defaultNavigateTo } from '#imports';
778
842
  import type { NavigateToOptions } from 'nuxt/dist/app/composables/router';
779
843
  import type { NavigationFailure } from 'vue-router';
780
844
  import type { TypedRouteLocationRawFromName, TypedRouteFromName, TypedRoute } from './__router';
@@ -812,7 +876,8 @@ function createNavigateToFile() {
812
876
  ) : Promise<void | NavigationFailure | TypedRouteFromName<RouteNameFromPath<T>>>`
813
877
  )}
814
878
  }
815
- export const navigateTo: NavigateToFunction = defaultNavigateTo as any;
879
+
880
+ export const navigateTo: NavigateToFunction = defaultNavigateTo as any;
816
881
 
817
882
  `
818
883
  );
@@ -994,7 +1059,7 @@ function extractPathElements(partOfPath, route) {
994
1059
  return { pathElements, strippedPath };
995
1060
  }
996
1061
 
997
- function createPathsFiles({ routesPaths }) {
1062
+ function createPathsFiles({ routesPaths, routesList }) {
998
1063
  const { i18n, i18nOptions } = moduleOptionStore;
999
1064
  const hasPrefixStrategy = i18n && i18nOptions?.strategy !== "no_prefix";
1000
1065
  const filteredRoutesPaths = routesPaths.filter((route) => !routesPaths.find((r) => `${route.path}/` === r.path)).map((route) => ({
@@ -1042,8 +1107,8 @@ function createPathsFiles({ routesPaths }) {
1042
1107
  const pathElements = filteredRoutesPaths.filter((f) => f.path && f.path !== "/").map((route) => {
1043
1108
  return route.path.split("/").filter((f) => f.length).map((m) => destructurePath(m, route));
1044
1109
  }).filter((f) => f.length);
1045
- const validatePathTypes = createValidatePathTypes(pathElements);
1046
- const validateLocalePathTypes = createValidatePathTypes(pathElements, true);
1110
+ const validatePathTypes = createValidatePathTypes(pathElements, routesList);
1111
+ const validateLocalePathTypes = createValidatePathTypes(pathElements, routesList, true);
1047
1112
  return (
1048
1113
  /* typescript */
1049
1114
  `
@@ -1301,6 +1366,10 @@ async function saveGeneratedFiles({ outputData }) {
1301
1366
  fileName: "__useTypedRoute.ts",
1302
1367
  content: createUseTypedRouteFile()
1303
1368
  },
1369
+ {
1370
+ fileName: "__useTypedLink.ts",
1371
+ content: createUseTypedLinkFile()
1372
+ },
1304
1373
  {
1305
1374
  fileName: "__paths.d.ts",
1306
1375
  content: createPathsFiles(outputData)
@@ -1445,7 +1514,7 @@ function walkThoughRoutes({
1445
1514
  return;
1446
1515
  }
1447
1516
  const newPath = `${parent?.path ?? ""}${route.path.startsWith("/") || parent?.path === "/" ? route.path : `/${route.path}`}`;
1448
- if (parent?.path !== "/") {
1517
+ if (parent?.path !== "/" || newPath !== parent?.path) {
1449
1518
  output.routesPaths.push({
1450
1519
  name: route.name,
1451
1520
  path: newPath,
@@ -0,0 +1,16 @@
1
+
2
+ import type { ModuleOptions } from './module'
3
+
4
+
5
+ declare module '@nuxt/schema' {
6
+ interface NuxtConfig { ['nuxtTypedRouter']?: Partial<ModuleOptions> }
7
+ interface NuxtOptions { ['nuxtTypedRouter']?: ModuleOptions }
8
+ }
9
+
10
+ declare module 'nuxt/schema' {
11
+ interface NuxtConfig { ['nuxtTypedRouter']?: Partial<ModuleOptions> }
12
+ interface NuxtOptions { ['nuxtTypedRouter']?: ModuleOptions }
13
+ }
14
+
15
+
16
+ export type { ModuleOptions, default } from './module'
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
- import { ModuleOptions } from './module'
2
+ import type { ModuleOptions } from './module'
3
+
3
4
 
4
5
  declare module '@nuxt/schema' {
5
6
  interface NuxtConfig { ['nuxtTypedRouter']?: Partial<ModuleOptions> }
@@ -12,4 +13,4 @@ declare module 'nuxt/schema' {
12
13
  }
13
14
 
14
15
 
15
- export { ModuleOptions, default } from './module'
16
+ export type { ModuleOptions, default } from './module'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-typed-router",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "description": "Provide autocompletion for routes paths, names and params in Nuxt apps",
5
5
  "type": "module",
6
6
  "main": "./dist/module.cjs",
@@ -15,11 +15,11 @@
15
15
  "dist"
16
16
  ],
17
17
  "scripts": {
18
- "prepack": "nuxt-module-build",
18
+ "prepack": "nuxt-module-build build",
19
19
  "dev": "nuxi dev playground",
20
20
  "dev:build": "nuxi build playground",
21
21
  "prepare:playground": "nuxi prepare playground",
22
- "dev:prepare": "nuxt-module-build --stub && nuxi prepare playground && pnpm run test:prepare-fixtures",
22
+ "dev:prepare": "nuxt-module-build build --stub && nuxi prepare playground && pnpm run test:prepare-fixtures",
23
23
  "build:test": "cross-env NUXT_BUILD_TYPE=stub pnpm run prepack && pnpm run dev:build",
24
24
  "test:prepare-fixtures": "nuxi prepare test/fixtures/simple && nuxi prepare test/fixtures/withOptions && nuxi prepare test/fixtures/complex",
25
25
  "test:fixtures": "vitest run --dir test",
@@ -60,44 +60,44 @@
60
60
  "url": "https://github.com/victorgarciaesgi/nuxt-typed-router/issues"
61
61
  },
62
62
  "dependencies": {
63
- "@nuxt/kit": "^3.6.5",
64
- "chalk": "^5.3.0",
65
- "defu": "^6.1.2",
66
- "lodash-es": "^4.17.21",
67
- "log-symbols": "^5.1.0",
68
- "mkdirp": "^3.0.1",
69
- "nanoid": "^4.0.2",
63
+ "@nuxt/kit": "3.8.1",
64
+ "chalk": "5.3.0",
65
+ "defu": "6.1.3",
66
+ "lodash-es": "4.17.21",
67
+ "log-symbols": "5.1.0",
68
+ "mkdirp": "3.0.1",
69
+ "nanoid": "5.0.3",
70
70
  "pathe": "1.1.1"
71
71
  },
72
72
  "devDependencies": {
73
- "@nuxt/devtools": "^0.8.0",
74
- "@nuxt/module-builder": "^0.4.0",
75
- "@nuxt/test-utils": "^3.6.5",
76
- "@nuxt/types": "^2.17.1",
77
- "@nuxtjs/eslint-config-typescript": "^12.0.0",
73
+ "@nuxt/devtools": "1.0.0",
74
+ "@nuxt/module-builder": "0.5.4",
75
+ "@nuxt/test-utils": "3.8.1",
76
+ "@nuxt/types": "2.17.2",
77
+ "@nuxtjs/eslint-config-typescript": "12.1.0",
78
78
  "@nuxtjs/i18n": "8.0.0-beta.10",
79
- "@nuxtjs/web-vitals": "^0.2.6",
80
- "@types/lodash-es": "^4.17.8",
81
- "@types/node": "^20.5.0",
82
- "@types/prettier": "^3.0.0",
83
- "@typescript-eslint/eslint-plugin": "^6.4.0",
84
- "@typescript-eslint/parser": "^6.4.0",
85
- "@vue/test-utils": "^2.4.1",
86
- "bumpp": "9.1.1",
87
- "changelogithub": "0.12.12",
88
- "cross-env": "^7.0.3",
89
- "eslint": "8.47.0",
90
- "eslint-config-prettier": "^9.0.0",
91
- "eslint-plugin-vue": "^9.17.0",
92
- "nuxt": "3.6.5",
93
- "nuxt-seo-kit": "1.3.9",
79
+ "@nuxtjs/web-vitals": "0.2.6",
80
+ "@types/lodash-es": "4.17.11",
81
+ "@types/node": "20.9.0",
82
+ "@types/prettier": "3.0.0",
83
+ "@typescript-eslint/eslint-plugin": "6.10.0",
84
+ "@typescript-eslint/parser": "6.10.0",
85
+ "@vue/test-utils": "2.4.1",
86
+ "bumpp": "9.2.0",
87
+ "changelogithub": "0.13.2",
88
+ "cross-env": "7.0.3",
89
+ "eslint": "8.53.0",
90
+ "eslint-config-prettier": "9.0.0",
91
+ "eslint-plugin-vue": "9.18.1",
92
+ "nuxt": "3.8.1",
93
+ "nuxt-seo-kit": "1.3.13",
94
94
  "playwright": "1.37.0",
95
- "prettier": "3.0.2",
96
- "tsd": "^0.28.1",
97
- "typescript": "^5.1.6",
98
- "vitest": "^0.34.2",
99
- "vue-eslint-parser": "^9.3.1",
100
- "vue-router": "^4.2.4",
101
- "vue-tsc": "^1.8.8"
95
+ "prettier": "3.0.3",
96
+ "tsd": "0.29.0",
97
+ "typescript": "5.2.2",
98
+ "vitest": "0.34.6",
99
+ "vue-eslint-parser": "9.3.2",
100
+ "vue-router": "4.2.5",
101
+ "vue-tsc": "1.8.22"
102
102
  }
103
103
  }