@mpen/rerouter 0.3.0 → 0.3.2

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.
Files changed (66) hide show
  1. package/README.md +4 -0
  2. package/{src → cli}/bin.test.ts +24 -2
  3. package/{src → cli}/bin.ts +27 -18
  4. package/cli/tsconfig.json +9 -0
  5. package/dist/acorn-k7ED_tOl.js +4968 -0
  6. package/dist/angular--Iqdw9UJ.js +4057 -0
  7. package/dist/babel-hfWAujRY.js +9878 -0
  8. package/dist/bin.d.ts +1 -1
  9. package/dist/bin.js +28 -23
  10. package/dist/estree-C1Zjnvlw.js +7266 -0
  11. package/dist/flow-BaD9LyIP.js +52912 -0
  12. package/dist/glimmer-CvCjW_1V.js +7541 -0
  13. package/dist/graphql-BdtzBuWh.js +1945 -0
  14. package/dist/html-DkZtUVbo.js +7137 -0
  15. package/dist/index.d.ts +19 -6
  16. package/dist/index.js +135 -27
  17. package/dist/markdown-Z8Vrc69e.js +6876 -0
  18. package/dist/meriyah-DeO4stuH.js +7590 -0
  19. package/dist/postcss-BmgGJ0E5.js +6777 -0
  20. package/dist/prettier-BT_F8kIx.js +15629 -0
  21. package/dist/typescript-DtIxStjy.js +22936 -0
  22. package/dist/yaml-CWOPBY0q.js +5281 -0
  23. package/examples/App.tsx +18 -49
  24. package/examples/dist/BlogPost-c10d9w2p.js +1 -0
  25. package/examples/dist/FetchLoading-534mdrgz.js +1 -0
  26. package/examples/dist/FetchLoading-sbxbdkre.js +1 -0
  27. package/examples/dist/Home-a1258p25.js +1 -0
  28. package/examples/dist/KitchenSink-821mjg0h.js +1 -0
  29. package/examples/dist/Login-wywx6bp7.js +1 -0
  30. package/examples/dist/Match-1e72jm5w.js +1 -0
  31. package/examples/dist/NotFound-smxj24jw.js +1 -0
  32. package/examples/dist/SlowLoading-59xxmbfk.js +1 -0
  33. package/examples/dist/index-0d4kj0rv.js +2 -0
  34. package/examples/dist/index-3x197sbt.js +9 -0
  35. package/examples/dist/index-a2hkfx1n.js +9 -0
  36. package/examples/dist/index-d21me1mc.js +9 -0
  37. package/examples/dist/index-ktqdknsn.js +2 -0
  38. package/examples/dist/index-p53qxxzd.js +2 -0
  39. package/examples/dist/index.html +67 -0
  40. package/examples/routes.gen.ts +66 -86
  41. package/examples/routes.ts +2 -2
  42. package/examples/server/serve-dist.ts +33 -0
  43. package/examples/server/tsconfig.json +9 -0
  44. package/package.json +15 -6
  45. package/src/components/Link.tsx +8 -6
  46. package/src/components/Router.test.tsx +183 -0
  47. package/src/components/Router.tsx +161 -29
  48. package/src/lib/routes.ts +2 -0
  49. package/tsconfig.json +3 -2
  50. package/tsdown.config.ts +3 -4
  51. package/dist/hooks-Dlwcb0sV.js +0 -20
  52. package/dist/hooks.d.ts +0 -2
  53. package/dist/hooks.js +0 -2
  54. package/dist/index-BYXpNitc.d.ts +0 -5
  55. /package/{src → cli}/fixtures/bin/kitchen-sink.tsx +0 -0
  56. /package/{src → cli}/fixtures/bin/optional.tsx +0 -0
  57. /package/{src → cli}/fixtures/bin/pages/Home.tsx +0 -0
  58. /package/{src → cli}/fixtures/bin/pages/KitchenSink.tsx +0 -0
  59. /package/{src → cli}/fixtures/bin/pages/Login.tsx +0 -0
  60. /package/{src → cli}/fixtures/bin/pages/Match.tsx +0 -0
  61. /package/{src → cli}/fixtures/bin/pages/NotFound.tsx +0 -0
  62. /package/{src → cli}/fixtures/bin/pages/Optional.tsx +0 -0
  63. /package/{src → cli}/fixtures/bin/regexp-groups.tsx +0 -0
  64. /package/{src → cli}/fixtures/bin/simple.tsx +0 -0
  65. /package/{src → cli}/fixtures/bin/unnamed.tsx +0 -0
  66. /package/dist/{routes-Hpf6cwcZ.js → routes-PW-bNm8e.js} +0 -0
