nuxt-typed-router 2.2.1 → 2.2.2-beta.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/dist/module.d.ts CHANGED
@@ -6,6 +6,30 @@ interface ModuleOptions {
6
6
  * @default false
7
7
  */
8
8
  plugin?: boolean;
9
+ /**
10
+ * Prevent passing a string path to `router` or `<NuxtLink/>`
11
+ * Ex:
12
+ *
13
+ * ```ts
14
+ * router.push('/login'); // Error ❌
15
+ * ```
16
+ * @default false
17
+ */
18
+ strict?: boolean | StrictOptions;
19
+ }
20
+ interface StrictOptions {
21
+ NuxtLink: StrictParamsOptions;
22
+ router: StrictParamsOptions;
23
+ }
24
+ interface StrictParamsOptions {
25
+ /**
26
+ * @default false
27
+ */
28
+ strictToArgument?: boolean;
29
+ /**
30
+ * @default false
31
+ */
32
+ strictRouteLocation?: boolean;
9
33
  }
10
34
 
11
35
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "nuxt": "^3.0.0-rc.1",
6
6
  "bridge": false
7
7
  },
8
- "version": "2.2.1"
8
+ "version": "2.2.2-beta.0"
9
9
  }
package/dist/module.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { addPluginTemplate, extendPages, defineNuxtModule, createResolver } from '@nuxt/kit';
2
2
  import chalk from 'chalk';
3
3
  import logSymbols from 'log-symbols';
4
+ import { defu } from 'defu';
4
5
  import prettier from 'prettier';
5
6
  import fs from 'fs';
6
7
  import { fileURLToPath } from 'url';
@@ -8,6 +9,66 @@ import { dirname, resolve } from 'pathe';
8
9
  import mkdirp from 'mkdirp';
9
10
  import { camelCase } from 'lodash-es';
10
11
 
