roullector
TypeScript icon, indicating that this package has built-in type declarations

1.1.2 • Public • Published

roullector: route collector

npm.badge codecov.badge bundlephobia.badge actions.ci.badge actions.release.badge semantic-release.badge MIT

tweet

Collect and generate route data from a file-based router such as svelte-kit's

What this does: show / hide
<!-- before -->
<script lang="ts">
  import { goto } from '$app/navigation';

  goto('/organiztion/org-abc/members/member-123/posts/prefix-too-much-literals-no-safety');
  // => 404 because organiztion is a typo
</script>

<!-- after -->
<script lang="ts">
  import { goto } from '$app/navigation';
  import { AppRoutes, route } from '$generated/routing';

  goto(
    route(
      AppRoutes.organization.$orgId.members.$memberId.posts.prefix$slug,
      'org-abc',
      'member-123',
      'type-support-no-typo',
    ),
  );
</script>

Table of Contents

Show / hide

Installation

npm install -D roullector
yarn add --dev roullector
pnpm install -D roullector

Usage

This package was initially built and tested for svelte-kit. But I expect it to work in other cases using the configurable options. Examples used in this docs will use svelte-kit common route setup.

Quick Start

If you are using svelte-kit and want a no lock-in jump start, do, at project root,...

npx roullector collect

...and inspect the src/generated/routing directory for the generated goodies.

Example

If you have a directory that contains some routes like below...

directory: show / hide
src/routes/
  ├── __components/
  |       ├── Navbar.svelte
  |       └── Footer.svelte
  ├── __layout.svelte
  ├── __error.svelte
  ├── me.svelte
  ├── sign-in.svelte
  ├── sign-up.svelte
  ├── index.svelte
  └── admin/
      ├── __components/
      |     ├── Admin.layout.svelte
      |     ├── types.ts
      └── users/
          ├── [id]/
          |     ├── __layout.svelte
          |     ├── index.svelte
          |     ├── types.ts
          |     └── posts/
          |           ├── [post_id].svelte
          |           ├── s-[slug].svelte
          |           └── l-[short-link]-l.svelte
          └── index.svelte

...and a npm script that run roullector with default options,...

package.json: show/hide
// package.json
{
  "scripts": {
    "codegen:routing": "roullector collect"
  }
}

...the following files will be generated:

Generated: show / hide
// src/generated/routing/routes.json
{
  "admin": {
    "users": {
      "$id": {
        "index": "/admin/users/[id]",
        "posts": {
          "$postId": "/admin/users/[id]/posts/[post_id]",
          "l$shortLink$L": "/admin/users/[id]/posts/l-[short-link]-l",
          "s$slug": "/admin/users/[id]/posts/s-[slug]",
          "__dir": "/admin/users/[id]/posts"
        }
      },
      "index": "/admin/users"
    },
    "__dir": "/admin"
  },
  "index": "/",
  "me": "/me",
  "signIn": "/sign-in",
  "signUp": "/sign-up"
}
// src/generated/routing/index.ts
export { default as AppRoutes } from './routes.json';
/**
 * build a complete path with injected arguments
 * @param path {string} based path
 * @param args {string[]} arguments to inject
 */
export function route(path: string, ...args: string[]): string {
  const params = path.match(/\[[a-zA-Z_-]+\]/g) ?? [];
  for (const i in params) {
    path = path.replace(params[i], args[i]);
  }
  return path;
}

Notice that index.ts will import json, you need to configure your tsconfig.json to enable resolveJsonModule:

tsconfig.json: show / hide
// tsconfig.json
{
  "compilerOptions": {
    "resolveJsonModule": true
  }
}

You can then use the route helper to construct a complete path with typescript support built-in. For example:

path contruct: show / hide
import { AppRoutes } from '$generated/routing'; // or use relative path

const path = route(AppRoutes.admin.users.$id.posts.s$slug, 'user-id-123', 'slug');
// path = '/admin/users/user-id-123/posts/s-slug'

// ... later
// navigate(path);

Options

Run npx roullector collect help to for configurable options in command-line mode

Table of Options
name default description cli equivalent
inDir 'src/routes' input directory path to collect route data from -i, --inDir
extensions ['.svelte'] file extensions to accept -e, --extensions (comma-separated)
ignorePatterns [/^_/] patterns to ignore filenames -x, --ignorePatterns (comma-separated)
output true write generated files to disk?, if false will print to console --no-output
outDir 'src/generated/routing' output directory -o, --outDir
depth Infinity depth of directory traversal -d, --depth
dirkey __dir key to save path for directories with no index file -k, --dirkey
keyTransform [dollarArgify(), camelCasify()] how to transform route key in mapping -t, --keyTransform (allows multiple)
utils true generate utils for building path? --no-utils
typescript true generate files in typescript? --no-typescript
verbose false print more info during operation (for cli only) --verbose

Notes:

  • in command-line mode, keyTransform
    • only accepts these choices: dollarArg | camelCase | none,
    • if you want to specify multiple transforms, provide multiple arguments: --keyTransform=dollarArg --keyTransform=camelCase. The transforms will be applied in the order they are provided.
    • The rationale for the current default is to enable reference to the mapping without having to do something like AppRoutes['a-kebab-case']['[id'].
    • To opt out completely, do --keyTransform=none.
    • See implementation for more details.
  • for boolean options (default to true), the cli equivalent is --no-<option>, meaning only add the flag if you want to negate the option.

Library Usage

show / hide
import {
  collect,
  defaultCollectOptions,
  camelCasify,
  dollarArgify,
  compose,
} from `roullector`;

console.log('These are default options:', defaultCollectOptions);

let { json, route } = collect(); // use default options
// json = './src/generated/routing/routes.json'
// route = './src/generated/routing/index.ts'

({ json, route } = collect({ output: false; }); // helpful for testing
// json = generated route mapping content
// route = generated index source

const transformers = [dollarArgify, camelCasify];
({ json, route } = collect({
  keyTransform: [
    (key, original) => compose(key, ...defaultTransformers),
    // key = the current key in the transformation pipeline
    // original = the original key before all transformation
  ],
}))

Contributing

Read Contribution Guide


tweet

buy vnphanquang a coffee

Package Sidebar

Install

npm i roullector

Weekly Downloads

0

Version

1.1.2

License

MIT

Unpacked Size

335 kB

Total Files

36

Last publish

Collaborators

  • vnphanquang