fuzor 0.0.1 → 0.2.1

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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +97 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/compiler/index.d.ts +28 -0
  8. package/dist/compiler/index.d.ts.map +1 -0
  9. package/dist/compiler/index.js +184 -0
  10. package/dist/compiler/index.js.map +1 -0
  11. package/dist/compiler/islands.d.ts +17 -0
  12. package/dist/compiler/islands.d.ts.map +1 -0
  13. package/dist/compiler/islands.js +78 -0
  14. package/dist/compiler/islands.js.map +1 -0
  15. package/dist/create.d.ts +21 -0
  16. package/dist/create.d.ts.map +1 -0
  17. package/dist/create.js +111 -0
  18. package/dist/create.js.map +1 -0
  19. package/dist/index.d.ts +8 -8
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +6 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/islands/react.d.ts +8 -0
  24. package/dist/islands/react.d.ts.map +1 -0
  25. package/dist/islands/react.js +19 -0
  26. package/dist/islands/react.js.map +1 -0
  27. package/dist/islands/solid.d.ts +8 -0
  28. package/dist/islands/solid.d.ts.map +1 -0
  29. package/dist/islands/solid.js +15 -0
  30. package/dist/islands/solid.js.map +1 -0
  31. package/dist/islands/vue.d.ts +5 -0
  32. package/dist/islands/vue.d.ts.map +1 -0
  33. package/dist/islands/vue.js +13 -0
  34. package/dist/islands/vue.js.map +1 -0
  35. package/dist/runtime/atom.d.ts +10 -0
  36. package/dist/runtime/atom.d.ts.map +1 -0
  37. package/dist/runtime/atom.js +38 -0
  38. package/dist/runtime/atom.js.map +1 -0
  39. package/dist/runtime/index.d.ts +31 -0
  40. package/dist/runtime/index.d.ts.map +1 -0
  41. package/dist/runtime/index.js +121 -0
  42. package/dist/runtime/index.js.map +1 -0
  43. package/dist/runtime/islands.d.ts +6 -0
  44. package/dist/runtime/islands.d.ts.map +1 -0
  45. package/dist/runtime/islands.js +43 -0
  46. package/dist/runtime/islands.js.map +1 -0
  47. package/dist/ssr/node.d.ts +7 -0
  48. package/dist/ssr/node.d.ts.map +1 -0
  49. package/dist/ssr/node.js +46 -0
  50. package/dist/ssr/node.js.map +1 -0
  51. package/dist/ssr.d.ts +10 -0
  52. package/dist/ssr.d.ts.map +1 -0
  53. package/dist/ssr.js +19 -0
  54. package/dist/ssr.js.map +1 -0
  55. package/dist/vite.d.ts +8 -0
  56. package/dist/vite.d.ts.map +1 -0
  57. package/dist/vite.js +310 -0
  58. package/dist/vite.js.map +1 -0
  59. package/package.json +71 -56
  60. package/templates/basic/README.md +16 -0
  61. package/templates/basic/_gitignore +3 -0
  62. package/templates/basic/components/app-badge.html +1 -0
  63. package/templates/basic/index.html +12 -0
  64. package/templates/basic/islands/counter.ts +13 -0
  65. package/templates/basic/package.json +20 -0
  66. package/templates/basic/pages/about/index.html +5 -0
  67. package/templates/basic/pages/docs/index.md +9 -0
  68. package/templates/basic/pages/index.html +9 -0
  69. package/templates/basic/pages/layout.html +8 -0
  70. package/templates/basic/pnpm-workspace.yaml +5 -0
  71. package/templates/basic/server.mjs +10 -0
  72. package/templates/basic/style.css +1 -0
  73. package/templates/basic/tsconfig.json +13 -0
  74. package/templates/basic/vite.config.ts +4 -0
  75. package/bin/index.js +0 -13
  76. package/dist/core/init.d.ts +0 -7
  77. package/dist/core/router.d.ts +0 -4
  78. package/dist/core/vite-config.d.ts +0 -5
  79. package/dist/init.cjs +0 -237
  80. package/dist/init.js +0 -468
  81. package/dist/lib.cjs +0 -222
  82. package/dist/lib.js +0 -19247
  83. package/dist/render/lit.d.ts +0 -1
  84. package/dist/render/preact.d.ts +0 -1
  85. package/dist/render/react.d.ts +0 -7
  86. package/dist/render/solid.d.ts +0 -1
  87. package/dist/render/svelte.d.ts +0 -6
  88. package/dist/render/vue.d.ts +0 -1
  89. package/dist/utils/create-file-if-not-exists.d.ts +0 -1
  90. package/dist/utils/create-folder-if-not-exist.d.ts +0 -2
  91. package/dist/utils/default-theme-files.d.ts +0 -7
  92. package/dist/utils/file-path-helpers.d.ts +0 -3
  93. package/dist/utils/is-valid-wordpress-slug.d.ts +0 -17
  94. package/dist/utils/read-write-file.d.ts +0 -1
  95. package/dist/utils/remove-file-exists.d.ts +0 -2
  96. package/dist/utils/remove-trailing-slash-url.d.ts +0 -1
  97. package/dist/utils/router-helpers.d.ts +0 -19
  98. package/dist/utils/zip-wp-theme.d.ts +0 -2
  99. package/types/index.d.ts +0 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-present Ivan Jeremic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # Fuzor