12
+ class ModuleOptionsStore {
13
+ constructor() {
14
+ this.plugin = false;
15
+ this.strict = false;
16
+ this.autoImport = false;
17
+ this.rootDir = "";
18
+ }
19
+ updateOptions(options) {
20
+ if (options.plugin != null)
21
+ this.plugin = options.plugin;
22
+ if (options.strict != null)
23
+ this.strict = options.strict;
24
+ if (options.autoImport != null)
25
+ this.autoImport = options.autoImport;
26
+ if (options.rootDir != null)
27
+ this.rootDir = options.rootDir;
28
+ }
29
+ getResolvedStrictOptions() {
30
+ let resolved;
31
+ if (typeof this.strict === "boolean") {
32
+ if (this.strict) {
33
+ resolved = {
34
+ NuxtLink: {
35
+ strictRouteLocation: true,
36
+ strictToArgument: true
37
+ },
38
+ router: {
39
+ strictRouteLocation: true,
40
+ strictToArgument: true
41
+ }
42
+ };
43
+ } else {
44
+ resolved = {
45
+ NuxtLink: {
46
+ strictRouteLocation: false,
47
+ strictToArgument: false
48
+ },
49
+ router: {
50
+ strictRouteLocation: false,
51
+ strictToArgument: false
52
+ }
53
+ };
54
+ }
55
+ } else {
56
+ resolved = defu(this.strict, {
57
+ NuxtLink: {
58
+ strictRouteLocation: false,
59
+ strictToArgument: false
60
+ },
61
+ router: {
62
+ strictRouteLocation: false,
63
+ strictToArgument: false
64
+ }
65
+ });
66
+ }
67
+ return resolved;
68
+ }
69
+ }
70
+ const moduleOptionStore = new ModuleOptionsStore();
71
+
11
72
  function createRoutesNamesListExport(routesList) {
12
73
  return `
13
74
  /**
@@ -119,7 +180,24 @@ function createRoutesTypesFile({
119
180
  );
120
181
  }
121
182
 
183
+ function isItemLast(array, index) {
184
+ return array ? index === array.length - 1 : false;
185
+ }
186
+ function returnIfTrue(condition, template, otherwise) {
187
+ if (condition) {
188
+ return template;
189
+ }
190
+ return otherwise ?? "";
191
+ }
192
+ function returnIfFalse(condition, template, otherwise) {
193
+ if (!condition) {
194
+ return template;
195
+ }
196
+ return otherwise ?? "";
197
+ }
198
+
122
199
  function createTypedRouterFile() {
200
+ const strictOptions = moduleOptionStore.getResolvedStrictOptions();
123
201
  return (
124
202
  /* typescript */
125
203
  `
@@ -149,15 +227,22 @@ function createTypedRouterFile() {
149
227
  * {@link RouteLocationRaw}
150
228
  * */
151
229
  export type TypedRouteLocationRaw =
152
- | (Omit<Exclude<RouteLocationRaw, string>, 'name' | 'params'> & RoutesNamedLocations)
153
- | string;
230
+ | (Omit<Exclude<RouteLocationRaw, string>, 'name' | 'params' ${returnIfTrue(
231
+ strictOptions.NuxtLink.strictRouteLocation,
232
+ `| 'path'`
233
+ )}> & RoutesNamedLocations)
234
+ ${returnIfFalse(strictOptions.NuxtLink.strictToArgument, "| string")};
235
+
154
236
 
155
237
  /**
156
238
  * Alternative version of {@link TypedRouteLocationRaw} but with a name generic
157
239
  */
158
240
  export type TypedRouteLocationRawFromName<T extends RoutesNamesList> =
159
- | (Omit<Exclude<RouteLocationRaw, string>, 'name' | 'params'> & TypedLocationAsRelativeRaw<T>)
160
- | string;
241
+ | (Omit<Exclude<RouteLocationRaw, string>, 'name' | 'params' ${returnIfTrue(
242
+ strictOptions.NuxtLink.strictRouteLocation,
243
+ `| 'path'`
244
+ )}> & TypedLocationAsRelativeRaw<T>)
245
+ ${returnIfFalse(strictOptions.NuxtLink.strictToArgument, "| string")};
161
246
 
162
247
  /**
163
248
  * Generic providing inference and dynamic inclusion of \`params\` property
@@ -258,7 +343,9 @@ function createTypedRouterFile() {
258
343
  );
259
344
  }
260
345
 
261
- function createTypedRouterDefinitionFile({ autoImport, plugin }) {
346
+ function createTypedRouterDefinitionFile() {
347
+ const { plugin, autoImport } = moduleOptionStore;
348
+ const strictOptions = moduleOptionStore.getResolvedStrictOptions();
262
349
  return (
263
350
  /* typescript */
264
351
  `
@@ -274,17 +361,24 @@ function createTypedRouterDefinitionFile({ autoImport, plugin }) {
274
361
 
275
362
  declare global {
276
363
 
277
- ${autoImport ? (
364
+ ${returnIfTrue(
365
+ autoImport,
278
366
  /* typescript */
279
367
  `
280
368
  const useRoute: typeof _useRoute;
281
369
  const useRouter: typeof _useRouter;
282
370
  const navigateTo: typeof _navigateTo;`
283
- ) : ""}
371
+ )}
284
372
  }
285
373
 
286
374
  type TypedNuxtLinkProps = Omit<NuxtLinkProps, 'to'> & {
287
- to: string | Omit<Exclude<RouteLocationRaw, string>, 'name'> & RoutesNamedLocations;
375
+ to: ${returnIfFalse(
376
+ strictOptions.NuxtLink.strictToArgument,
377
+ "string |"
378
+ )} Omit<Exclude<RouteLocationRaw, string>, 'name' | 'params' ${returnIfTrue(
379
+ strictOptions.NuxtLink.strictRouteLocation,
380
+ `| 'path'`
381
+ )}> & RoutesNamedLocations;
288
382
  };
289
383
 
290
384
  export type TypedNuxtLink = DefineComponent<
@@ -310,7 +404,8 @@ function createTypedRouterDefinitionFile({ autoImport, plugin }) {
310
404
  }
311
405
  }
312
406
 
313
- ${plugin ? (
407
+ ${returnIfTrue(
408
+ plugin,
314
409
  /* typescript */
315
410
  `
316
411
  interface CustomPluginProperties {
@@ -325,7 +420,7 @@ function createTypedRouterDefinitionFile({ autoImport, plugin }) {
325
420
  interface ComponentCustomProperties extends CustomPluginProperties {}
326
421
  }
327
422
  `
328
- ) : ""}
423
+ )}
329
424
  `
330
425
  );
331
426
  }
@@ -543,10 +638,10 @@ dirname(fileURLToPath(import.meta.url));
543
638
  async function processPathAndWriteFile({
544
639
  content,
545
640
  fileName,
546
- rootDir,
547
641
  outDir
548
642
  }) {
549
643
  try {
644
+ const { rootDir } = moduleOptionStore;
550
645
  const finalOutDir = outDir ?? `.nuxt/typed-router`;
551
646
  const processedOutDir = resolve(rootDir, finalOutDir);
552
647
  const outputFile = resolve(process.cwd(), `${processedOutDir}/${fileName}`);
@@ -586,9 +681,6 @@ const watermarkTemplate = `
586
681
 
587
682
  let previousGeneratedRoutes = "";
588
683
  async function saveGeneratedFiles({
589
- rootDir,
590
- autoImport,
591
- plugin,
592
684
  outputData: { routesDeclTemplate, routesList, routesObjectTemplate, routesParams }
593
685
  }) {
594
686
  const filesMap = [
@@ -623,7 +715,7 @@ async function saveGeneratedFiles({
623
715
  },
624
716
  {
625
717
  fileName: `typed-router.d.ts`,
626
- content: createTypedRouterDefinitionFile({ autoImport, plugin })
718
+ content: createTypedRouterDefinitionFile()
627
719
  },
628
720
  {
629
721
  fileName: "index.ts",
@@ -637,7 +729,7 @@ async function saveGeneratedFiles({
637
729
 
638
730
  ${content}
639
731
  `;
640
- return processPathAndWriteFile({ rootDir, content: waterMakeredContent, fileName });
732
+ return processPathAndWriteFile({ content: waterMakeredContent, fileName });
641
733
  })
642
734
  );
