Skip to content

Commit

Permalink
feat: add Helper To Validate Params (#11)
Browse files Browse the repository at this point in the history
* feat: add $params helper

* chore: update docs
  • Loading branch information
martinliptak authored Jul 12, 2022
1 parent 442f5da commit 92d679a
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 5 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# remix-routes

`remix-routes` automatically generates typesafe helper function for manipulating internal links in your Remix apps.
`remix-routes` automatically generates typesafe helper functions for manipulating internal links in your Remix apps.

![Screenshot](https://user-images.githubusercontent.com/465125/147367217-0b8e8a04-0152-48e8-ba65-32c34605a4a5.png)

Expand Down Expand Up @@ -61,10 +61,24 @@ $path('/posts/:id', { id: 6 }, { version: 18 }); // => /posts/6?version=18
$path('/posts', { limit: 10 }); // => /posts?limit=10
```

Checking params:

```typescript
import type { ActionFunction } from 'remix';
import { $params } from 'remix-routes'; // <-- Import $params helper.

export const action: ActionFunction = async ({ params }) => {
const { id } = $params("/posts/:id/update", params) // <-- It's type safe, try renaming `id` param.

// ...
}
```

## API

- `$path(path: string, params: { [key: string]: string | number }, query?: { [key: string]: string | number })`
- `$path(path: string, query?: { [key: string]: string | number })`
- `$params(path: string, params: { readonly [key: string]: string | undefined })`

## Command Line Options

Expand Down
40 changes: 40 additions & 0 deletions src/__tests__/__snapshots__/cli.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,45 @@ export declare function $path(
query?: Record<string, string | number>
): string;
export declare function $params(
route: \\"/chats/:season/:episode/:slug\\",
params: { readonly [key: string]: string | undefined }
): {
season: string,
episode: string,
slug: string
};
export declare function $params(
route: \\"/chats/:season/:episode\\",
params: { readonly [key: string]: string | undefined }
): {
season: string,
episode: string
};
export declare function $params(
route: \\"/s/:query\\",
params: { readonly [key: string]: string | undefined }
): {
query: string
};
export declare function $params(
route: \\"/admin/episodes/:id\\",
params: { readonly [key: string]: string | undefined }
): {
id: string
};
export declare function $params(
route: \\"/admin/episodes/:id/comments\\",
params: { readonly [key: string]: string | undefined }
): {
id: string
};
export declare function $params(
route: \\"/jokes/:jokeId\\",
params: { readonly [key: string]: string | undefined }
): {
jokeId: string
};
"
`;
6 changes: 5 additions & 1 deletion src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $path } from '../';
import { $path, $params } from '../';

test('$path', () => {
expect($path('/posts')).toBe('/posts');
Expand All @@ -15,3 +15,7 @@ test('$path + query', () => {
test('$path + params + query', () => {
expect($path('/posts/:id', { id: 1 }, { raw: 'true' })).toBe('/posts/1?raw=true');
});

test('$params', () => {
expect($params('/posts/:id', { id: "1" })).toStrictEqual({ id: "1" });
});
30 changes: 27 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ function watch(remixRoot: string) {

function generate(routesInfo: RoutesInfo) {
const jsCode = generateHelpers(routesInfo);
const tsCode = generateDefinition(routesInfo);
const tsCode = [
generatePathDefinition(routesInfo),
generateParamsDefinition(routesInfo)
].join('\n\n') + '\n\n';
const outputPath = path.join(process.cwd(), 'node_modules', '.remix-routes');
if (!fs.existsSync(outputPath)) {
fs.mkdirSync(outputPath);
Expand All @@ -89,7 +92,7 @@ module.exports = { routes }
`;
}

function generateDefinition(routesInfo: RoutesInfo) {
function generatePathDefinition(routesInfo: RoutesInfo) {
const code: string[] = [];
Object.entries({
'/': [],
Expand All @@ -105,10 +108,31 @@ function generateDefinition(routesInfo: RoutesInfo) {
lines.push(`): string;`);
code.push(lines.join('\n'));
});
code.push('\n');
return code.join('\n');
}

function generateParamsDefinition(routesInfo: RoutesInfo) {
const routes = Object.entries(routesInfo)

// $params helper makes sense only for routes with params.
const routesWithParams = routes.filter(([_, paramsNames]) => paramsNames.length > 0)

const code = routesWithParams.map(([route, paramsNames]) => {
const lines: string[] = []

lines.push(`export declare function $params(`)
lines.push(` route: ${JSON.stringify(route)},`)
lines.push(` params: { readonly [key: string]: string | undefined }`)
lines.push(`): {`)
lines.push(paramsNames.map(paramName => ` ${paramName}: string`).join(',\n'))
lines.push(`};`)

return lines.join('\n')
})

return code.join('\n')
}

function parse(routes: ConfigRoute[]) {
const paramNames: string[] = [];
routes.forEach((route) => {
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ export function $path(route: string, ...paramsOrQuery: Array<object>) {

return path + '?' + searchParams.toString();
}

export function $params(_route: string, params: { readonly [key: string]: string | undefined }) {
return params
}

0 comments on commit 92d679a

Please sign in to comment.