package/README.md CHANGED
@@ -65,6 +65,10 @@ function App() {
65
65
  }
66
66
  ```
67
67
 
68
+ `loading` is delayed by 400ms by default to avoid flashing fallback UI during quick route
69
+ loads. Pass `loadingDelayMs={0}` to show it immediately, or another millisecond value to tune
70
+ the delay.
71
+
68
72
  ### Link
69
73
 
70
74
  ```tsx
@@ -37,7 +37,27 @@ describe('rerouter bin', () => {
37
37
 
38
38
  const outputContent = await fs.readFile(outputFile, 'utf8')
39
39
  expect(outputContent).toContain('export function home()')
40
- expect(result.stderr).toContain(`Wrote ${outputFile}`)
40
+ expect(result.stderr).toBe(`Wrote ${path.relative(process.cwd(), outputFile)}\n`)
41
+ })
42
+
43
+ test('formats output files with --pretty', async () => {
44
+ const routesFile = path.join(FIXTURES_DIR, 'simple.tsx')
45
+ const outputFile = path.join(TEMP_DIR, 'pretty-output.ts')
46
+
47
+ await runRerouterBin([routesFile, '-o', outputFile, '--pretty'])
48
+
49
+ const outputContent = await fs.readFile(outputFile, 'utf8')
50
+ expect(outputContent).toContain("export function home(): string {\n let sb = ''")
51
+ expect(outputContent).toContain(" sb += '/'")
52
+ })
53
+
54
+ test('ignores --pretty when writing to stdout', async () => {
55
+ const routesFile = path.join(FIXTURES_DIR, 'simple.tsx')
56
+
57
+ const { stdout } = await runRerouterBin([routesFile, '-p'])
58
+
59
+ expect(stdout).toContain('export function home(): string {\n let sb = ""')
60
+ expect(stdout).toContain(' sb += "/"')
41
61
  })
42
62
 
