Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions .github/workflows/www.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ jobs:
echo "url=$URL" >> "$GITHUB_OUTPUT"
echo "Preview will be served from $URL" >> "$GITHUB_STEP_SUMMARY"

- name: Smoke test
run: deno task smoke
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JSR_API: ${{ secrets.JSR_API }}
timeout-minutes: 5
working-directory: ./www

- name: Serve Website
run: |
deno run -A main.tsx &
Expand All @@ -68,13 +76,6 @@ jobs:
timeout-minutes: 5
working-directory: ./www

- name: Smoke test
run: deno task smoke
env:
SMOKE_URL: http://127.0.0.1:8000
timeout-minutes: 5
working-directory: ./www

- name: Download Staticalize
run: |
wget https://github.com/thefrontside/staticalize/releases/download/v0.3.1/staticalize-linux.tar.gz \
Expand Down Expand Up @@ -165,6 +166,14 @@ jobs:
with:
deno-version: v2.9.1

- name: Smoke test
run: deno task smoke
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JSR_API: ${{ secrets.JSR_API }}
timeout-minutes: 5
working-directory: ./www

- name: Serve Website
run: |
deno run -A main.tsx &
Expand All @@ -178,13 +187,6 @@ jobs:
timeout-minutes: 5
working-directory: ./www

- name: Smoke test
run: deno task smoke
env:
SMOKE_URL: http://127.0.0.1:8000
timeout-minutes: 5
working-directory: ./www

- name: Download Staticalize
run: |
wget https://github.com/thefrontside/staticalize/releases/download/v0.3.1/staticalize-linux.tar.gz \
Expand Down
5 changes: 3 additions & 2 deletions www/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"dev": "deno run -A @effectionx/watch deno run -A main.tsx",
"staticalize": "deno run -A npm:staticalize@0.3.1 --site http://localhost:8000 --output=built --base=http://localhost:8000",
"test": "deno test --allow-run --allow-write --allow-read --allow-env",
"smoke": "deno test --allow-net --allow-env tests/markdown-routes.ts"
"smoke": "deno test -A tests/markdown-routes.ts"
},
"lint": {
"exclude": [
Expand Down Expand Up @@ -51,6 +51,8 @@
"@types/hast": "npm:@types/hast@3.0.4",
"effection": "npm:effection@^3.6.1",
"@effectionx/context-api": "npm:@effectionx/context-api@^0.6.0",
"@effectionx/bdd": "jsr:@effectionx/bdd@^0.3.1",
"@effectionx/fetch": "npm:@effectionx/fetch@^0.2.1",
"@effectionx/deno-deploy": "jsr:@effectionx/deno-deploy@^0.3.1",
"@effectionx/process": "jsr:@effectionx/process@^0.6.2",
"hast": "npm:hast@^1.0.0",
Expand Down Expand Up @@ -87,7 +89,6 @@
"@std/fs": "jsr:@std/fs@1",
"@std/path": "jsr:@std/path@1",
"@std/yaml": "jsr:@std/yaml@1",
"@std/testing": "jsr:@std/testing@1",
"md5": "npm:md5@^2.3.0",
"expect": "jsr:@std/expect@^1",
"arktype": "npm:arktype@^2",
Expand Down
2 changes: 1 addition & 1 deletion www/hooks/use-markdown.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it } from "../testing.ts";
import { describe, it } from "@effectionx/bdd";
import { expect } from "expect";
import { createJsDocSanitizer, escapeMdxSyntax } from "./use-markdown.tsx";

Expand Down
2 changes: 1 addition & 1 deletion www/lib/command-parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it } from "../testing.ts";
import { describe, it } from "@effectionx/bdd";
import { expect } from "expect";
import { parseCommand, splitCommand } from "./command-parser.ts";

Expand Down
224 changes: 119 additions & 105 deletions www/main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { main, suspend } from "effection";
import { main, type Operation, resource, suspend } from "effection";
import { parse, printErrors, printHelp } from "@frontside/configliere";
import { createRevolution, ServerInfo } from "revolution";