643
735
  if (previousGeneratedRoutes !== routesList.join(",")) {
@@ -646,10 +738,6 @@ async function saveGeneratedFiles({
646
738
  }
647
739
  }
648
740
 
649
- function isItemLast(array, index) {
650
- return array ? index === array.length - 1 : false;
651
- }
652
-
653
741
  const routeParamExtractRegxp = /(:(\w+)(\(.+\)[*+]?)?(\?)?)+/g;
654
742
  function extractRouteParamsFromPath(path, isIndexFileForRouting, previousParams) {
655
743
  let params = [];
@@ -805,7 +893,6 @@ function startGenerator({ output, routesConfig }) {
805
893
  let hasLoggedNoPages = false;
806
894
  let hasRoutesDefined = false;
807
895
  async function createTypedRouter({
808
- plugin,
809
896
  nuxt,
810
897
  routesConfig,
811
898
  isHookCall = false
@@ -813,18 +900,19 @@ async function createTypedRouter({
813
900
  try {
814
901
  const rootDir = nuxt.options.rootDir;
815
902
  const autoImport = nuxt.options.imports.autoImport ?? true;
903
+ moduleOptionStore.updateOptions({ rootDir, autoImport });
816
904
  if (!isHookCall) {
817
905
  if (routesConfig) {
818
906
  await nuxt.callHook("pages:extend", routesConfig);
819
907
  return;
820
908
  }
821
909
  nuxt.hook("pages:extend", (routesConfig2) => {
822
- createTypedRouter({ nuxt, plugin, routesConfig: routesConfig2, isHookCall: true });
910
+ createTypedRouter({ nuxt, routesConfig: routesConfig2, isHookCall: true });
823
911
  });
824
912
  nuxt.hook("modules:done", () => {
825
- createTypedRouter({ nuxt, plugin, isHookCall: true });
913
+ createTypedRouter({ nuxt, isHookCall: true });
826
914
  });
827
- if (plugin) {
915
+ if (moduleOptionStore.plugin) {
828
916
  await handleAddPlugin();
829
917
  }
830
918
  return;
@@ -833,10 +921,7 @@ async function createTypedRouter({
833
921
  hasRoutesDefined = true;
834
922
  const outputData = constructRouteMap(routes);
835
923
  await saveGeneratedFiles({
836
- autoImport,
837
- rootDir,
838
- outputData,
839
- plugin
924
+ outputData
840
925
  });
841
926
  });
842
927
  setTimeout(() => {
@@ -864,11 +949,12 @@ const module = defineNuxtModule({
864
949
  compatibility: { nuxt: "^3.0.0-rc.1", bridge: false }
865
950
  },
866
951
  defaults: {
867
- plugin: false
952
+ plugin: false,
953
+ strict: false
868
954
  },
869
955
  setup(moduleOptions, nuxt) {
870
956
  const rootDir = nuxt.options.rootDir;
871
- const { plugin } = moduleOptions;
957
+ moduleOptionStore.updateOptions(moduleOptions);
872
958
  const { resolve } = createResolver(import.meta.url);
873
959
  nuxt.options.alias = {
874
960
  ...nuxt.options.alias,
@@ -877,8 +963,7 @@ const module = defineNuxtModule({
877
963
  nuxt.options.typescript.tsConfig = {
878
964
  include: ["./typed-router/typed-router.d.ts"]
879
965
  };
880
- const typedRouterOptions = { nuxt, plugin };
881
- createTypedRouter({ ...typedRouterOptions });
966
+ createTypedRouter({ nuxt });
882
967
  }
883
968
  });
884
969
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-typed-router",
3
- "version": "2.2.1",
3
+ "version": "2.2.2-beta.0",
4
4
  "description": "Provide autocompletion for pages route names generated by Nuxt router",
5
5
  "type": "module",
6
6
  "main": "./dist/module.cjs",
@@ -63,7 +63,8 @@
63
63
  "log-symbols": "^5.1.0",
64
64
  "mkdirp": "^1.0.4",
65
65
  "pathe": "1.1.0",
66
- "prettier": "2.8.3"
66
+ "prettier": "2.8.3",
67
+ "defu": "^6.1.2"
67
68
  },
68
69
  "devDependencies": {
69
70
  "@nuxt/module-builder": "^0.2.1",
@@ -74,14 +75,17 @@
74
75
  "@types/mkdirp": "^1.0.2",
75
76
  "@types/node": "^17.0.23",
76
77
  "@types/prettier": "^2.7.2",
78
+ "@typescript-eslint/eslint-plugin": "^5.49.0",
79
+ "@typescript-eslint/parser": "^5.49.0",
77
80
  "cross-env": "^7.0.3",
78
- "eslint": "8.32.0",
81
+ "eslint": "8.33.0",
79
82
  "eslint-config-prettier": "^8.6.0",
80
83
  "eslint-plugin-vue": "^9.9.0",
81
84
  "nuxt": "3.1.1",
82
85
  "playwright": "1.30.0",
83
86
  "typescript": "^4.9.4",
84
- "vitest": "^0.28.2",
87
+ "vitest": "^0.28.3",
88
+ "vue-eslint-parser": "^9.1.0",
85
89
  "vue-router": "^4.1.6",
86
90
  "vue-tsc": "^1.0.24"
87
91
  }