nuxt-typed-router 3.0.0-beta.8 → 3.0.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 CHANGED
@@ -29,7 +29,7 @@
29
29
 
30
30
  <br/>
31
31
  <p align="center">
32
- <img src="https://github.com/victorgarciaesgi/nuxt-typed-router/blob/master/.github/images/nuxt-router.gif?raw=true"/>
32
+ <img src="https://github.com/victorgarciaesgi/nuxt-typed-router/blob/master/.github/images/nuxt-typed-router.gif?raw=true"/>
33
33
  </p>
34
34
  <br/>
35
35
 
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "nuxt": "^3.0.0",
6
6
  "bridge": false
7
7
  },
8
- "version": "3.0.0-beta.8"
8
+ "version": "3.0.0"
9
9
  }
package/dist/module.mjs CHANGED
@@ -162,19 +162,42 @@ function createRoutesParamsRecordResolvedExport(routesParams) {
162
162
  }`;
163
163
  }
164
164
 
165
+ function isItemLast(array, index) {
166
+ return array ? index === array.length - 1 : false;
167
+ }
168
+ function returnIfTrue(condition, template, otherwise) {
169
+ if (condition) {
170
+ return template;
171
+ }
172
+ return otherwise ?? "";
173
+ }
174
+
165
175
  const nanoid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10);
166
176
  function createRoutePathSchema(routePaths) {
167
177
  return `export type RoutePathSchema =
168
178
  ${routePaths.filter((f) => !!f.path).map((route) => `"${route.path}"`).join("|")}
169
179
  `;
170
180
  }
171
- function createValidatePathTypes(pathElements) {
172
- let pathConditions = pathElements.map(createTypeValidatePathCondition);
181
+ function createLocaleRoutePathSchema(routePaths) {
182
+ return `export type LocaleRoutePathSchema =
183
+ ${routePaths.filter((f) => !!f.path && !f.isLocale).map((route) => `"${route.path}"`).join("|")}
184
+ `;
185
+ }
186
+ function createValidatePathTypes(pathElements, withLocale = false) {
187
+ let pathConditions = pathElements.map(createTypeValidatePathCondition).filter((f) => {
188
+ if (withLocale) {
189
+ return !f.isLocale;
190
+ }
191
+ return true;
192
+ });
173
193
  const conditionsList = pathConditions.map((m) => m.condition);
174
194
  return `
175
195
  ${pathConditions.length ? conditionsList.join("\n\n") : ""}
176
196
 
177
- export type ValidatePath<T extends string> = T extends string
197
+ export type Validate${returnIfTrue(
198
+ withLocale,
199
+ "Locale"
200
+ )}Path<T extends string> = T extends string
178
201
  ? T extends '/'
179
202
  ? T
180
203
  ${pathConditions.length ? `:${pathConditions.map((t) => `${t.typeName}<T> extends true ? T`).join(": ")}` : ""}
