Skip to content

Commit

Permalink
wip: experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Feb 7, 2024
1 parent 6695982 commit 82d784e
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
*.map
coverage
lib
_lib
node_modules
tsconfig.*.tsbuildinfo
tsconfig.tsbuildinfo
3 changes: 1 addition & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"css.validate": false
}
}
5 changes: 4 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
"linter": {
"enabled": true,
"rules": {
"recommended": true
"recommended": true,
"complexity": {
"noUselessFragments": "off"
}
}
}
}
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
"name": "example",
"private": true,
"scripts": {
"dev": "bun run --hot src/index.ts"
"dev": "bun run --hot src/index.tsx"
},
"dependencies": {
"@wevm/framework": "workspace:*",
"hono": "^3.12.8"
},
"devDependencies": {
Expand Down
9 changes: 0 additions & 9 deletions example/src/index.ts

This file was deleted.

24 changes: 24 additions & 0 deletions example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/** @jsx jsx */
/** @jsxImportSource hono/jsx */
/** @jsxFrag */

import { Button, Framework } from "@wevm/framework";

const app = new Framework();

app.frame("/", () => {
return {
image: <div>hello</div>,
intents: (
<>
<Button>Apples</Button>
<Button>Oranges</Button>
</>
),
};
});

export default {
port: 3001,
fetch: app.fetch,
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"clean": "rimraf src/index.js src/lib src/tsconfig.build.tsbuildinfo",
"format": "biome format . --write",
"lint": "biome check . --apply",
"preconstruct": "bun run scripts/preconstruct.ts",
"test": "vitest",
"typecheck": "tsc --noEmit"
},
Expand Down
93 changes: 93 additions & 0 deletions scripts/preconstruct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import fs from "node:fs/promises";
import path from "node:path";
import { glob } from "glob";

// Symlinks package sources to dist for local development

console.log("Setting up packages for development.");

// Get all package.json files
const packagePaths = await glob("**/package.json", {
ignore: ["**/dist/**", "**/node_modules/**"],
});

let count = 0;
for (const packagePath of packagePaths) {
type Package = {
bin?: Record<string, string> | undefined;
exports?:
| Record<string, { types: string; default: string } | string>
| undefined;
name?: string | undefined;
private?: boolean | undefined;
};
const file = Bun.file(packagePath);
const packageJson = (await file.json()) as Package;

// Skip private packages
if (packageJson.private) continue;
if (!packageJson.exports) continue;

count += 1;
console.log(`${packageJson.name}${path.dirname(packagePath)}`);

const dir = path.resolve(path.dirname(packagePath));

// Empty dist directory
const distDirName = "_lib";
const dist = path.resolve(dir, distDirName);
let files: string[] = [];
try {
files = await fs.readdir(dist);
} catch {
await fs.mkdir(dist);
}

const promises: Promise<void>[] = [];
for (const file of files) {
promises.push(
fs.rm(path.join(dist, file), { recursive: true, force: true }),
);
}
await Promise.all(promises);

// Link exports to dist locations
for (const [key, exports] of Object.entries(packageJson.exports)) {
// Skip `package.json` exports
if (/package\.json$/.test(key)) continue;

let entries: string[][];
if (typeof exports === "string")
entries = [
["default", exports],
["types", exports.replace(".js", ".d.ts")],
];
else entries = Object.entries(exports);

// Link exports to dist locations
for (const [, value] of entries as [
type: "types" | "default",
value: string,
][]) {
const srcDir = path.resolve(
dir,
path.dirname(value).replace(distDirName, ""),
);
let srcFileName: string;
if (key === ".") srcFileName = "index.tsx";
else srcFileName = path.basename(`${key}.tsx`);
const srcFilePath = path.resolve(srcDir, srcFileName);

const distDir = path.resolve(dir, path.dirname(value));
const distFileName = path.basename(value);
const distFilePath = path.resolve(distDir, distFileName);

await fs.mkdir(distDir, { recursive: true });

// Symlink src to dist file
await fs.symlink(srcFilePath, distFilePath, "file");
}
}
}

console.log(`Done. Set up ${count} ${count === 1 ? "package" : "packages"}.`);
1 change: 0 additions & 1 deletion src/index.ts

This file was deleted.

79 changes: 79 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { type Context, Hono } from "hono";
import { ImageResponse } from "hono-og";
import { type JSXNode } from "hono/jsx";

type FrameReturnType = {
image: JSX.Element;
intents: JSX.Element;
};

export class Framework extends Hono {
frame(
path: string,
handler: (c: Context) => FrameReturnType | Promise<FrameReturnType>,
) {
this.get(path, async (c) => {
const { intents } = await handler(c);
return c.render(
<html lang="en">
<head>
<meta property="fc:frame" content="vNext" />
<meta property="fc:frame:image" content={`${c.req.url}_og`} />
<meta property="og:image" content={`${c.req.url}_og`} />
{parseIntents(intents)}
</head>
</html>,
);
});

// TODO: don't slice
this.get(`${path.slice(1)}/_og`, async (c) => {
const { image } = await handler(c);
return new ImageResponse(image);
});
}
}

////////////////////////////////////////////////////////////////////////
// Components

export type ButtonProps = {
children: string;
};

export function Button({ children }: ButtonProps) {
return <meta property="fc:frame:button" content={children} />;
}

////////////////////////////////////////////////////////////////////////
// Utilities

type Counter = { button: number };

function parseIntents(intents_: JSX.Element) {
const intents = intents_ as unknown as JSXNode;
const counter: Counter = {
button: 0,
};

if (typeof intents.children[0] === "object")
return Object.assign(intents, {
children: intents.children.map((e) => parseIntent(e as JSXNode, counter)),
});
return parseIntent(intents, counter);
}

function parseIntent(node: JSXNode, counter: Counter) {
const intent = (
typeof node.tag === "function" ? node.tag({}) : node
) as JSXNode;

const props = intent.props || {};

if (props.property === "fc:frame:button") {
props.property = `fc:frame:button:${counter.button++}`;
props.content = node.children;
}

return Object.assign(intent, { props });
}
12 changes: 9 additions & 3 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
"name": "@wevm/framework",
"version": "0.0.0",
"type": "module",
"module": "lib/index.js",
"types": "lib/index.d.ts",
"typings": "lib/index.d.ts",
"module": "_lib/index.js",
"types": "_lib/index.d.ts",
"typings": "_lib/index.d.ts",
"sideEffects": false,
"exports": {
".": "./_lib/index.js"
},
"peerDependencies": {
"hono": "^3"
},
"dependencies": {
"hono-og": "~0.0.2"
}
}
2 changes: 1 addition & 1 deletion tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./src/lib",
"outDir": "./src/_lib",
"rootDir": "./src"
}
}

0 comments on commit 82d784e

Please sign in to comment.