Skip to content

Commit

Permalink
feat: qwik-city layout hierarchy top (QwikDev#809)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley authored Jul 20, 2022
1 parent 4bb293d commit e31f1a9
Show file tree
Hide file tree
Showing 37 changed files with 446 additions and 383 deletions.
22 changes: 11 additions & 11 deletions packages/qwik-city/buildtime/build-layout.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,41 @@ test('total layouts', ({ layouts }) => {
assert.is(layouts.length, 6, JSON.stringify(layouts, null, 2));
});

test('filename layout', ({ assertLayout }) => {
test('filename nested layout', ({ assertLayout }) => {
const l = assertLayout('AuthLayout');
assert.is(basename(l.filePath), '_layout.tsx');
assert.is(l.type, 'nested');
assert.is(l.layoutType, 'nested');
assert.is(l.layoutName, '');
});

test('directory layout', ({ assertLayout }) => {
test('directory/index nested layout', ({ assertLayout }) => {
const l = assertLayout('BlogLayoutIndex');
assert.is(basename(dirname(l.filePath)), '_layout');
assert.is(basename(l.filePath), 'index.tsx');
assert.is(l.type, 'nested');
assert.is(l.layoutType, 'nested');
assert.is(l.layoutName, '');
});

test('named filename layout', ({ assertLayout }) => {
test('named filename nested layout', ({ assertLayout }) => {
const l = assertLayout('DashboardLayoutdashboard');
assert.is(basename(l.filePath), '_layout-dashboard.tsx');
assert.is(l.type, 'top');
assert.is(l.layoutType, 'nested');
assert.is(l.layoutName, 'dashboard');
});

test('nested directory layout', ({ assertLayout }) => {
test('directory/index top layout', ({ assertLayout }) => {
const l = assertLayout('DocsLayoutIndex');
assert.is(basename(dirname(l.filePath)), '_layout');
assert.is(basename(dirname(l.filePath)), '_layout!');
assert.is(basename(l.filePath), 'index.tsx');
assert.is(l.type, 'nested');
assert.is(l.layoutType, 'top');
assert.is(l.layoutName, '');
});

test('named directory layout', ({ assertLayout }) => {
test('named directory/index nested layout', ({ assertLayout }) => {
const l = assertLayout('ApiLayoutfooIndex');
assert.is(basename(dirname(l.filePath)), '_layout-foo');
assert.is(basename(l.filePath), 'index.tsx');
assert.is(l.type, 'top');
assert.is(l.layoutType, 'nested');
assert.is(l.layoutName, 'foo');
});

Expand Down
71 changes: 40 additions & 31 deletions packages/qwik-city/buildtime/build-pages.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,59 @@ test('pathless directory', ({ assertPage }) => {
assert.equal(r.layouts[1].id, 'AuthLayout');
});

test('index file w/ named layout, in directory w/ named layout', ({ assertPage, layouts }) => {
test('index file w/ nested named layout, in directory w/ nested named layout', ({ assertPage }) => {
const r = assertPage('/api');
assert.equal(r.id, 'ApiIndexfoo');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/api\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 1);
assert.equal(r.layouts[0].id, 'ApiLayoutfooIndex');
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[0].layoutName, '');
assert.equal(r.layouts[0].layoutType, 'nested');
assert.equal(r.layouts[1].id, 'ApiLayoutfooIndex');
assert.equal(r.layouts[1].layoutName, 'foo');
assert.equal(r.layouts[1].layoutType, 'nested');
assert.equal(r.layouts.length, 2);
});

test('file w/out named layout, in directory w/ named layout', ({ assertPage }) => {
test('index file w/out named layout, in directory w/ named layout', ({ assertPage }) => {
const r = assertPage('/dashboard');
assert.equal(r.id, 'DashboardIndex');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/dashboard\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 1);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[0].layoutType, 'nested');
assert.equal(r.layouts.length, 1);
});

test('file w/ named layout, in directory w/ named layout', ({ assertPage }) => {
test('file w/ named layout, in directory w/ nested named layout file', ({ assertPage }) => {
const r = assertPage('/dashboard/profile');
assert.equal(r.id, 'DashboardProfiledashboard');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/dashboard\/profile\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 1);
assert.equal(r.layouts[0].id, 'DashboardLayoutdashboard');
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[0].layoutType, 'nested');
assert.equal(r.layouts[1].id, 'DashboardLayoutdashboard');
assert.equal(r.layouts[1].layoutType, 'nested');
assert.equal(r.layouts.length, 2);
});

test('index file w/ named layout, in directory w/ named layout', ({ assertPage }) => {
test('index file w/ named layout, in directory w/ nested named layout file', ({ assertPage }) => {
const r = assertPage('/dashboard/settings');
assert.equal(r.id, 'DashboardSettingsIndexdashboard');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/dashboard\/settings\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 1);
assert.equal(r.layouts[0].id, 'DashboardLayoutdashboard');
assert.equal(r.layouts[0].type, 'top');
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[0].layoutType, 'nested');
assert.equal(r.layouts[1].id, 'DashboardLayoutdashboard');
assert.equal(r.layouts[1].layoutType, 'nested');
assert.equal(r.layouts.length, 2);
});

test('params route, index file w/out named layout, in directory w/ layout directory', ({
test('params route, index file w/out named layout, in directory w/ top layout directory', ({
assertPage,
}) => {
const r = assertPage('/docs/[category]/[id]');
Expand All @@ -67,55 +78,53 @@ test('params route, index file w/out named layout, in directory w/ layout direct
assert.equal(r.paramNames.length, 2);
assert.equal(r.paramNames[0], 'category');
assert.equal(r.paramNames[1], 'id');
assert.equal(r.layouts.length, 2);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[1].id, 'DocsLayoutIndex');
assert.equal(r.layouts[0].id, 'DocsLayoutIndex');
assert.equal(r.layouts.length, 1);
});

test('markdown index file w/out named layout, in directory w/ layout directory', ({
test('markdown index file w/out named layout, in directory w/ top layout directory', ({
assertPage,
}) => {
const r = assertPage('/docs/overview');
assert.equal(r.id, 'DocsOverviewIndex');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/docs\/overview\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 2);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[1].id, 'DocsLayoutIndex');
assert.equal(r.layouts[0].id, 'DocsLayoutIndex');
assert.equal(r.layouts.length, 1);
});

test('markdown file w/out named layout, in directory w/ layout directory', ({ assertPage }) => {
test('markdown file w/out named layout, in directory w/ top layout directory', ({ assertPage }) => {
const r = assertPage('/docs/getting-started');
assert.equal(r.id, 'DocsGettingstarted');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/docs\/getting-started\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 2);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[1].id, 'DocsLayoutIndex');
assert.equal(r.layouts[0].id, 'DocsLayoutIndex');
assert.equal(r.layouts.length, 1);
});

test('index file w/out named layout, in directory w/ layout directory', ({ assertPage }) => {
test('index file w/out named layout, in directory w/ top layout directory', ({ assertPage }) => {
const r = assertPage('/docs');
assert.equal(r.id, 'DocsIndex');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/docs\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 2);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[1].id, 'DocsLayoutIndex');
assert.equal(r.layouts[0].id, 'DocsLayoutIndex');
assert.equal(r.layouts[0].layoutName, '');
assert.equal(r.layouts[0].layoutType, 'top');
assert.equal(r.layouts.length, 1);
});

test('index file w/out named layout, in directory w/ layout directory', ({ assertPage }) => {
test('named file w/out named layout, in directory w/ layout directory', ({ assertPage }) => {
const r = assertPage('/about-us');
assert.equal(r.id, 'Aboutus');
assert.equal(r.type, 'page');
assert.equal(r.pattern, /^\/about-us\/?$/);
assert.equal(r.paramNames.length, 0);
assert.equal(r.layouts.length, 1);
assert.equal(r.layouts[0].id, 'Layout');
assert.equal(r.layouts[0].type, 'nested');
assert.equal(r.layouts[0].layoutType, 'nested');
assert.equal(r.layouts.length, 1);
});

test('named tsx file', ({ assertPage }) => {
Expand Down
24 changes: 0 additions & 24 deletions packages/qwik-city/buildtime/routing/endpoint.ts

This file was deleted.

37 changes: 0 additions & 37 deletions packages/qwik-city/buildtime/routing/layout.ts

This file was deleted.

48 changes: 0 additions & 48 deletions packages/qwik-city/buildtime/routing/page.ts

This file was deleted.

87 changes: 87 additions & 0 deletions packages/qwik-city/buildtime/routing/resolve-source-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { dirname } from 'path';
import type {
BuildLayout,
BuildRoute,
NormalizedPluginOptions,
ParsedLayoutId,
RouteSourceFile,
} from '../types';
import { createFileId, isLayoutName, normalizePath, parseLayoutId } from '../utils/fs';
import { getPathnameFromFilePath } from '../utils/pathname';
import { parseRoutePathname } from './parse-pathname';

export function resolveLayout(routesDir: string, layoutSourceFile: RouteSourceFile) {
const dirName = layoutSourceFile.dirName;
const filePath = layoutSourceFile.filePath;
let dirPath = layoutSourceFile.dirPath;

let layoutId: ParsedLayoutId;

if (isLayoutName(dirName)) {
dirPath = normalizePath(dirname(dirPath));
layoutId = parseLayoutId(dirName);
} else {
layoutId = parseLayoutId(layoutSourceFile.fileName);
}

const layout: BuildLayout = {
id: createFileId(routesDir, filePath),
filePath,
dirPath,
...layoutId,
};

return layout;
}

export function resolveRoute(
opts: NormalizedPluginOptions,
appLayouts: BuildLayout[],
sourceFile: RouteSourceFile
) {
const filePath = sourceFile.filePath;
const layouts: BuildLayout[] = [];
const routesDir = opts.routesDir;
const { pathname, layoutName } = getPathnameFromFilePath(opts, filePath);
const hasNamedLayout = layoutName !== '';

let currentDir = normalizePath(dirname(filePath));
let hasFoundNamedLayout = false;

for (let i = 0; i < 20; i++) {
let layout: BuildLayout | undefined = undefined;

if (hasNamedLayout && !hasFoundNamedLayout) {
layout = appLayouts.find((l) => l.dirPath === currentDir && l.layoutName === layoutName);
if (layout) {
hasFoundNamedLayout = true;
}
} else {
layout = appLayouts.find((l) => l.dirPath === currentDir && l.layoutName === '');
}

if (layout) {
layouts.push(layout);
if (layout.layoutType === 'top') {
break;
}
}

if (currentDir === routesDir) {
break;
}

currentDir = normalizePath(dirname(currentDir));
}

const buildRoute: BuildRoute = {
type: sourceFile.type as any,
id: createFileId(routesDir, filePath),
filePath,
pathname,
layouts: layouts.reverse(),
...parseRoutePathname(pathname),
};

return buildRoute;
}
Loading

0 comments on commit e31f1a9

Please sign in to comment.