From 4a30b1a4eb42658fa5efa9435bcae21cc242659a Mon Sep 17 00:00:00 2001 From: Alec Aivazis Date: Fri, 5 May 2023 21:08:09 -0700 Subject: [PATCH] Add route groups to react integration (#1083) --- .../src/plugin/codegen/entries.test.ts | 46 +++--- .../src/plugin/codegen/manifest.test.ts | 134 ++++++++++++++---- .../src/plugin/codegen/manifest.ts | 2 +- .../src/plugin/codegen/router.test.ts | 72 +++++----- .../houdini-react/src/plugin/conventions.ts | 9 +- 5 files changed, 171 insertions(+), 92 deletions(-) diff --git a/packages/houdini-react/src/plugin/codegen/entries.test.ts b/packages/houdini-react/src/plugin/codegen/entries.test.ts index b40ef8d8b..43d6fbde7 100644 --- a/packages/houdini-react/src/plugin/codegen/entries.test.ts +++ b/packages/houdini-react/src/plugin/codegen/entries.test.ts @@ -41,11 +41,11 @@ test('composes layouts and pages', async function () { { plugins: ['jsx'] } ) expect(page_entry).toMatchInlineSnapshot(` - import Layout___ from "../layouts/__.jsx"; - import Layout___subRoute from "../layouts/__subRoute.jsx"; - import Page___subRoute__nested from "../pages/__subRoute__nested.jsx"; - import PageFallback___subRoute__nested from "../fallbacks/page/__subRoute__nested.jsx"; - import LayoutFallback___subRoute__nested from "../../fallbacks/layout"; + import Layout__0 from "../layouts/_0.jsx"; + import Layout__0subRoute from "../layouts/_0subRoute.jsx"; + import Page__0subRoute_0nested from "../pages/_0subRoute_0nested.jsx"; + import PageFallback__0subRoute_0nested from "../fallbacks/page/_0subRoute_0nested.jsx"; + import LayoutFallback__0subRoute_0nested from "../../fallbacks/layout"; export default ( { @@ -53,15 +53,15 @@ test('composes layouts and pages', async function () { } ) => { return ( - ( - - - - - - - - ) + ( + + + + + + + + ) ); }; `) @@ -74,7 +74,7 @@ test('composes layouts and pages', async function () { ) expect(page_unit).toMatchInlineSnapshot(` import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing/components/Router"; - import Component___subRoute__nested from "../../../../../src/routes/subRoute/nested/+page"; + import Component__0subRoute_0nested from "../../../../../src/routes/subRoute/nested/+page"; export default ( { @@ -84,9 +84,9 @@ test('composes layouts and pages', async function () { const [FinalQuery$data, FinalQuery$handle] = useQueryResult("FinalQuery"); return ( - ( + ( {children} - ) + ) ); }; `) @@ -99,7 +99,7 @@ test('composes layouts and pages', async function () { ) expect(root_layout_unit).toMatchInlineSnapshot(` import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing/components/Router"; - import Component___ from "../../../../../src/routes/+layout"; + import Component__0 from "../../../../../src/routes/+layout"; export default ( { @@ -107,9 +107,9 @@ test('composes layouts and pages', async function () { } ) => { return ( - ( + ( {children} - ) + ) ); }; `) @@ -122,7 +122,7 @@ test('composes layouts and pages', async function () { ) expect(deep_layout_unit).toMatchInlineSnapshot(` import { useQueryResult } from "$houdini/plugins/houdini-react/runtime/routing/components/Router"; - import Component___subRoute from "../../../../../src/routes/subRoute/+layout"; + import Component__0subRoute from "../../../../../src/routes/subRoute/+layout"; export default ( { @@ -133,13 +133,13 @@ test('composes layouts and pages', async function () { const [SubQuery$data, SubQuery$handle] = useQueryResult("SubQuery"); return ( - ( {children} - ) + ) ); }; `) diff --git a/packages/houdini-react/src/plugin/codegen/manifest.test.ts b/packages/houdini-react/src/plugin/codegen/manifest.test.ts index 67f3168e8..3a5e43af6 100644 --- a/packages/houdini-react/src/plugin/codegen/manifest.test.ts +++ b/packages/houdini-react/src/plugin/codegen/manifest.test.ts @@ -25,6 +25,84 @@ test('empty routes dir generates empty manifest', async function () { `) }) +test('route groups', async function () { + const config = await test_config() + + // create the mock filesystem + await fs.mock({ + [config.routesDir]: { + '+layout.tsx': mockView([]), + '(subRoute)': { + '+layout.tsx': mockView(['RootQuery']), + '+layout.gql': mockQuery('RootQuery'), + nested: { + '+page.gql': mockQuery('FinalQuery', true), + '+page.tsx': mockView(['FinalQuery']), + }, + }, + }, + }) + + expect( + await load_manifest({ + config, + }) + ).toMatchInlineSnapshot(` + { + "pages": { + "_0_3subRoute_4_0nested": { + "id": "_0_3subRoute_4_0nested", + "queries": [ + "FinalQuery" + ], + "url": "/(subRoute)/nested", + "layouts": [ + "_0", + "_0_3subRoute_4" + ], + "path": "(subRoute)/nested/+page.tsx" + } + }, + "layouts": { + "_0": { + "id": "_0", + "queries": [], + "url": "/", + "layouts": [], + "path": "+layout.tsx" + }, + "_0_3subRoute_4": { + "id": "_0_3subRoute_4", + "queries": [ + "RootQuery" + ], + "url": "/(subRoute)/", + "layouts": [ + "_0" + ], + "path": "(subRoute)/+layout.tsx" + } + }, + "page_queries": { + "_0_3subRoute_4_0nested": { + "path": "(subRoute)/nested/+page.gql", + "name": "FinalQuery", + "url": "/(subRoute)/nested/", + "loading": true + } + }, + "layout_queries": { + "_0_3subRoute_4": { + "path": "(subRoute)/+layout.gql", + "name": "RootQuery", + "url": "/(subRoute)/", + "loading": false + } + } + } + `) +}) + test('nested route structure happy path', async function () { const config = await test_config() @@ -59,95 +137,95 @@ test('nested route structure happy path', async function () { ).resolves.toMatchInlineSnapshot(` { "pages": { - "__": { - "id": "__", + "_0": { + "id": "_0", "queries": [ "RootQuery" ], "url": "/", "layouts": [ - "__" + "_0" ], "path": "+page.tsx" }, - "__subRoute": { - "id": "__subRoute", + "_0subRoute": { + "id": "_0subRoute", "queries": [ "SubQuery", "RootQuery" ], "url": "/subRoute", "layouts": [ - "__", - "__subRoute" + "_0", + "_0subRoute" ], "path": "subRoute/+page.jsx" }, - "__another": { - "id": "__another", + "_0another": { + "id": "_0another", "queries": [ "MyQuery", "MyLayoutQuery" ], "url": "/another", "layouts": [ - "__", - "__another" + "_0", + "_0another" ], "path": "another/+page.tsx" }, - "__subRoute__nested": { - "id": "__subRoute__nested", + "_0subRoute_0nested": { + "id": "_0subRoute_0nested", "queries": [ "FinalQuery" ], "url": "/subRoute/nested", "layouts": [ - "__", - "__subRoute" + "_0", + "_0subRoute" ], "path": "subRoute/nested/+page.tsx" } }, "layouts": { - "__": { - "id": "__", + "_0": { + "id": "_0", "queries": [], "url": "/", "layouts": [], "path": "+layout.tsx" }, - "__another": { - "id": "__another", + "_0another": { + "id": "_0another", "queries": [ "RootQuery" ], "url": "/another/", "layouts": [ - "__" + "_0" ], "path": "another/+layout.tsx" }, - "__subRoute": { - "id": "__subRoute", + "_0subRoute": { + "id": "_0subRoute", "queries": [ "RootQuery" ], "url": "/subRoute/", "layouts": [ - "__" + "_0" ], "path": "subRoute/+layout.tsx" } }, "page_queries": { - "__another": { + "_0another": { "path": "another/+page.gql", "name": "MyQuery", "url": "/another/", "loading": false }, - "__subRoute__nested": { + "_0subRoute_0nested": { "path": "subRoute/nested/+page.gql", "name": "FinalQuery", "url": "/subRoute/nested/", @@ -155,19 +233,19 @@ test('nested route structure happy path', async function () { } }, "layout_queries": { - "__": { + "_0": { "path": "+layout.gql", "name": "RootQuery", "url": "/", "loading": true }, - "__another": { + "_0another": { "path": "another/+layout.gql", "name": "MyLayoutQuery", "url": "/another/", "loading": false }, - "__subRoute": { + "_0subRoute": { "path": "subRoute/+layout.gql", "name": "SubQuery", "url": "/subRoute/", diff --git a/packages/houdini-react/src/plugin/codegen/manifest.ts b/packages/houdini-react/src/plugin/codegen/manifest.ts index df2cae145..54739d17c 100644 --- a/packages/houdini-react/src/plugin/codegen/manifest.ts +++ b/packages/houdini-react/src/plugin/codegen/manifest.ts @@ -296,7 +296,7 @@ export async function extractQueries(source: string): Promise { throw new Error('Props should be specified as an object pattern.') } } else { - throw new Error('Default export function has no arguments.') + return [] } return props.filter((p) => p !== 'children') diff --git a/packages/houdini-react/src/plugin/codegen/router.test.ts b/packages/houdini-react/src/plugin/codegen/router.test.ts index 2a99a8391..51ab039ea 100644 --- a/packages/houdini-react/src/plugin/codegen/router.test.ts +++ b/packages/houdini-react/src/plugin/codegen/router.test.ts @@ -44,8 +44,8 @@ test('happy path', async function () { .toMatchInlineSnapshot(` "export default { pages: { - \\"__\\": { - id: \\"__\\", + \\"_0\\": { + id: \\"_0\\", pattern: /^\\\\/$/, params: [], @@ -57,11 +57,11 @@ test('happy path', async function () { } }, - component: () => import(\\"../units/entries/__\\") + component: () => import(\\"../units/entries/_0\\") }, - \\"____id__\\": { - id: \\"____id__\\", + \\"_0_2id_1\\": { + id: \\"_0_2id_1\\", pattern: /^\\\\/([^/]+?)\\\\/?$/, params: [{\\"name\\":\\"id\\",\\"optional\\":false,\\"rest\\":false,\\"chained\\":false}], @@ -77,11 +77,11 @@ test('happy path', async function () { } }, - component: () => import(\\"../units/entries/____id__\\") + component: () => import(\\"../units/entries/_0_2id_1\\") }, - \\"__another\\": { - id: \\"__another\\", + \\"_0another\\": { + id: \\"_0another\\", pattern: /^\\\\/another\\\\/?$/, params: [], @@ -101,11 +101,11 @@ test('happy path', async function () { } }, - component: () => import(\\"../units/entries/__another\\") + component: () => import(\\"../units/entries/_0another\\") }, - \\"____id____nested\\": { - id: \\"____id____nested\\", + \\"_0_2id_1_0nested\\": { + id: \\"_0_2id_1_0nested\\", pattern: /^\\\\/([^/]+?)\\\\/nested\\\\/?$/, params: [{\\"name\\":\\"id\\",\\"optional\\":false,\\"rest\\":false,\\"chained\\":false}], @@ -121,23 +121,23 @@ test('happy path', async function () { } }, - component: () => import(\\"../units/entries/____id____nested\\") + component: () => import(\\"../units/entries/_0_2id_1_0nested\\") }, }, layouts: { - \\"__\\": { - id: \\"__\\", + \\"_0\\": { + id: \\"_0\\", queries: [], }, - \\"____id__\\": { - id: \\"____id__\\", + \\"_0_2id_1\\": { + id: \\"_0_2id_1\\", queries: [\\"RootQuery\\"], }, - \\"__another\\": { - id: \\"__another\\", + \\"_0another\\": { + id: \\"_0another\\", queries: [\\"RootQuery\\"], } @@ -181,8 +181,8 @@ test('loading state at root', async function () { .toMatchInlineSnapshot(` "export default { pages: { - \\"__\\": { - id: \\"__\\", + \\"_0\\": { + id: \\"_0\\", pattern: /^\\\\/$/, params: [], @@ -194,11 +194,11 @@ test('loading state at root', async function () { } }, - component: () => import(\\"../units/entries/__\\") + component: () => import(\\"../units/entries/_0\\") }, - \\"____id__\\": { - id: \\"____id__\\", + \\"_0_2id_1\\": { + id: \\"_0_2id_1\\", pattern: /^\\\\/([^/]+?)\\\\/?$/, params: [{\\"name\\":\\"id\\",\\"optional\\":false,\\"rest\\":false,\\"chained\\":false}], @@ -214,11 +214,11 @@ test('loading state at root', async function () { } }, - component: () => import(\\"../units/entries/____id__\\") + component: () => import(\\"../units/entries/_0_2id_1\\") }, - \\"__another\\": { - id: \\"__another\\", + \\"_0another\\": { + id: \\"_0another\\", pattern: /^\\\\/another\\\\/?$/, params: [], @@ -238,11 +238,11 @@ test('loading state at root', async function () { } }, - component: () => import(\\"../units/entries/__another\\") + component: () => import(\\"../units/entries/_0another\\") }, - \\"____id____nested\\": { - id: \\"____id____nested\\", + \\"_0_2id_1_0nested\\": { + id: \\"_0_2id_1_0nested\\", pattern: /^\\\\/([^/]+?)\\\\/nested\\\\/?$/, params: [{\\"name\\":\\"id\\",\\"optional\\":false,\\"rest\\":false,\\"chained\\":false}], @@ -258,23 +258,23 @@ test('loading state at root', async function () { } }, - component: () => import(\\"../units/entries/____id____nested\\") + component: () => import(\\"../units/entries/_0_2id_1_0nested\\") }, }, layouts: { - \\"__\\": { - id: \\"__\\", + \\"_0\\": { + id: \\"_0\\", queries: [], }, - \\"____id__\\": { - id: \\"____id__\\", + \\"_0_2id_1\\": { + id: \\"_0_2id_1\\", queries: [\\"RootQuery\\"], }, - \\"__another\\": { - id: \\"__another\\", + \\"_0another\\": { + id: \\"_0another\\", queries: [\\"RootQuery\\"], } diff --git a/packages/houdini-react/src/plugin/conventions.ts b/packages/houdini-react/src/plugin/conventions.ts index 51af0f205..66d65d0ad 100644 --- a/packages/houdini-react/src/plugin/conventions.ts +++ b/packages/houdini-react/src/plugin/conventions.ts @@ -90,13 +90,14 @@ export function normalize_path(path: string) { if (path.endsWith('/') && path.length > 1) { path = path.substring(0, path.length - 1) } - const special_chars = ['/', ']', '['] - const mask = '__' + const special_chars = ['/', ']', '[', '(', ')'] + const mask = '_' let copy = '' for (const char of path) { - if (special_chars.includes(char)) { - copy += mask + const match = special_chars.indexOf(char) + if (match !== -1) { + copy += mask + match.toString() } else { copy += char }