Skip to content

Commit

Permalink
allow nested components in nunjucks #189
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarotero committed Apr 22, 2022
1 parent cc393b5 commit f81f7c4
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 6 deletions.
3 changes: 3 additions & 0 deletions core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type {
ComponentsTree,
default as ComponentLoader,
} from "./core/component_loader.ts";
import type { ComponentFunction, ProxyComponents } from "./core/components.ts";
import type {
Content,
Data,
Expand Down Expand Up @@ -73,6 +74,7 @@ type Plugin = (site: Site) => void;

export type {
Component,
ComponentFunction,
ComponentLoader,
ComponentsOptions,
ComponentsTree,
Expand Down Expand Up @@ -104,6 +106,7 @@ export type {
PluginSetup,
Processor,
Processors,
ProxyComponents,
Reader,
Renderer,
RequestHandler,
Expand Down
4 changes: 3 additions & 1 deletion core/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export default class Components {
}
}

export type ComponentFunction = (props: Record<string, unknown>) => string;

export interface ProxyComponents {
[key: string]: ((props: Record<string, unknown>) => string) | ProxyComponents;
[key: string]: ComponentFunction | ProxyComponents;
}
40 changes: 35 additions & 5 deletions plugins/nunjucks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import nunjucks from "../deps/nunjucks.ts";
import loader from "../core/loaders/text.ts";
import { merge } from "../core/utils.ts";
import { Exception } from "../core/errors.ts";
import { join } from "../deps/path.ts";

import type { Data, Engine, Helper, HelperOptions, Site } from "../core.ts";
import type {
ComponentFunction,
Data,
Engine,
Helper,
HelperOptions,
ProxyComponents,
Site,
} from "../core.ts";
import type { NunjucksOptions } from "../deps/nunjucks.ts";

export interface Options {
Expand Down Expand Up @@ -156,14 +165,35 @@ export default function (userOptions?: Partial<Options>) {
// Register the component helper
engine.addHelper("comp", (...args) => {
const baseData = site.source.root!.baseData || {};
const components = baseData[site.options.components.variable];
const components = baseData[site.options.components.variable] as
| ProxyComponents
| undefined;
const [content, name, options] = args;
delete options.__keywords;
const props = { content, ...options };

if (!components) {
throw new Error("No components found");
throw new Exception(`Component "${name}" not found`);
}

const [content, name, props] = args;
console.log({ content, name, props });
const names = name.split(".") as string[];
let component: ProxyComponents | ComponentFunction | undefined =
components;

while (names.length) {
try {
// @ts-ignore: `component` is defined or throw an error
component = component[names.shift()];
} catch {
throw new Exception(`Component "${name}" not found`);
}
}

if (typeof component === "function") {
return component(props);
}

throw new Exception(`Component "${name}" not found`);
}, {
type: "tag",
body: true,
Expand Down
8 changes: 8 additions & 0 deletions tests/assets/nunjucks/_components/Button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
interface Props {
content: string;
className?: string;
}

export default function ({ content, className }: Props) {
return `<button class="${className || ""}" type="button">${content}</button>`;
}
3 changes: 3 additions & 0 deletions tests/assets/nunjucks/_components/icon/User.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<icon name="{{ name }}">
{{ content }}
</icon>
10 changes: 10 additions & 0 deletions tests/assets/nunjucks/components.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{{ comp.Button({ content: "button content" }) | safe }}
{{ comp.icon.User({ content: "this is John", name:"John" }) | safe }}

{% comp "Button", className="my-button" %}
button content

{% comp "icon.user", name="John" %}
this is John
{% endcomp %}
{% endcomp %}
7 changes: 7 additions & 0 deletions tests/nunjucks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,11 @@ Deno.test("build a site with nunjucks", async () => {
// @ts-ignore: innerText doesn't exist on Node
equals(lis.item(1)?.innerHTML, "async helper in a partial (async)");
});

testPage(site, "/components", (page) => {
equals(page.data.url, "/components/");
equals(page.document?.querySelectorAll("button").length, 2);
equals(page.document?.querySelectorAll("icon").length, 2);
equals(page.document?.querySelectorAll("button icon").length, 1);
});
});

0 comments on commit f81f7c4

Please sign in to comment.