43
63
  test('writes to adjacent file with -w', async () => {
@@ -56,7 +76,9 @@ describe('rerouter bin', () => {
56
76
 
57
77
  const { stdout: outputContent } = await runRerouterBin([routesFile])
58
78
 
59
- expect(outputContent).toContain('export function optional(')
79
+ expect(outputContent).toContain(
80
+ 'export function optional(params: {} & AllOrNone<{ "bar": ParamType }>): string {',
81
+ )
60
82
  expect(outputContent).toContain('AllOrNone<')
61
83
  expect(outputContent).toContain('"bar": ParamType')
62
84
  })
@@ -5,12 +5,13 @@ import process from 'node:process'
5
5
  import { fileURLToPath, pathToFileURL } from 'node:url'
6
6
  import { parseArgs, type ParseArgsConfig } from 'node:util'
7
7
  import { parse } from 'path-to-regexp'
8
- import { normalizeLegacyPathToRegexpSyntax, normalizeRoutes, type Route } from './lib/routes'
8
+ import { normalizeLegacyPathToRegexpSyntax, normalizeRoutes, type Route } from '../src/lib/routes'
9
9
 
10
10
  const PARSE_CONFIG = {
11
11
  options: {
12
12
  output: { type: 'string', short: 'o' },
13
13
  write: { type: 'boolean', short: 'w' },
14
+ pretty: { type: 'boolean', short: 'p' },
14
15
  'wildcard-delimiter': { type: 'string' },
15
16
  'encode-function': { type: 'string' },
16
17
  },
@@ -62,6 +63,10 @@ function compilePathGenerator(
62
63
 
63
64
  const typeOfParam = (t: any) => (t.type === 'wildcard' ? 'WildcardType' : 'ParamType')
64
65
  const makeProp = (name: string, t: any): Prop => ({ name, type: typeOfParam(t) })
66
+ const renderPropsType = (props: readonly Prop[]): string =>
67
+ props.length
68
+ ? `{ ${props.map((p) => `${escapeString(p.name)}: ${p.type}`).join('; ')} }`
69
+ : '{}'
65
70
 
66
71
  function collectGroupProps(ts2: any[]): Prop[] {
67
72
  const props: Prop[] = []
@@ -79,12 +84,7 @@ function compilePathGenerator(
79
84
  } else if (t.type === 'group') {
80
85
  const groupProps = collectGroupProps(t.tokens)
81
86
  if (groupProps.length) {
82
- const some = [
83
- '{',
84
- ...groupProps.map((p) => ` ${escapeString(p.name)}: ${p.type}`),
85
- '}',
86
- ].join('\n')
87
- groupTypes.push(`AllOrNone<${some}>`)
87
+ groupTypes.push(`AllOrNone<${renderPropsType(groupProps)}>`)
88
88
  }
89
89
  collectTypes(t.tokens, false)
90
90
  }
@@ -93,11 +93,7 @@ function compilePathGenerator(
93
93
 
94
94
  collectTypes(tokens)
95
95
 
96
- const baseParamsType = [
97
- '{',
98
- ...baseProps.map((p) => ` ${escapeString(p.name)}: ${p.type}`),
99
- '}',
100
- ].join('\n')
96
+ const baseParamsType = renderPropsType(baseProps)
101
97
  const paramsType = groupTypes.length
102
98
  ? `${baseParamsType} & ${groupTypes.join(' & ')}`
103
99
  : baseParamsType
@@ -111,9 +107,7 @@ function compilePathGenerator(
111
107
  const hasAnyParams = baseProps.length > 0 || groupTypes.length > 0
112
108
 
113
109
  if (hasAnyParams) {
114
- lines.push(`export function ${functionName}(`)
115
- lines.push(` params: ${paramsType}`)
116
- lines.push(`): string {`)
110
+ lines.push(`export function ${functionName}(params: ${paramsType}): string {`)
117
111
  } else {
118
112
  lines.push(`export function ${functionName}(): string {`)
119
113
  }
@@ -197,6 +191,18 @@ async function importRoutes(routesPath: string): Promise<readonly Route[]> {
197
191
  return mod.default as readonly Route[]
198
192
  }
199
193
 
194
+ async function formatWithPrettier(source: string, outputPath: string): Promise<string> {
195
+ let prettier: typeof import('prettier')
196
+ try {
197
+ prettier = await import('prettier')
198
+ } catch (cause) {
199
+ throw new Error('The --pretty option requires prettier to be installed.', { cause })
200
+ }
201
+
202
+ const options = (await prettier.resolveConfig(outputPath)) ?? {}
203
+ return prettier.format(source, { ...options, filepath: outputPath })
204
+ }
205
+
200
206
  function extractRoutes(routes: readonly Route[]): ExtractedRoute[] {
201
207
  return normalizeRoutes(routes).flatMap((route) => {
202
208
  if (!route.name || typeof route.pattern !== 'string') return []
@@ -218,7 +224,7 @@ async function main(
218
224
  return {
219
225
  exitCode: 1,
220
226
  stdout: '',
221
- stderr: 'Usage: rerouter <routes-file> [-o <output-file>] [-w] [--wildcard-delimiter <string>] [--encode-function <identifier>]\n',
227
+ stderr: 'Usage: rerouter <routes-file> [-o <output-file>] [-w] [-p|--pretty] [--wildcard-delimiter <string>] [--encode-function <identifier>]\n',
222
228
  }
223
229
  }
224
230
 
@@ -280,10 +286,13 @@ async function main(
280
286
  }
281
287
  }
282
288
 
283
- const finalOutput = out.join('\n')
289
+ let finalOutput = out.join('\n')
284
290
  if (outputPath) {
291
+ if (options.pretty) {
292
+ finalOutput = await formatWithPrettier(finalOutput, outputPath)
293
+ }
285
294
  await fs.writeFile(outputPath, finalOutput, 'utf8')
286
- return { stdout: '', stderr: `Wrote ${outputPath}\n` }
295
+ return { stdout: '', stderr: `Wrote ${path.relative(cwd, outputPath) || '.'}\n` }
287
296
  } else {
288
297
  return { stdout: finalOutput, stderr: '' }
289
298
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
5
+ "types": ["node"]
6
+ },
7
+ "include": ["**/*"],
8
+ "exclude": ["**/*.test.*"]
9
+ }