@@ -184,7 +207,10 @@ function createValidatePathTypes(pathElements) {
184
207
  : never;
185
208
 
186
209
 
187
- export type RouteNameFromPath<T extends string> = T extends string
210
+ export type RouteNameFrom${returnIfTrue(
211
+ withLocale,
212
+ "Locale"
213
+ )}Path<T extends string> = T extends string
188
214
  ? T extends '/'
189
215
  ? "index"
190
216
  ${pathConditions.length ? `: ${pathConditions.map((t) => `${t.typeName}<T> extends true ? "${t.routeName}"`).join(": ")} : never` : ": never"}
@@ -197,6 +223,7 @@ function createTypeValidatePathCondition(elements) {
197
223
  const params = /* @__PURE__ */ new Map();
198
224
  const routeName = elements.flat()[0].routeName;
199
225
  const hasOnlyNames = elements.flat().every((elem) => elem.type === "name");
226
+ const isLocale = elements.flat()[0].isLocale;
200
227
  const condition = `type ${typeName}<T> = T extends \`/${elements.map((elementArray, index) => {
201
228
  return elementArray.map((elem) => {
202
229
  const isLast = index === elements.flat().length - 1;
@@ -238,7 +265,8 @@ function createTypeValidatePathCondition(elements) {
238
265
  return {
239
266
  typeName,
240
267
  condition,
241
- routeName
268
+ routeName,
269
+ isLocale
242
270
  };
243
271
  }
244
272
 
@@ -276,16 +304,6 @@ function createRoutesTypesFile({
276
304
  );
277
305
  }
278
306
 
279
- function isItemLast(array, index) {
280
- return array ? index === array.length - 1 : false;
281
- }
282
- function returnIfTrue(condition, template, otherwise) {
283
- if (condition) {
284
- return template;
285
- }
286
- return otherwise ?? "";
287
- }
288
-
289
307
  function createTypedRouterFile() {
290
308
  const strictOptions = moduleOptionStore.getResolvedStrictOptions();
291
309
  const { i18n, experimentalPathCheck } = moduleOptionStore;
@@ -776,7 +794,7 @@ function createi18nRouterFile() {
776
794
  import type {RoutesNamesList} from './__routes';
777
795
  ${returnIfTrue(
778
796
  experimentalPathCheck,
779
- `import type {TypedPathParameter, RouteNameFromPath} from './__paths';`
797
+ `import type {TypedLocalePathParameter, RouteNameFromLocalePath} from './__paths';`
780
798
  )}
781
799
 
782
800
  export type I18nLocales = ${i18nOptions?.locales?.length ? i18nOptions.locales.map((loc) => `"${loc}"`).join("|") : "string"};
@@ -791,9 +809,9 @@ function createi18nRouterFile() {
791
809
  ${returnIfTrue(
792
810
  experimentalPathCheck && !router.strictToArgument,
793
811
  `<T extends string>(
794
- to: TypedPathParameter<T>,
812
+ to: TypedLocalePathParameter<T>,
795
813
  locale?: I18nLocales | undefined
796
- ) : [T] extends [never] ? string : Required<TypedRouteLocationRawFromName<RouteNameFromPath<T>, T>>;`
814
+ ) : [T] extends [never] ? string : Required<TypedRouteLocationRawFromName<RouteNameFromLocalePath<T>, T>>;`
797
815
  )}
798
816
  }
799
817
 
@@ -805,7 +823,7 @@ function createi18nRouterFile() {
805
823
  <T extends RoutesNamesList, P extends string>(to: TypedRouteLocationRawFromName<T, P>, locale?: I18nLocales | undefined) : TypedRouteFromName<T>
806
824
  ${returnIfTrue(
807
825
  experimentalPathCheck && !router.strictToArgument,
808
- ` <T extends string>(to: TypedPathParameter<T>, locale?: I18nLocales | undefined) : TypedRouteFromName<RouteNameFromPath<T>>;`
826
+ ` <T extends string>(to: TypedLocalePathParameter<T>, locale?: I18nLocales | undefined) : TypedRouteFromName<RouteNameFromLocalePath<T>>;`
809
827
  )}
810
828
  }
811
829
 
@@ -838,12 +856,6 @@ function extractParamsFromPathDecl(path) {
838
856
  } while (matches);
839
857
  return params;
840
858
  }
841
- function replaceParamsFromPathDecl(path) {
842
- const replacedPath = path.replace(routeParamExtractRegxp, (_, mtch, key, catchAll, optional) => {
843
- return catchAll ? `\${((string | ''))}` : `\${(string ${optional ? "| ''" : ""})}`;
844
- });
845
- return replacedPath;
846
- }
847
859
 
848
860
  function extractRouteParamsFromPath(path, isIndexFileForRouting, previousParams) {
849
861
  const params = extractParamsFromPathDecl(path);
@@ -868,17 +880,17 @@ function extractRouteParamsFromPath(path, isIndexFileForRouting, previousParams)
868
880
  }
869
881
 
870
882
  const ExtractRegex = /(^(\/)?([^:/]+)?(:(\w+)(\(.+\)[*+]?)?(\?)?)*([^:/]+)?)+/g;