2
+
3
+ **One source app. Three ways to ship.** Write your routes, layouts, components, and islands once, then compile that same source tree as a SPA, a static MPA, or a server-served app. Choose a build target, and Fuzor's compiler produces the right output for it. Your pages and islands keep the same appearance and behavior in every mode, with no rewrites or separate implementations.
4
+
5
+ Fuzor is an early HTML-first framework prototype. Pages can be HTML or Markdown, with interactive islands where needed. The Fuzor CLI selects the build target.
6
+
7
+ | Target | What the build produces | How navigation works |
8
+ | --- | --- | --- |
9
+ | `spa` | One HTML document containing the compiled route templates, plus an ESM entry and lazy island chunks | The browser selects templates with the History API; route content is already in the initial document |
10
+ | `mpa` | A standalone HTML file per route and client assets | Ordinary links load the next document; suitable for static hosting |
11
+ | `ssr` | A server entry containing complete, preassembled route documents and client assets | The server looks up the requested route and sends its document |
12
+
13
+ Despite the `ssr` name, the current server target **prerenders at build time**. It does not render or stitch page HTML on each request. The MPA target is also static generation; there is no separate SSG mode. Add `--inline` to a SPA build to put its JavaScript and CSS into a single HTML file for embedded or offline UIs.
14
+
15
+ ## Try it locally
16
+
17
+ This repository contains a [mixed-framework example](./examples/basic) and the [Fuzor website](./website), which is itself a Fuzor app. From the repository root:
18
+
19
+ ```bash
20
+ pnpm install
21
+ pnpm build
22
+ pnpm example:dev:ssr
23
+ ```
24
+
25
+ Open the address printed by Vite. On the example homepage, **View Page Source** shows the vanilla, React, Solid, and Vue counter markup before the browser activates the islands. Click the counters to see the client behavior attach to that markup. The same example can run in the other development targets:
26
+
27
+ ```bash
28
+ pnpm --filter @fuzor/example dev:spa
29
+ pnpm --filter @fuzor/example dev:mpa
30
+ ```
31
+
32
+ Build each output from those same source files:
33
+
34
+ ```bash
35
+ pnpm example:spa # examples/basic/dist-spa/
36
+ pnpm example:spa --inline # single dist-spa/index.html
37
+ pnpm example:mpa # examples/basic/dist-mpa/
38
+ pnpm example:ssr # examples/basic/dist-ssr/
39
+ pnpm --filter @fuzor/example start:ssr # serve the built SSR target on port 4173
40
+ ```
41
+
42
+ Run `pnpm website:dev` for the website, or `pnpm website:build` for its static MPA output. Its homepage is HTML; the `/docs` route tree is Markdown files and folders under [`website/pages/docs/`](./website/pages/docs), with a shared docs layout in [`website/layouts/docs.html`](./website/layouts/docs.html).
43
+
44
+ ## How an app is written
45
+
46
+ Routes are folders containing `index.html` or `index.md`. A route can inherit layouts and use reusable HTML components. Interactive regions are explicit islands:
47
+
48
+ ```text
49
+ my-app/
50
+ ├── index.html # document shell
51
+ ├── pages/
52
+ │ ├── index.html # /
53
+ │ ├── about/index.html # /about/
54
+ │ └── docs/index.md # /docs/
55
+ ├── components/
56
+ │ └── app-header.html # <app-header>
57
+ └── islands/
58
+ └── counter.ts
59
+ ```
60
+
61
+ ```html
62
+ <fuzor-link href="/about/">About</fuzor-link>
63
+ <fuzor-island src="counter" props='{"initial":1}' client:load></fuzor-island>
64
+ ```
65
+
66
+ `<fuzor-link>` becomes a real anchor, so links work without JavaScript in the MPA and server targets. In the SPA, the router handles navigation and replaces route markup. A vanilla island exports `mount(host, props)` and may return a cleanup function. It can also export `render(props)` to provide initial HTML at build time. `client:load`, `client:idle`, and `client:visible` control when an island activates.
67
+
68
+ React, Solid, and Vue islands in the example render their initial HTML **during compilation**, then hydrate inside separate DOM hosts in the browser. Their frameworks do not own each other's DOM. React and Solid JSX use file-specific Vite plugin filters (`*.react.tsx` and `*.solid.tsx`) so their transforms do not collide; Solid's plugin enables SSR rendering. This is renderer-based build-time output, not static extraction of JSX templates. See the [island architecture and its constraints](./design/islands.md).
69
+
70
+ For contributors: the compiler uses [Effect v4](https://effect.website/) services and Layers for file access, typed compilation errors, and bounded concurrent directory work. It validates route and layout structure and renders Markdown to HTML at build time with [TanStack Markdown](https://tanstack.com/markdown). The runtime provides browser and in-memory history hosts plus schema-checked URL atoms.
71
+
72
+ ## CLI and new apps
73
+
74
+ The CLI uses Citty for commands and Clack for interactive creation and progress. It selects a target while Vite handles serving and bundling:
75
+
76
+ Create an app with the official scaffold command:
77
+
78
+ ```bash
79
+ npm create fuzor@latest my-app
80
+ cd my-app
81
+ pnpm install
82
+ pnpm dev
83
+ ```
84
+
85
+ The creator can install dependencies for you; if you accept that prompt, the separate `pnpm install` is optional. It generates one source tree with scripts for all three targets. The `create-fuzor` npm package powers this command.
86
+
87
+ ```bash
88
+ fuzor dev --target spa # also mpa or ssr; accepts --host and --port
89
+ fuzor build --target spa
90
+ fuzor build --target spa --inline
91
+ fuzor build --target mpa
92
+ fuzor build --target ssr
93
+ fuzor create my-app
94
+ ```
95
+
96
+ A Vite config can simply add `fuzorPlugin()`. The [starter template](./templates/basic) includes scripts for all three targets, a Markdown route, and a vanilla island. The `fuzor create my-app` command calls the same creator if Fuzor is already installed. Deployment adapters and `fuzor deploy` are not implemented.
97
+
98
+ ## Current boundaries
99
+
100
+ Fuzor currently compiles **known, static folder routes**. Dynamic URL parameters, request-time page data, forms, per-page revalidation, and request-time rendering are future work. Build-time island previews require known JSON props and a compatible renderer; other islands begin with an empty host. Arbitrary asynchronous content cannot yet promise a layout-shift-free placeholder. Multiple versions of one UI framework in a single build are not guaranteed; additional JSX systems need their own tested adapters.
101
+
102
+ The SPA carries every route's HTML in its initial document, so that document grows with the route tree, even though its island code loads lazily. SPA deep links need a hosting fallback to `index.html`. The inline build requires assets it can embed.
103
+
104
+ ```bash
105
+ pnpm test
106
+ pnpm typecheck
107
+ pnpm --filter @fuzor/example typecheck
108
+ pnpm verify:profiles
109
+ pnpm website:verify
110
+ ```
111
+
112
+ Further detail lives in the [website docs](./website/pages/docs) and the [example walkthrough](./examples/basic/README.md).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from "node:fs/promises";
3
+ import { defineCommand, runMain } from "citty";
4
+ import * as prompts from "@clack/prompts";
5
+ import colors from "picocolors";
6
+ import { createCommand } from "./create.js";
7
+ const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
8
+ const targetArg = () => ({ type: "enum", options: ["spa", "mpa", "ssr"], default: "spa", description: "Output profile" });
9
+ function selectTarget(target, inline = false) {
10
+ process.env.FUZOR_TARGET = target;
11
+ process.env.FUZOR_INLINE = inline ? "1" : "0";
12
+ }
13
+ const dev = defineCommand({
14
+ meta: { name: "dev", description: "Start Vite with a Fuzor profile" },
15
+ args: {
16
+ target: targetArg(),
17
+ host: { type: "string", description: "Host to listen on" },
18
+ port: { type: "string", description: "Port to listen on" }
19
+ },
20
+ async run({ args }) {
21
+ const target = (args.target ?? "spa");
22
+ selectTarget(target);
23
+ const port = args.port === undefined ? undefined : Number(args.port);
24
+ if (port !== undefined && (!Number.isInteger(port) || port < 1 || port > 65535))
25
+ throw new Error("--port must be between 1 and 65535.");
26
+ prompts.intro(colors.cyan(colors.bold(`◉ Fuzor ${target.toUpperCase()}`)));
27
+ const spin = process.stdout.isTTY ? prompts.spinner() : undefined;
28
+ if (spin)
29
+ spin.start("Starting development server");
30
+ else
31
+ console.log("Starting development server...");
32
+ try {
33
+ const { createServer } = await import("vite");
34
+ const server = await createServer({
35
+ server: { ...(args.host === undefined ? {} : { host: args.host }), ...(port === undefined ? {} : { port }) },
36
+ logLevel: "error"
37
+ });
38
+ await server.listen();
39
+ if (spin)
40
+ spin.stop("Development server ready");
41
+ else
42
+ console.log("Development server ready");
43
+ for (const url of server.resolvedUrls?.local ?? [])
44
+ console.log(` ${colors.green("Local")} ${url}`);
45
+ for (const url of server.resolvedUrls?.network ?? [])
46
+ console.log(` ${colors.green("Network")} ${url}`);
47
+ const close = () => { void server.close().then(() => { process.exitCode = 0; }); };
48
+ process.once("SIGINT", close);
49
+ process.once("SIGTERM", close);
50
+ }
51
+ catch (error) {
52
+ if (spin)
53
+ spin.stop("Could not start development server");
54
+ throw error;
55
+ }
56
+ }
57
+ });
58
+ const buildCommand = defineCommand({
59
+ meta: { name: "build", description: "Build a Fuzor profile with Vite" },
60
+ args: {
61
+ target: targetArg(),
62
+ inline: { type: "boolean", description: "Inline SPA JavaScript and CSS into one HTML file" }
63
+ },
64
+ async run({ args }) {
65
+ const target = (args.target ?? "spa");
66
+ if (args.inline && target !== "spa")
67
+ throw new Error("--inline is only supported for the SPA target.");
68
+ selectTarget(target, args.inline);
69
+ const outDir = target === "ssr" ? "dist-ssr/client" : `dist-${target}`;
70
+ prompts.intro(colors.cyan(colors.bold(`◉ Fuzor ${target.toUpperCase()}`)));
71
+ const spin = process.stdout.isTTY ? prompts.spinner() : undefined;
72
+ if (spin)
73
+ spin.start(args.inline ? "Building inline SPA" : `Building ${target.toUpperCase()}`);
74
+ else
75
+ console.log(args.inline ? "Building inline SPA..." : `Building ${target.toUpperCase()}...`);
76
+ try {
77
+ const { build } = await import("vite");
78
+ await build({ build: { outDir }, logLevel: "error" });
79
+ if (spin)
80
+ spin.stop(`Built ${colors.green(outDir)}`);
81
+ else
82
+ console.log(`Built ${outDir}`);
83
+ prompts.outro(args.inline ? "One HTML file, ready to ship" : "Build complete");
84
+ }
85
+ catch (error) {
86
+ if (spin)
87
+ spin.stop("Build failed");
88
+ throw error;
89
+ }
90
+ }
91
+ });
92
+ const main = defineCommand({
93
+ meta: { name: "fuzor", version: packageJson.version, description: "Compile one app for every Fuzor target" },
94
+ subCommands: { dev, build: buildCommand, create: createCommand }
95
+ });
96
+ void runMain(main);
97
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Dirent, Stats } from "node:fs";
2
+ import { Context, Effect, Layer } from "effect";
3
+ export type CompiledRoute = {
4
+ readonly path: string;
5
+ readonly source: string;
6
+ readonly html: string;
7
+ };
8
+ export type CompiledProject = {
9
+ readonly routes: readonly CompiledRoute[];
10
+ readonly files: readonly string[];
11
+ };
12
+ export declare class CompilerError extends Error {
13
+ readonly _tag = "CompilerError";
14
+ }
15
+ export type CompilerFileSystemShape = {
16
+ readonly read: (file: string) => Effect.Effect<string, CompilerError>;
17
+ readonly entries: (directory: string) => Effect.Effect<Dirent[], CompilerError>;
18
+ readonly stat: (file: string) => Effect.Effect<Stats, CompilerError>;
19
+ readonly exists: (file: string) => Effect.Effect<boolean, CompilerError>;
20
+ };
21
+ export declare const CompilerFileSystem: Context.Service<CompilerFileSystemShape, CompilerFileSystemShape>;
22
+ export declare const CompilerFileSystemLive: Layer.Layer<CompilerFileSystemShape, never, never>;
23
+ export declare function compileProjectEffect(root: string): Effect.Effect<{
24
+ routes: CompiledRoute[];
25
+ files: string[];
26
+ }, CompilerError, CompilerFileSystemShape>;
27
+ export declare function compileProject(root: string): Promise<CompiledProject>;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAKhD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAIF,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,mBAAmB;CACjC;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtE,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC;IAChF,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACrE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;CAC1E,CAAC;AAEF,eAAO,MAAM,kBAAkB,mEAAsE,CAAC;AAKtG,eAAO,MAAM,sBAAsB,oDAWC,CAAC;AAuErC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM;;;2CAiFhD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAErE"}
@@ -0,0 +1,184 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { Context, Effect, Layer } from "effect";
4
+ import { parseMarkdown } from "@tanstack/markdown/parser";
5
+ import { renderHtml } from "@tanstack/markdown/html";
6
+ import { parseFragment } from "parse5";
7
+ const slotPattern = /<slot\s*(?:\/\s*>|>\s*<\/slot\s*>)/i;
8
+ export class CompilerError extends Error {
9
+ _tag = "CompilerError";
10
+ }
11
+ export const CompilerFileSystem = Context.Service("FuzorCompilerFileSystem");
12
+ const io = (label, action) => Effect.tryPromise({ try: action, catch: (error) => new CompilerError(`${label}: ${String(error)}`) });
13
+ export const CompilerFileSystemLive = Layer.succeed(CompilerFileSystem, {
14
+ read: (file) => io(`Cannot read ${file}`, () => readFile(file, "utf8")),
15
+ entries: (directory) => io(`Cannot list ${directory}`, () => readdir(directory, { withFileTypes: true })),
16
+ stat: (file) => io(`Cannot stat ${file}`, () => stat(file)),
17
+ exists: (file) => io(`Cannot check ${file}`, async () => {
18
+ try {
19
+ return (await stat(file)).isFile();
20
+ }
21
+ catch (error) {
22
+ if (error.code === "ENOENT")
23
+ return false;
24
+ throw error;
25
+ }
26
+ })
27
+ });
28
+ function routePath(relativeDir) {
29
+ return relativeDir === "" ? "/" : `/${relativeDir.split(path.sep).join("/")}/`;
30
+ }
31
+ function fillSlot(layout, content, label) {
32
+ if (!slotPattern.test(layout)) {
33
+ throw new Error(`${label} must contain a default <slot></slot>.`);
34
+ }
35
+ return layout.replace(slotPattern, () => content);
36
+ }
37
+ function expandComponents(html, components, stack = []) {
38
+ const fragment = parseFragment(html, { sourceCodeLocationInfo: true });
39
+ const replacements = [];
40
+ const visit = (node) => {
41
+ if (!("tagName" in node))
42
+ return;
43
+ const name = node.tagName;
44
+ const source = components.get(name);
45
+ if (source) {
46
+ if (stack.includes(name))
47
+ throw new Error(`Component cycle: ${[...stack, name].join(" -> ")}`);
48
+ const location = node.sourceCodeLocation;
49
+ if (!location?.startTag || !location.endTag)
50
+ throw new Error(`Component <${name}> must have a closing tag.`);
51
+ const children = html.slice(location.startTag.endOffset, location.endTag.startOffset);
52
+ const nested = expandComponents(children, components, stack);
53
+ const body = slotPattern.test(source) ? fillSlot(source, nested, `Component ${name}`) : source;
54
+ replacements.push({
55
+ start: location.startOffset,
56
+ end: location.endOffset,
57
+ value: expandComponents(body, components, [...stack, name])
58
+ });
59
+ return;
60
+ }
61
+ for (const child of node.childNodes)
62
+ visit(child);
63
+ if (node.tagName === "template") {
64
+ for (const child of node.content.childNodes)
65
+ visit(child);
66
+ }
67
+ };
68
+ for (const node of fragment.childNodes)
69
+ visit(node);
70
+ for (const replacement of replacements.sort((a, b) => b.start - a.start)) {
71
+ html = html.slice(0, replacement.start) + replacement.value + html.slice(replacement.end);
72
+ }
73
+ return html;
74
+ }
75
+ function compileLinks(html) {
76
+ const fragment = parseFragment(html, { sourceCodeLocationInfo: true });
77
+ const replacements = [];
78
+ const visit = (node) => {
79
+ if (!("tagName" in node))
80
+ return;
81
+ if (node.tagName === "fuzor-link") {
82
+ const location = node.sourceCodeLocation;
83
+ if (!location?.startTag || !location.endTag)
84
+ throw new Error("<fuzor-link> must have a closing tag.");
85
+ const opening = html.slice(location.startTag.startOffset, location.startTag.endOffset)
86
+ .replace(/^<fuzor-link\b/i, "<a data-fuzor-link");
87
+ replacements.push({ start: location.startTag.startOffset, end: location.startTag.endOffset, value: opening });
88
+ replacements.push({ start: location.endTag.startOffset, end: location.endTag.endOffset, value: "</a>" });
89
+ }
90
+ for (const child of node.childNodes)
91
+ visit(child);
92
+ if (node.tagName === "template") {
93
+ for (const child of node.content.childNodes)
94
+ visit(child);
95
+ }
96
+ };
97
+ for (const node of fragment.childNodes)
98
+ visit(node);
99
+ for (const replacement of replacements.sort((a, b) => b.start - a.start)) {
100
+ html = html.slice(0, replacement.start) + replacement.value + html.slice(replacement.end);
101
+ }
102
+ return html;
103
+ }
104
+ export function compileProjectEffect(root) {
105
+ return Effect.gen(function* () {
106
+ const fs = yield* CompilerFileSystem;
107
+ const projectRoot = path.resolve(root);
108
+ const pagesRoot = path.join(projectRoot, "pages");
109
+ const componentsRoot = path.join(projectRoot, "components");
110
+ const layoutsRoot = path.join(projectRoot, "layouts");
111
+ for (const directory of [pagesRoot, componentsRoot]) {
112
+ const directoryStat = yield* fs.stat(directory);
113
+ if (!directoryStat.isDirectory())
114
+ yield* Effect.fail(new CompilerError(`${directory} must be a directory.`));
115
+ }
116
+ const files = [];
117
+ const components = new Map();
118
+ const componentEntries = yield* fs.entries(componentsRoot);
119
+ yield* Effect.forEach(componentEntries, (entry) => Effect.gen(function* () {
120
+ if (!entry.isFile() || !entry.name.endsWith(".html"))
121
+ return;
122
+ const name = entry.name.slice(0, -5);
123
+ if (!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/.test(name) || name.startsWith("fuzor-")) {
124
+ yield* Effect.fail(new CompilerError(`Invalid component filename: ${entry.name}. Use kebab-case and reserve fuzor-* for the framework.`));
125
+ }
126
+ const file = path.join(componentsRoot, entry.name);
127
+ components.set(name, yield* fs.read(file));
128
+ files.push(file);
129
+ }), { concurrency: 8, discard: true });
130
+ const routes = [];
131
+ const visit = (directory, relativeDir, layouts) => Effect.gen(function* () {
132
+ const entries = yield* fs.entries(directory);
133
+ const layoutFile = path.join(directory, "layout.html");
134
+ const externalLayoutFile = relativeDir ? path.join(layoutsRoot, `${relativeDir}.html`) : "";
135
+ const hasLocalLayout = yield* fs.exists(layoutFile);
136
+ const hasExternalLayout = externalLayoutFile ? yield* fs.exists(externalLayoutFile) : false;
137
+ if (hasLocalLayout && hasExternalLayout) {
138
+ yield* Effect.fail(new CompilerError(`Duplicate layout for /${relativeDir}/: ${layoutFile} and ${externalLayoutFile}`));
139
+ }
140
+ const selectedLayout = hasLocalLayout ? layoutFile : hasExternalLayout ? externalLayoutFile : undefined;
141
+ const ownLayouts = selectedLayout
142
+ ? [...layouts, yield* fs.read(selectedLayout)]
143
+ : [...layouts];
144
+ if (selectedLayout)
145
+ files.push(selectedLayout);
146
+ const htmlFile = path.join(directory, "index.html");
147
+ const mdFile = path.join(directory, "index.md");
148
+ const hasHtml = yield* fs.exists(htmlFile);
149
+ const hasMarkdown = yield* fs.exists(mdFile);
150
+ if (hasHtml && hasMarkdown)
151
+ yield* Effect.fail(new CompilerError(`${directory} has both index.html and index.md.`));
152
+ if (hasHtml || hasMarkdown) {
153
+ const source = hasHtml ? htmlFile : mdFile;
154
+ const raw = yield* fs.read(source);
155
+ files.push(source);
156
+ let content = hasMarkdown ? yield* Effect.try({
157
+ try: () => renderHtml(parseMarkdown(raw)),
158
+ catch: (error) => new CompilerError(`Markdown error in ${source}: ${String(error)}`)
159
+ }) : raw;
160
+ content = yield* Effect.try({
161
+ try: () => {
162
+ for (let index = ownLayouts.length - 1; index >= 0; index--) {
163
+ content = fillSlot(ownLayouts[index], content, `Layout ${index + 1} for ${source}`);
164
+ }
165
+ return compileLinks(expandComponents(content, components));
166
+ },
167
+ catch: (error) => new CompilerError(`Compilation failed for ${source}: ${String(error)}`)
168
+ });
169
+ routes.push({ path: routePath(relativeDir), source, html: content });
170
+ }
171
+ yield* Effect.forEach(entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")), (entry) => visit(path.join(directory, entry.name), path.join(relativeDir, entry.name), ownLayouts), { concurrency: 8, discard: true });
172
+ });
173
+ yield* visit(pagesRoot, "", []);
174
+ if (!routes.some((route) => route.path === "/")) {
175
+ yield* Effect.fail(new CompilerError(`${pagesRoot} requires index.html or index.md for the root route.`));
176
+ }
177
+ routes.sort((a, b) => a.path.localeCompare(b.path));
178
+ return { routes, files };
179
+ });
180
+ }
181
+ export function compileProject(root) {
182
+ return Effect.runPromise(compileProjectEffect(root).pipe(Effect.provide(CompilerFileSystemLive)));
183
+ }
184
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Effect } from "effect";
2
+ import type { CompiledProject } from "./index.js";
3
+ export declare class IslandCompileError extends Error {
4
+ readonly _tag = "IslandCompileError";
5
+ }
6
+ export type IslandRenderer = (name: string, props: Record<string, unknown>, id: string) => Promise<string | undefined>;
7
+ /** Compiler phase that prerenders each known island into its route document. */
8
+ export declare function compileIslandsEffect(project: CompiledProject, renderer: IslandRenderer): Effect.Effect<{
9
+ routes: {
10
+ html: string;
11
+ path: string;
12
+ source: string;
13
+ }[];
14
+ files: readonly string[];
15
+ }, IslandCompileError, never>;
16
+ export declare function compileIslands(project: CompiledProject, renderer: IslandRenderer): Promise<CompiledProject>;
17
+ //# sourceMappingURL=islands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"islands.d.ts","sourceRoot":"","sources":["../../src/compiler/islands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAEjE,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,wBAAwB;CACtC;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AA+CvH,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc;;;;;;;8BAyBtF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAE3G"}
@@ -0,0 +1,78 @@
1
+ import { Effect } from "effect";
2
+ import { parseFragment } from "parse5";
3
+ export class IslandCompileError extends Error {
4
+ _tag = "IslandCompileError";
5
+ }
6
+ function locateIslands(html, routeId) {
7
+ const fragment = parseFragment(html, { sourceCodeLocationInfo: true });
8
+ const found = [];
9
+ const visit = (node, insideIsland = false) => {
10
+ if (!("tagName" in node))
11
+ return;
12
+ const isIsland = node.tagName === "fuzor-island";
13
+ if (isIsland) {
14
+ if (insideIsland)
15
+ throw new IslandCompileError("Nested Fuzor islands are not supported.");
16
+ const location = node.sourceCodeLocation;
17
+ if (!location?.startTag || !location.endTag) {
18
+ throw new IslandCompileError("A Fuzor island needs an explicit closing tag.");
19
+ }
20
+ const name = node.attrs.find((attribute) => attribute.name === "src")?.value;
21
+ if (!name)
22
+ throw new IslandCompileError("A Fuzor island needs a src attribute.");
23
+ const rawProps = node.attrs.find((attribute) => attribute.name === "props")?.value ?? "{}";
24
+ let props;
25
+ try {
26
+ const parsed = JSON.parse(rawProps);
27
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
28
+ throw new Error("props must be an object");
29
+ props = parsed;
30
+ }
31
+ catch (error) {
32
+ throw new IslandCompileError(`Invalid props for island ${name}: ${String(error)}`);
33
+ }
34
+ found.push({
35
+ name, props, id: `r${routeId}i${found.length}`,
36
+ start: location.startOffset, end: location.endOffset,
37
+ openEnd: location.startTag.endOffset, closeStart: location.endTag.startOffset
38
+ });
39
+ }
40
+ for (const child of node.childNodes)
41
+ visit(child, insideIsland || isIsland);
42
+ };
43
+ for (const node of fragment.childNodes)
44
+ visit(node);
45
+ return found;
46
+ }
47
+ /** Compiler phase that prerenders each known island into its route document. */
48
+ export function compileIslandsEffect(project, renderer) {
49
+ return Effect.gen(function* () {
50
+ const routes = yield* Effect.forEach(project.routes, (route, routeId) => Effect.gen(function* () {
51
+ const islands = yield* Effect.try({
52
+ try: () => locateIslands(route.html, routeId),
53
+ catch: (error) => error instanceof IslandCompileError ? error : new IslandCompileError(String(error))
54
+ });
55
+ let html = route.html;
56
+ const replacements = yield* Effect.forEach(islands, (island) => Effect.gen(function* () {
57
+ const preview = yield* Effect.tryPromise({
58
+ try: () => renderer(island.name, island.props, island.id),
59
+ catch: (error) => new IslandCompileError(`Cannot prerender ${island.name} in ${route.path}: ${String(error)}`)
60
+ });
61
+ if (preview === undefined)
62
+ return undefined;
63
+ const opening = route.html.slice(island.start, island.openEnd).replace(/>$/, ` data-fuzor-prerendered data-fuzor-island-id="${island.id}">`);
64
+ const closing = route.html.slice(island.closeStart, island.end);
65
+ return { start: island.start, end: island.end, html: opening + preview + closing };
66
+ }), { concurrency: 4 });
67
+ for (const replacement of replacements.filter((value) => value !== undefined).sort((a, b) => b.start - a.start)) {
68
+ html = html.slice(0, replacement.start) + replacement.html + html.slice(replacement.end);
69
+ }
70
+ return { ...route, html };
71
+ }), { concurrency: 4 });
72
+ return { ...project, routes };
73
+ });
74
+ }
75
+ export function compileIslands(project, renderer) {
76
+ return Effect.runPromise(compileIslandsEffect(project, renderer));
77
+ }
78
+ //# sourceMappingURL=islands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"islands.js","sourceRoot":"","sources":["../../src/compiler/islands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare function createApp(directory: string | undefined, options?: {
2
+ yes?: boolean;
3
+ install?: boolean;
4
+ }): Promise<string>;
5
+ export declare const createCommand: import("citty").CommandDef<{
6
+ readonly directory: {
7
+ readonly type: "positional";
8
+ readonly description: "Directory for the new app";
9
+ readonly required: false;
10
+ };
11
+ readonly yes: {
12
+ readonly type: "boolean";
13
+ readonly description: "Use defaults without prompting";
14
+ };
15
+ readonly install: {
16
+ readonly type: "boolean";
17
+ readonly description: "Install dependencies with pnpm";
18
+ };
19
+ }>;
20
+ export declare function runCreateCli(): void;
21
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AA2BA,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlI;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;EAQxB,CAAC;AAEH,wBAAgB,YAAY,IAAI,IAAI,CAEnC"}