Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable output directory #35

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
dist
example
.eslintrc.js
jest.config.js
plugin.js
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ Now you just need to decide how you want to integrate `next-type-safe-routes` in

<img src="./example.gif" />

## Configuration
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how are these docs @ckastbjerg ?


You can configure the plugin by adding values to the `nextTypeSafeRoutes` object
in `next.config.js`:

```js
const withPlugins = require("next-compose-plugins");
const nextTypeSafePages = require("next-type-safe-routes/plugin");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking this should be

Suggested change
const nextTypeSafePages = require("next-type-safe-routes/plugin");
const nextTypeSafeRoutes = require("next-type-safe-routes/plugin");


module.exports = withPlugins([nextTypeSafePages], {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested this out in the example project, but it only worked for me with:

module.exports = withPlugins([nextTypeSafeRoutes], {
  nextTypeSafeRoutes: { outDir: "@types/custom-page-type-directory" },
});

Is this the intended interface? Or am I misunderstanding something?

Note, I haven't looked into the "correct" way of allowing options for plugins...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = withPlugins([nextTypeSafePages], {
module.exports = withPlugins([nextTypeSafeRoutes], {

outDir: "@types/custom-page-type-directory",
});
```

Available options:

### `outDir`

**Default:** `@types/next-type-safe-routes`

If provided, will save the types to a file called `index.d.ts` in the provided
directory. Paths are placed relative to the `src/` directory, and absolute paths
are also supported.

## How it works

Since the Next.js router is based (strictly) on the file-system, we can determine which pages and API routes exists in an application simply by parsing the `/pages` folder. And due to the strictness, we can also determine which parameters are needed for dynamic routes.
Expand Down
5 changes: 3 additions & 2 deletions example/next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const withPlugins = require("next-compose-plugins");
const nextTypeSafePages = require("next-type-safe-routes/plugin");
const nextTypeSafeRoutes = require("next-type-safe-routes/plugin");
const path = require("path");

module.exports = withPlugins([nextTypeSafePages]);
module.exports = withPlugins([nextTypeSafeRoutes]);
8 changes: 4 additions & 4 deletions example/src/@types/next-type-safe-routes/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