Expand Down Expand Up @@ -65,113 +65,127 @@ if (import.meta.main) {
}
}

function* serve(options: Options) {
yield* verboseLogging(options.verbose);

let { current, series } = yield* useConfig();

// Get stable series (no prereleases) for guides
let stableSeries = series.filter((s) => !s.includePrerelease);

yield* initClones(options.clonesDir, {
checkouts: localCheckouts(options.effectionxDir),
});
yield* initWorktrees(options.worktreesDir);
yield* initGuides({
current,
worktrees: stableSeries
.filter((s) => s.name !== current)
.map((s) => s.name),
});

yield* initBlog();
yield* initFonts();
yield* initImageStore();

yield* initJSRClient(options.jsrApi);
yield* initFetch();

// configures Octokit client
yield* initOctokitContext(options.githubToken);

let revolution = createRevolution({
app: [
route("/", indexRoute()),
route("/search", searchRoute()),
route("/docs", redirectIndexRoute(firstPage(current))),
route("/docs/:id", redirectDocsRoute(current)),
// Guides only for stable series (no prereleases)
...stableSeries.map((s) =>
route(`/guides/${s.name}`, redirectIndexRoute(firstPage(s.name)))
),
// before the page route, so that `.md` is a suffix and not a guide id
route("/guides/:series/:id.md", guidesMarkdownRoute()),
route("/guides/:series/:id", guidesRoute({ search: true })),
route("/contrib", xIndexRedirect()),
route("/contrib/:workspacePath", xPackageRedirect()),
route("/x", xIndexRoute({ search: true })),
// before the page route, so that `.md` is a suffix and not a package
route("/x/:workspacePath.md", xPackageMarkdownRoute()),
route("/x/:workspacePath", xPackageRoute({ search: true })),
route("/api", apiIndexRoute({ search: true })),
// before the page routes, so that `.md` is a suffix and not a symbol
route("/api.md", apiIndexMarkdownRoute()),
...series.map((s) =>
route(`/api/${s.name}/:symbol.md`, apiSymbolMarkdownRoute(s.name))
),
...series.map((s) =>
route(
`/api/${s.name}/experimental/:symbol.md`,
apiSymbolMarkdownRoute(s.name, { entrypoint: "./experimental" }),
)
),
// API docs for all series including prereleases
...series.map((s) =>
route(
`/api/${s.name}/:symbol`,
apiReferenceRoute(s.name, { search: true }),
)
),
// Experimental API docs (namespaced; empty for series without the
// `./experimental` entrypoint)
...series.map((s) =>
/**
* The running site, as a resource: everything it needs is set up before it is
* provided, and the server shuts down when the enclosing scope exits.
*
* `main.tsx` keeps it running until the process ends; a test holds it for the
* length of a suite and lets its scope close.
*/
export function useSite(options: Options): Operation<ServerInfo> {
return resource(function* (provide) {
yield* verboseLogging(options.verbose);

let { current, series } = yield* useConfig();

// Get stable series (no prereleases) for guides
let stableSeries = series.filter((s) => !s.includePrerelease);

yield* initClones(options.clonesDir, {
checkouts: localCheckouts(options.effectionxDir),
});
yield* initWorktrees(options.worktreesDir);
yield* initGuides({
current,
worktrees: stableSeries
.filter((s) => s.name !== current)
.map((s) => s.name),
});

yield* initBlog();
yield* initFonts();
yield* initImageStore();

yield* initJSRClient(options.jsrApi);
yield* initFetch();

// configures Octokit client
yield* initOctokitContext(options.githubToken);

let revolution = createRevolution({
app: [
route("/", indexRoute()),
route("/search", searchRoute()),
route("/docs", redirectIndexRoute(firstPage(current))),
route("/docs/:id", redirectDocsRoute(current)),
// Guides only for stable series (no prereleases)
...stableSeries.map((s) =>
route(`/guides/${s.name}`, redirectIndexRoute(firstPage(s.name)))
),
// before the page route, so that `.md` is a suffix and not a guide id
route("/guides/:series/:id.md", guidesMarkdownRoute()),
route("/guides/:series/:id", guidesRoute({ search: true })),
route("/contrib", xIndexRedirect()),
route("/contrib/:workspacePath", xPackageRedirect()),
route("/x", xIndexRoute({ search: true })),
// before the page route, so that `.md` is a suffix and not a package
route("/x/:workspacePath.md", xPackageMarkdownRoute()),
route("/x/:workspacePath", xPackageRoute({ search: true })),
route("/api", apiIndexRoute({ search: true })),
// before the page routes, so that `.md` is a suffix and not a symbol
route("/api.md", apiIndexMarkdownRoute()),
...series.map((s) =>
route(`/api/${s.name}/:symbol.md`, apiSymbolMarkdownRoute(s.name))
),
...series.map((s) =>
route(
`/api/${s.name}/experimental/:symbol.md`,
apiSymbolMarkdownRoute(s.name, { entrypoint: "./experimental" }),
)
),
// API docs for all series including prereleases
...series.map((s) =>
route(
`/api/${s.name}/:symbol`,
apiReferenceRoute(s.name, { search: true }),
)
),
// Experimental API docs (namespaced; empty for series without the
// `./experimental` entrypoint)
...series.map((s) =>
route(
`/api/${s.name}/experimental/:symbol`,
apiReferenceRoute(s.name, {
search: true,
entrypoint: "./experimental",
}),
)
),
route("/blog", blogIndexRoute({ search: true })),
route("/blog/feed.xml", blogFeedRoute()),
route("/llms.txt", llmsTxtRoute()),
route("/AGENTS.md", agentsMdRoute()),
route("/blog/tags/:tag", blogTagRoute({ search: true })),
route("/blog/:id", blogPostRoute({ search: true })),
route("/blog/:id/:name.png", blogImageRoute()),
route("/blog{/*path}", assetsRoute("blog")),
route(
`/api/${s.name}/experimental/:symbol`,
apiReferenceRoute(s.name, {
search: true,
entrypoint: "./experimental",
}),
)
),
route("/blog", blogIndexRoute({ search: true })),
route("/blog/feed.xml", blogFeedRoute()),
route("/llms.txt", llmsTxtRoute()),
route("/AGENTS.md", agentsMdRoute()),
route("/blog/tags/:tag", blogTagRoute({ search: true })),
route("/blog/:id", blogPostRoute({ search: true })),
route("/blog/:id/:name.png", blogImageRoute()),
route("/blog{/*path}", assetsRoute("blog")),
route(
"/pagefind{/*path}",
pagefindRoute({ pagefindDir: options.pagefindDir }),
),
route("/assets/*path", assetsRoute("assets")),
],
plugins: [
yield* tailwindPlugin({
input: options.tailwindInput,
outdir: options.tailwindOutdir,
}),
inlineSvgPlugin({
basedir: new URL(".", import.meta.url).pathname,
}),
currentRequestPlugin(),
yield* etagPlugin({ deploymentId: options.denoDeploymentId }),
sitemapPlugin(),
],
"/pagefind{/*path}",
pagefindRoute({ pagefindDir: options.pagefindDir }),
),
route("/assets/*path", assetsRoute("assets")),
],
plugins: [
yield* tailwindPlugin({
input: options.tailwindInput,
outdir: options.tailwindOutdir,
}),
inlineSvgPlugin({
basedir: new URL(".", import.meta.url).pathname,
}),
currentRequestPlugin(),
yield* etagPlugin({ deploymentId: options.denoDeploymentId }),
sitemapPlugin(),
],
});

yield* provide(yield* revolution.start({ port: options.port }));
});
}

function* serve(options: Options) {
let server = yield* useSite(options);

let server = yield* revolution.start({ port: options.port });
console.log(`www -> ${urlFromServer(server)}`);

yield* suspend();
Expand Down
62 changes: 0 additions & 62 deletions www/testing.ts

This file was deleted.

Loading
Loading