871
- function destructurePath(path, fullPath, routeName) {
883
+ function destructurePath(path, route) {
872
884
  let allPathElements = [];
873
885
  let _path = `${path}`;
874
886
  do {
875
- const { pathElements, strippedPath } = extractPathElements(_path, fullPath, routeName);
887
+ const { pathElements, strippedPath } = extractPathElements(_path, route);
876
888
  allPathElements = allPathElements.concat(pathElements);
877
889
  _path = _path.replace(strippedPath, "");
878
890
  } while (_path.length);
879
891
  return allPathElements;
880
892
  }
881
- function extractPathElements(partOfPath, fullPath, routeName) {
893
+ function extractPathElements(partOfPath, route) {
882
894
  let pathElements = [];
883
895
  let strippedPath = "";
884
896
  let matches;
@@ -887,20 +899,34 @@ function extractPathElements(partOfPath, fullPath, routeName) {
887
899
  const [_, mtch, slash, path1, paramDef, key, catchAll, optional, path2] = matches;
888
900
  if (mtch) {
889
901
  strippedPath = mtch;
902
+ const sharedProperties = {
903
+ fullPath: route.path,
904
+ routeName: route.name,
905
+ isLocale: route.isLocale
906
+ };
890
907
  if (path1) {
891
- pathElements.push({ type: "name", content: path1, fullPath, id: nanoid$1(6), routeName });
908
+ pathElements.push({
909
+ type: "name",
910
+ content: path1,
911
+ id: nanoid$1(6),
912
+ ...sharedProperties
913
+ });
892
914
  }
893
915
  if (key) {
894
916
  pathElements.push({
895
917
  type: catchAll ? "catchAll" : optional ? "optionalParam" : "param",
896
918
  content: key,
897
- fullPath,
898
919
  id: nanoid$1(6),
899
- routeName
920
+ ...sharedProperties
900
921
  });
901
922
  }
902
923
  if (path2) {
903
- pathElements.push({ type: "name", content: path2, fullPath, id: nanoid$1(6), routeName });
924
+ pathElements.push({
925
+ type: "name",
926
+ content: path2,
927
+ id: nanoid$1(6),
928
+ ...sharedProperties
929
+ });
904
930
  }
905
931
  }
906
932
  }
@@ -908,6 +934,8 @@ function extractPathElements(partOfPath, fullPath, routeName) {
908
934
  }
909
935
 
910
936
  function createPathsFiles({ routesPaths }) {
937
+ const { i18n, i18nOptions } = moduleOptionStore;
938
+ const hasPrefixStrategy = i18n && i18nOptions?.strategy !== "no_prefix";
911
939
  const filteredRoutesPaths = routesPaths.filter(
912
940
  (route, index) => routesPaths.findIndex((r) => route.name === r.name) === index && !routesPaths.find((r) => `${route.path}/` === r.path)
913
941
  ).sort((a, b) => {
@@ -950,15 +978,18 @@ function createPathsFiles({ routesPaths }) {
950
978
  return order;
951
979
  });
952
980
  const pathElements = filteredRoutesPaths.filter((f) => f.path && f.path !== "/").map((route) => {
953
- return route.path.split("/").filter((f) => f.length).map((m) => destructurePath(m, route.path, route.name));
981
+ return route.path.split("/").filter((f) => f.length).map((m) => destructurePath(m, route));
954
982
  });
955
983
  const validatePathTypes = createValidatePathTypes(pathElements);
984
+ const validateLocalePathTypes = createValidatePathTypes(pathElements, true);
956
985
  return (
957
986
  /* typescript */
958
987
  `
959
988
 
960
989
  ${createRoutePathSchema(filteredRoutesPaths)};
961
990
 
991
+ ${returnIfTrue(hasPrefixStrategy, createLocaleRoutePathSchema(filteredRoutesPaths))}
992
+
962
993
  type ValidStringPath<T> = T extends \`\${string} \${string}\` ? false : T extends '' ? false : true;
963
994
 
964
995
  type ValidParam<T, R extends boolean = true> = T extends \`\${infer A}/\${infer B}\`
@@ -1002,9 +1033,14 @@ function createPathsFiles({ routesPaths }) {
1002
1033
  : false;
1003
1034
 
1004
1035
  ${validatePathTypes}
1036
+ ${returnIfTrue(hasPrefixStrategy, validateLocalePathTypes)}
1005
1037
 
1006
1038
 
1007
- export type TypedPathParameter<T extends string> = ValidatePath<T> | RoutePathSchema
1039
+ export type TypedPathParameter<T extends string> = ValidatePath<T> | RoutePathSchema;
1040
+ ${returnIfTrue(
1041
+ hasPrefixStrategy,
1042
+ `export type TypedLocalePathParameter<T extends string> = ValidateLocalePath<T> | LocaleRoutePathSchema;`
1043
+ )}
1008
1044
 
1009
1045
  `
1010
1046
  );
@@ -1389,7 +1425,7 @@ function hasi18nSibling(source, route) {
1389
1425
  }
1390
1426
  function modifyRoutePrefixDefaultIfI18n(route) {
1391
1427
  const { i18n, i18nOptions } = moduleOptionStore;
1392
- if (i18n && route.name) {
1428
+ if (i18n && route.name && i18nOptions?.strategy === "prefix_and_default") {
1393
1429
  const separator = i18nOptions?.routesNameSeparator ?? "___";
1394
1430
  const routeDefaultRegXp = new RegExp(
1395
1431
  `([a-zA-Z-]+)${separator}[a-zA-Z]+${separator}default`,
@@ -1409,52 +1445,57 @@ function walkThoughRoutes({
1409
1445
  parent,
1410
1446
  previousParams,
1411
1447
  output,
1412
- isLast
1448
+ isLast,
1449
+ isLocale
1413
1450
  }) {
1414
1451
  modifyRoutePrefixDefaultIfI18n(route);
1415
- if (!hasi18nSibling(output.routesPaths, route)) {
1416
- const newPath = `${parent?.path ?? ""}${route.path.startsWith("/") ? route.path : `/${route.path}`}`;
1417
- output.routesPaths.push({
1418
- name: route.name,
1419
- typePath: replaceParamsFromPathDecl(newPath),
1420
- path: newPath
1421
- });
1422
- if (route.children?.length) {
1423
- let childrenChunks = route.children;
1424
- let nameKey = createKeyedName(route, parent);
1425
- const allRouteParams = extractRouteParamsFromPath(route.path, false, previousParams);
1426
- const newRoute = { ...route, name: nameKey, path: newPath };
1452
+ const newPath = `${parent?.path ?? ""}${route.path.startsWith("/") ? route.path : `/${route.path}`}`;
1453
+ const isLocaleRoute = isLocale || hasi18nSibling(output.routesPaths, route);
1454
+ output.routesPaths.push({
1455
+ name: route.name,
1456
+ path: newPath,
1457
+ isLocale: isLocaleRoute
1458
+ });
1459
+ if (route.children?.length) {
1460
+ let childrenChunks = route.children;
1461
+ let nameKey = createKeyedName(route, parent);
1462
+ const allRouteParams = extractRouteParamsFromPath(route.path, false, previousParams);
1463
+ const newRoute = { ...route, name: nameKey, path: newPath };
1464
+ if (!isLocaleRoute) {
1427
1465
  output.routesObjectTemplate += `${nameKey}:{`;
1428
1466
  output.routesDeclTemplate += `"${nameKey}":{`;
1429
- childrenChunks?.map(
1430
- (routeConfig, index) => walkThoughRoutes({
1431
- route: routeConfig,
1432
- level: level + 1,
1433
- siblings: extractUnMatchingSiblings(route, siblings),
1434
- parent: newRoute,
1435
- previousParams: allRouteParams,
1436
- output,
1437
- isLast: isItemLast(childrenChunks, index)
1438
- })
1439
- );
1467
+ }
1468
+ childrenChunks?.map(
1469
+ (routeConfig, index) => walkThoughRoutes({
1470
+ route: routeConfig,
1471
+ level: level + 1,
1472
+ siblings: extractUnMatchingSiblings(route, siblings),
1473
+ parent: newRoute,
1474
+ previousParams: allRouteParams,
1475
+ output,
1476
+ isLast: isItemLast(childrenChunks, index),
1477
+ isLocale: isLocaleRoute
1478
+ })
1479
+ );
1480
+ if (!isLocaleRoute) {
1440
1481
  output.routesObjectTemplate += "},";
1441
1482
  output.routesDeclTemplate += `}${isLast ? "" : ","}`;
1442
- } else if (route.name) {
1443
- let keyName = createNameKeyFromFullName(route, level, parent?.name);
1444
- output.routesObjectTemplate += `'${keyName}': '${route.name}' as const,`;
1445
- output.routesDeclTemplate += `"${keyName}": "${route.name}"${isLast ? "" : ","}`;
1446
- output.routesList.push(route.name);
1447
- const isIndexFileForRouting = route.path === "";
1448
- const allRouteParams = extractRouteParamsFromPath(
1449
- route.path,
1450
- isIndexFileForRouting,
1451
- previousParams
1452
- );
1453
- output.routesParams.push({
1454
- name: route.name,
1455
- params: allRouteParams
1456
- });
1457
1483
  }
1484
+ } else if (route.name && !isLocaleRoute) {
1485
+ let keyName = createNameKeyFromFullName(route, level, parent?.name);
1486
+ output.routesObjectTemplate += `'${keyName}': '${route.name}' as const,`;
1487
+ output.routesDeclTemplate += `"${keyName}": "${route.name}"${isLast ? "" : ","}`;
1488
+ output.routesList.push(route.name);
1489
+ const isIndexFileForRouting = route.path === "";
1490
+ const allRouteParams = extractRouteParamsFromPath(
1491
+ route.path,
1492
+ isIndexFileForRouting,
1493
+ previousParams
1494
+ );
1495
+ output.routesParams.push({
1496
+ name: route.name,
1497
+ params: allRouteParams
1498
+ });
1458
1499
  }
1459
1500
  }
1460
1501
 
@@ -1465,14 +1506,12 @@ function constructRouteMap(routesConfig) {
1465
1506
  let routesList = [];
1466
1507
  let routesParams = [];
1467
1508
  let routesPaths = [];
1468
- let routesPathsTree = "{";
1469
1509
  const output = {
1470
1510
  routesObjectTemplate,
1471
1511
  routesDeclTemplate,
1472
1512
  routesList,
1473
1513
  routesParams,
1474
- routesPaths,
1475
- routesPathsTree
1514
+ routesPaths
1476
1515
  };
1477
1516
  startGenerator({
1478
1517
  output,
@@ -1491,7 +1530,8 @@ function startGenerator({ output, routesConfig }) {
1491
1530
  level: 0,
1492
1531
  output,
1493
1532
  siblings: rootSiblingsRoutes,
1494
- isLast: isItemLast(routesConfig, index)
1533
+ isLast: isItemLast(routesConfig, index),
1534
+ isLocale: false
1495
1535
  });
1496
1536
  });
1497
1537
  output.routesObjectTemplate += "}";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-typed-router",
3
- "version": "3.0.0-beta.8",
4
- "description": "Provide autocompletion for paths, routes names and params in Nuxt apps",
3
+ "version": "3.0.0",
4
+ "description": "Provide autocompletion for routes paths, names and params in Nuxt apps",
5
5
  "type": "module",
6
6
  "main": "./dist/module.cjs",
7
7
  "types": "./dist/types.d.ts",
@@ -70,7 +70,7 @@
70
70
  "prettier": "2.8.4"
71
71
  },
72
72
  "devDependencies": {
73
- "@nuxt/devtools": "^0.1.4",
73
+ "@nuxt/devtools": "^0.1.6",
74
74
  "@nuxt/module-builder": "^0.2.1",
75
75
  "@nuxt/test-utils": "^3.2.2",
76
76
  "@nuxt/types": "^2.16.0",
@@ -81,21 +81,21 @@
81
81
  "@types/mkdirp": "^2.0.0",
82
82
  "@types/node": "^18.14.0",
83
83
  "@types/prettier": "^2.7.2",
84
- "@typescript-eslint/eslint-plugin": "^5.52.0",
85
- "@typescript-eslint/parser": "^5.52.0",
84
+ "@typescript-eslint/eslint-plugin": "^5.53.0",
85
+ "@typescript-eslint/parser": "^5.53.0",
86
86
  "@vue/test-utils": "^2.3.0",
87
87
  "cross-env": "^7.0.3",
88
88
  "eslint": "8.34.0",
89
89
  "eslint-config-prettier": "^8.6.0",
90
90
  "eslint-plugin-vue": "^9.9.0",
91
91
  "nuxt": "3.2.2",
92
- "playwright": "1.30.0",
92
+ "playwright": "1.31.0",
93
93
  "standard-version": "^9.5.0",
94
94
  "tsd": "^0.25.0",
95
95
  "typescript": "^4.9.5",
96
96
  "vitest": "^0.28.5",
97
97
  "vue-eslint-parser": "^9.1.0",
98
98
  "vue-router": "^4.1.6",
99
- "vue-tsc": "^1.1.4"
99
+ "vue-tsc": "^1.1.7"
100
100
  }
101
101
  }