declare module "next-type-safe-routes" {
type Query = { [key: string]: any };
export type TypeSafePage = { route: "/catch-all", path: string, query?: Query } | "/" | { route: "/", query?: Query } | { route: "/nested-catch-all/[dynamic]/slugs", path: string, params: { dynamic: string | number }, query?: Query } | "/optional-catch-all" | { route: "/optional-catch-all", path?: string, query?: Query } | { route: "/users/[userId]", params: { userId: string | number }, query?: Query } | "/users" | { route: "/users", query?: Query };
export type TypeSafeApiRoute = "/api/mocks" | { route: "/api/mocks", query?: Query } | { route: "/api/users/[userId]", params: { userId: string | number }, query?: Query } | "/api/users" | { route: "/api/users", query?: Query };
export const getPathname = (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
export const getRoute = (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
export type TypeSafePage = { route: "/catch-all", path: string, query?: Query } | "/" | { route: "/", query?: Query } | { route: "/nested-catch-all/[dynamic]/slugs", path: string, params: { "dynamic": string | number }, query?: Query } | "/optional-catch-all" | { route: "/optional-catch-all", path?: string, query?: Query } | { route: "/users/[userId]", params: { "userId": string | number }, query?: Query } | "/users" | { route: "/users", query?: Query };
export type TypeSafeApiRoute = "/api/mocks" | { route: "/api/mocks", query?: Query } | { route: "/api/users/[userId]", params: { "userId": string | number }, query?: Query } | "/api/users" | { route: "/api/users", query?: Query };
export const getPathname: (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
export const getRoute: (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
}
107 changes: 105 additions & 2 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@
resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001"
integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw==

"@types/minimatch@^3.0.3":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==

"@types/node@^14.14.34":
version "14.18.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.9.tgz#0e5944eefe2b287391279a19b407aa98bd14436d"
integrity sha512-j11XSuRuAlft6vLDEX4RvhqC0KxNxx6QIyMXNb0vHHSNPXTPeiy3algESWmOOIzEtiEL0qiowPU3ewW9hHVa7Q==

"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
Expand Down Expand Up @@ -154,6 +164,14 @@ anymatch@~3.1.1:
normalize-path "^3.0.0"
picomatch "^2.0.4"

anymatch@~3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"

asn1.js@^5.2.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
Expand Down Expand Up @@ -182,6 +200,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=

balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==

base64-js@^1.0.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
Expand All @@ -207,6 +230,14 @@ bn.js@^5.0.0, bn.js@^5.1.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==

brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"

braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
Expand Down Expand Up @@ -360,6 +391,21 @@ [email protected]:
optionalDependencies:
fsevents "~2.3.1"

chokidar@^3.5.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"

cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
Expand Down Expand Up @@ -407,6 +453,11 @@ commondir@^1.0.1:
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=

[email protected]:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=

console-browserify@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
Expand Down Expand Up @@ -565,6 +616,11 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=

ensure-posix-path@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce"
integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==

escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
Expand Down Expand Up @@ -622,7 +678,7 @@ find-up@^4.0.0:
locate-path "^5.0.0"
path-exists "^4.0.0"

fsevents@~2.3.1:
fsevents@~2.3.1, fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
Expand All @@ -634,7 +690,7 @@ [email protected]:
dependencies:
stream-parser "^0.3.1"

glob-parent@~5.1.0:
glob-parent@~5.1.0, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
Expand Down Expand Up @@ -839,6 +895,14 @@ make-dir@^3.0.2:
dependencies:
semver "^6.0.0"

matcher-collection@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29"
integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==
dependencies:
"@types/minimatch" "^3.0.3"
minimatch "^3.0.2"

md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
Expand Down Expand Up @@ -871,11 +935,23 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=

minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"

minimist@^1.2.0:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==

mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==

[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
Expand All @@ -898,6 +974,16 @@ next-compose-plugins@^2.2.1:
resolved "https://registry.yarnpkg.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab"
integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg==

next-type-safe-routes@latest:
version "0.3.1-alpha.1"
resolved "https://registry.yarnpkg.com/next-type-safe-routes/-/next-type-safe-routes-0.3.1-alpha.1.tgz#7234c297ed1b610e4483097fd894a08334fdafd1"
integrity sha512-WLjJpQ+nQhv62aQBieOp0G5A6DtSUU1bnh8ay5wreLGvEMo6P3U4crA9PAgiWerZPXvUjNQy6PTHSB4HRsN4qA==
dependencies:
"@types/node" "^14.14.34"
chokidar "^3.5.1"
mkdirp "^1.0.4"
walk-sync "^2.2.0"

[email protected]:
version "10.0.9"
resolved "https://registry.yarnpkg.com/next/-/next-10.0.9.tgz#ad5d8e0368fee8363cdfd64d22dfbf71f683ae66"
Expand Down Expand Up @@ -1255,6 +1341,13 @@ readdirp@~3.5.0:
dependencies:
picomatch "^2.2.1"

readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"

regenerator-runtime@^0.13.4:
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
Expand Down Expand Up @@ -1558,6 +1651,16 @@ [email protected], vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==

walk-sync@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-2.2.0.tgz#80786b0657fcc8c0e1c0b1a042a09eae2966387a"
integrity sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==
dependencies:
"@types/minimatch" "^3.0.3"
ensure-posix-path "^1.1.0"
matcher-collection "^2.0.0"
minimatch "^3.0.4"

[email protected]:
version "2.1.1"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7"
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
},
"dependencies": {
"chokidar": "^3.5.1",
"mkdirp": "^1.0.4",
"walk-sync": "^2.2.0"
},
"devDependencies": {
Expand All @@ -39,10 +38,14 @@
"eslint": "^8.7.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^26.6.3",
"next": "^12.0.9",
"prettier": "^2.5.1",
"ts-jest": "^26.5.4",
"typescript": "^4.5.5"
},
"peerDependencies": {
"next": "*"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ckastbjerg/next-type-safe-routes.git"
Expand Down
7 changes: 4 additions & 3 deletions src/plugin/generateTypeScriptFile/getNextPageRoute.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { getIsCatchAllRoute, getIsOptionalCatchAllRoute } from "./utils";

const getNextPageRoute = (fileName: string) => {
const getNextPageRoute = (fileName: string): string => {
// casts safe since we guard with the conditionals
if (getIsOptionalCatchAllRoute(fileName)) {
return fileName.split("/[[...")[0];
return fileName.split("/[[...")[0] as string;
} else if (getIsCatchAllRoute(fileName)) {
return fileName.split("/[...")[0];
return fileName.split("/[...")[0] as string;
}

const route = fileName
Expand Down
Loading