Skip to content

Instantly share code, notes, and snippets.

@tomhicks
Created July 24, 2020 11:09
Show Gist options
  • Save tomhicks/56b6a159ab5e727e5f43353172a49b6d to your computer and use it in GitHub Desktop.
Save tomhicks/56b6a159ab5e727e5f43353172a49b6d to your computer and use it in GitHub Desktop.

Revisions

  1. tomhicks created this gist Jul 24, 2020.
    27 changes: 27 additions & 0 deletions InternalLink.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    import React from "react"
    import {InternalRoutes} from "types/routes"
    import Link, {LinkProps} from "next/link"

    export function InternalLink({
    routeName,
    routeParams,
    ...linkProps
    }: Omit<LinkProps, "href" | "as"> &
    InternalRoutes & {children: React.ReactChild}) {
    return (
    <Link
    {...linkProps}
    href={routeName}
    as={createUrl(routeName, routeParams)}
    passHref={true}
    />
    )
    }

    function createUrl(routePath: string, routeParams?: Record<string, string>) {
    if (!routeParams) {
    return routePath
    }

    return routePath.replace(/\[(\w+)\]/g, (_, k) => routeParams[k])
    }
    48 changes: 48 additions & 0 deletions generate-route-types.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@
    const glob = require("glob")
    const fs = require("fs")
    const prettier = require("prettier")

    const basePath = "src/app/pages"

    glob(`${basePath}/**/*.{tsx,ts}`, undefined, (err, files) => {
    const pageFiles = files
    .map(f =>
    f
    .replace(basePath, "")
    .replace(/\.\w+$/, "")
    .replace(/\/index$/, ""),
    )
    .filter(f => !f.startsWith("/_"))
    .map(file => {
    const paramNames = (file.match(/\[\w+\]/g) || []).map(pathSegment =>
    pathSegment.replace(/[\[\]]/g, ""),
    )

    return {
    routeName: file,
    routeParams: paramNames,
    }
    })

    const allTypes = pageFiles.map(typeTemplate)

    fs.writeFileSync(
    "src/app/types/routes.ts",
    prettier.format(
    `
    export type InternalRoutes = | ${allTypes.join("\n| ")}
    `,
    {
    semi: false,
    parser: "typescript",
    },
    ),
    )
    })

    const typeTemplate = ({routeName, routeParams}) => `{
    routeName: "${routeName}";
    routeParams${routeParams.length ? "" : "?"}: {
    ${routeParams.map(param => `${param}: string`).join(";\n ")}
    }
    }`