Skip to content

omnibridge/static API reference

Floor
Bridge
Version
1.x
Verified for real
Verified in part
Licence
MIT
composer require omnibridge/static:1.x-dev

Read from the package's own PHP files at the commit 1ba157548bc3: its namespaces, classes, interfaces and enums, their public constants, properties and methods with their PHPDoc, and the options its factories take. Nothing of it is run.

Omnibridge\Static

  • Diagnostic class

    One thing the export found: an error fails the build (a page that did not render, two pages for one file, a link to nothing, a missing asset, a page rendered differently twice), a warning is to be read (a route left out, a page given twice), a notice says what the export did on purpose (a link left to the dynamic host).

    6 methods · 4 properties · 15 constants

  • Exporter class

    Exports a site to a folder: every page its providers give, rendered by its renderer, written as a file; the files of its asset manifests and the public files it names, copied; every internal link of the pages followed - to a page or file of the export, to a public file (copied), to a file the application serves (rendered and written), to the dynamic host (left, or rewritten to it) - and any other reported as broken; the redirections as small pages, _redirects and redirects.json; 404.html; sitemap.xml; and omnibridge-static.json, the report (files and checksums, pages, redirections, diagnostics).

    2 methods · 1 constant

  • Report class

    What an export wrote and found: the files (their path in the export, their SHA-256 and size), the pages and where each went, the redirections, the diagnostics. The same report is written as omnibridge-static.json in the export, without a date: two builds of the same application give the same file, so CI can compare them.

    7 methods · 5 properties

  • Site class

    What a site exports, declared once (the file the CLI reads returns it): the public address (an origin, or a folder of one: basePath()), the providers of its addresses, its renderer, its public folder and asset manifests, the page a static host shows for an unknown address, the addresses that stay on the dynamic host, and the normalisers that take out of a page what changes at every request.

    29 methods · 1 property

  • StaticPage class

    One address of the application to export: its path (an absolute URL path, no query string, no fragment), and what is known of it - the route and the parameters it was generated from, the action the route runs, its language and the same page in the other languages, whether the sitemap lists it.

    4 methods · 9 properties · 3 constants

  • StaticRendererInterface interface

    Renders one page at build time, by the application's own code: through its host's request handling (Render\RequestRenderer: Symfony's kernel, Laravel's), by calling the route's action itself (Render\ActionRenderer), or by any callable (Render\CallableRenderer, a plain PHP application).

    1 method

  • StaticResponse class

    What a page answered at build time: its status, its type, its body - or, for a redirection, where it sends. Nothing of the request's own (cookies, caching headers) is kept: a static host answers every visitor alike.

    13 methods · 5 properties · 1 constant

  • StaticRouteProviderInterface interface

    Where the addresses to export come from: an explicit list (Route\PageList), a router's routes with the values of their parameters (Route\RouteCollectionProvider), the application's own sitemap (Route\SitemapProvider), or the application's own class.

    1 method

Omnibridge\Static\Asset

  • AssetManifest class

    The files a front-end build produced, read from its manifest, whichever tool wrote it - the exporter copies them from the public folder, as the bundler fingerprinted them:

    2 methods

Omnibridge\Static\Console

  • Cli class

    The command line, plain PHP (bin/omnibridge-static), which the Symfony command and the artisan command of omnibridge/symfony and omnibridge/laravel call with their host:

    5 methods · 5 constants

Omnibridge\Static\Link

  • Links class

    The addresses a page or a style sheet refers to, and the rewriting of some of them: what the exporter follows to check that every internal link resolves within the export, to collect the files the pages need, and to send a visitor to the dynamic host for what cannot be static.

    5 methods · 4 constants

Omnibridge\Static\Output

  • BasePath class

    The folder of its origin a static site is served under ("/repository" on https://owner.github.io/repository/), and the moving of an export's internal addresses under it. The application renders its pages at the root of the origin; once they are written, every address that names the site is moved under the base path:

    9 methods · 2 properties · 4 constants

  • OutputPath class

    Where an address is written in the export, and the URL rules the exporter follows: "/" and "/blog/hello" are HTML pages written as index.html in their folder (a static host serves /blog/hello from blog/hello/index.html: nginx's try_files $uri $uri/index.html, the "pretty URLs" of the static hosts); a page whose path ends in .html, and any other file, are written at their path. Paths are percent-decoded: the file of /caf%C3%A9 is café/index.html, as a static host decodes the address before it looks.

    5 methods

Omnibridge\Static\Render

  • ActionRenderer class

    Renders a page by calling the action its route runs, with no host's request handling: the action taken from a PSR-11 container, called with the route's parameters by name (and `$query`, an empty query string), its other parameters taken from the container by their type, or left to their default; what it returns handed to $answer, the application's own way of turning an action's result into a page (omnibase's Base\Screen\Negotiation, a template engine...).

    2 methods

  • CallableRenderer class

    A renderer of any callable: a plain PHP application renders its pages its own way (its templates, its data) and answers a StaticResponse - or a string, an HTML page with status 200, or null, no such page (404).

    2 methods

  • RequestRenderer class

    Renders a page the way the host serves it: a GET request of its address handled in this process by the host's own request handling - the route matched, the same action run, the same templates rendered, the host's listeners on the way - with symfony/http-foundation's Request and Response, which Symfony's kernel and Laravel's both speak (a Laravel request extends it).

    2 methods · 1 constant

Omnibridge\Static\Route

  • PageList class

    The plainest provider: the addresses written out, as paths or as pages.

    2 methods

  • RouteCollectionProvider class

    The pages of a router's routes (symfony/routing's RouteCollection - what Symfony's router holds, what omnibridge/laravel's Routing\ActionRoutes reads from an application's #[Route] actions, what symfony/routing's attribute loader gives a plain PHP application).

    3 methods

  • SitemapProvider class

    The pages an application's own sitemap lists (sitemaps.org's urlset, its xhtml:link alternates): a site that already enumerates its addresses for the crawlers enumerates them for the export too. The sitemap is read from a file, or rendered at build time by the renderer (its path, "/sitemap.xml" by default). A sitemap index (sitemapindex) is followed, one level.

    3 methods

  • SkipReportingInterface interface

    A provider that leaves routes out says which and why (a route of a method other than GET, a parameter nobody gave values for...): the exporter lists them in its diagnostics, so that nothing is left out silently.

    1 method

Omnibridge\Static

Diagnostic class

final class Diagnostic implements JsonSerializable Diagnostic.php:12

One thing the export found: an error fails the build (a page that did not render, two pages for one file, a link to nothing, a missing asset, a page rendered differently twice), a warning is to be read (a route left out, a page given twice), a notice says what the export did on purpose (a link left to the dynamic host).

const ERROR = 'error'
const WARNING = 'warning'
const NOTICE = 'notice'
const RENDER_FAILED = 'render-failed'

A page answered an error status, or its rendering threw.

const DUPLICATE_OUTPUT = 'duplicate-output'

Two pages would be written to one file.

const DUPLICATE_PAGE = 'duplicate-page'

The same page was given twice (the first is kept).

An internal link resolves to nothing in the export.

const MISSING_ASSET = 'missing-asset'

A file of an asset manifest, or one to copy, is not in the public folder.

const NOT_DETERMINISTIC = 'not-deterministic'

A page rendered twice gave two different bodies.

const SKIPPED_ROUTE = 'skipped-route'

A provider left a route out.

const NOT_EXPORTABLE = 'not-exportable'

A page answered something a static file cannot be (no extension for a type other than HTML...).

const QUERY_IGNORED = 'query-ignored'

A link with a query string to an exported page: a static host answers the page whatever the query.

const DYNAMIC = 'dynamic'

A link left to the dynamic host (Site::dynamic()).

const OUTSIDE_BASE = 'outside-base'

An internal address of a written file that points outside the site's base path (Site::basePath()).

const GITHUB_PAGES = 'github-pages'

What GitHub Pages will not serve as the export expects (no 404 page, a file or a site above its limits).

public readonly string $level
public readonly string $code
public readonly string $subject
public readonly string $message

Diagnostic::__construct()

public function __construct(public readonly string $level, public readonly string $code, public readonly string $subject, public readonly string $message)

Diagnostic::error()

public static function error(string $code, string $subject, string $message): self

Diagnostic::warning()

public static function warning(string $code, string $subject, string $message): self

Diagnostic::notice()

public static function notice(string $code, string $subject, string $message): self

Diagnostic::__toString()

public function __toString(): string

Diagnostic::jsonSerialize()

public function jsonSerialize(): array

Exporter class

final class Exporter Exporter.php:37

Exports a site to a folder: every page its providers give, rendered by its renderer, written as a file; the files of its asset manifests and the public files it names, copied; every internal link of the pages followed - to a page or file of the export, to a public file (copied), to a file the application serves (rendered and written), to the dynamic host (left, or rewritten to it) - and any other reported as broken; the redirections as small pages, _redirects and redirects.json; 404.html; sitemap.xml; and omnibridge-static.json, the report (files and checksums, pages, redirections, diagnostics).

A site served under a folder of its origin (Site::basePath()) is rendered at the root and its written files' internal addresses are then moved under the folder (Output\BasePath); any left outside it is an error. For GitHub Pages (Site::githubPages()): .nojekyll, CNAME for a custom domain, the redirections as pages only.

$report = (new Exporter())->export($site, __DIR__.'/dist');
exit($report->hasErrors() ? 1 : 0);

The output is deterministic: pages are rendered in the order of their paths, nothing written carries a date, the report's lists are sorted. With $verify, every page is rendered twice and a page that differs is an error. The folder is emptied first, if it holds an earlier export (its omnibridge-static.json) or nothing.

const REPORT = 'omnibridge-static.json'

Exporter::__construct()

public function __construct(readonly ?\Closure $log = null)
$log

told of the progress, a line at a time

Exporter::export()

public function export(Site $site, string $outDir, bool $verify = false): Report

Report class

final class Report Report.php:12

What an export wrote and found: the files (their path in the export, their SHA-256 and size), the pages and where each went, the redirections, the diagnostics. The same report is written as omnibridge-static.json in the export, without a date: two builds of the same application give the same file, so CI can compare them.

public readonly string $baseUrl
public readonly array $files

path in the export => checksum and size, sorted

public readonly array $pages

page path => what was written, sorted

public readonly array $redirects

path => target, sorted

public readonly array $diagnostics

in the order they were found

Report::__construct()

public function __construct(public readonly string $baseUrl, public readonly array $files, public readonly array $pages, public readonly array $redirects, public readonly array $diagnostics)
$files

path in the export => checksum and size, sorted

$pages

page path => what was written, sorted

$redirects

path => target, sorted

$diagnostics

in the order they were found

Report::errors()

public function errors(): array

Report::warnings()

public function warnings(): array

Report::hasErrors()

public function hasErrors(): bool

Report::level()

public function level(string $level): array

Report::counts()

public function counts(): array
Returns

code => how many, sorted by code

Report::toJson()

public function toJson(): string

The report as omnibridge-static.json holds it: stable keys, no date.

Site class

final class Site Site.php:22

What a site exports, declared once (the file the CLI reads returns it): the public address (an origin, or a folder of one: basePath()), the providers of its addresses, its renderer, its public folder and asset manifests, the page a static host shows for an unknown address, the addresses that stay on the dynamic host, and the normalisers that take out of a page what changes at every request.

Asset\AssetManifest reads the manifests.

return (new Site('https://example.org')) ->provide(new PageList(['/', '/about'])) ->renderWith(new CallableRenderer(fn (StaticPage $page) => render($page->path))) ->publicDir(__DIR__.'/public') ->assets(__DIR__.'/public/build/manifest.json', '/build') ->copy('favicon.ico', 'robots.txt') ->notFound('/404');

public readonly string $baseUrl

the public address of the static site: its origin ("https://example.org"), or the folder of an origin it is served under ("https://owner.github.io/repository/") - the sitemap's addresses, the links taken for internal, and the base path every internal address of the export is moved under (Output\BasePath)

Site::__construct()

public function __construct(public readonly string $baseUrl)
$baseUrl

the public address of the static site: its origin ("https://example.org"), or the folder of an origin it is served under ("https://owner.github.io/repository/") - the sitemap's addresses, the links taken for internal, and the base path every internal address of the export is moved under (Output\BasePath)

Site::basePath()

public function basePath(): string

The folder of its origin the site is served under, without its trailing slash ("/repository"), or "" at the root. The application renders its pages at the root; the export moves every internal address under this folder (Output\BasePath).

Site::githubPages()

public function githubPages(bool $githubPages = true): self

Exported for GitHub Pages: .nojekyll written; a CNAME file when the base URL's host is a custom domain (not <owner>.github.io); the redirections as pages only (Pages reads no _redirects); 404.html expected; every internal address of the export checked to stay under the base path (an error otherwise); Pages' limits on a file's and the site's size warned of.

Site::isForGitHubPages()

public function isForGitHubPages(): bool

Site::customDomain()

public function customDomain(): ?string

The custom domain GitHub Pages serves the site at (its CNAME file), or null on <owner>.github.io.

Site::origin()

public function origin(): string

The scheme, host and port of the base URL ("https://example.org:8443").

Site::provide()

public function provide(StaticRouteProviderInterface ...$providers): self

Site::renderWith()

public function renderWith(StaticRendererInterface $renderer): self

Site::publicDir()

public function publicDir(string $publicDir): self

The application's public folder: the files the pages refer to are copied from it before any is rendered.

Site::assets()

public function assets(string $manifest, string $base = ''): self

A front-end build's manifest (Vite, Webpack, Encore's entrypoints.json): every file it names is copied from the public folder (Asset\AssetManifest).

$base

the public path a Vite manifest's files are relative to ("/build")

Site::copy()

public function copy(string ...$patterns): self

Public files copied as they are, by pattern relative to the public folder ("favicon.ico", "images/*").

Site::notFound()

public function notFound(string $path = '/404'): self

The address rendered for 404.html: one the application does not serve (its error page, status 404).

Site::dynamic()

public function dynamic(array $patterns, ?string $host = null): self

The addresses that cannot be static and stay on the dynamic host: a link or a form to one of them is not a broken link. Given the dynamic host's origin, their links and forms are rewritten to it.

$patterns

paths, fnmatch patterns ("/login", "/admin/*": "*" crosses slashes)

Site::normalise()

public function normalise(\Closure $normaliser): self

What changes from one request to the next taken out of each HTML page before it is written (a nonce, a token, a timing): the export stays the same from one build to the next.

Site::followResources()

public function followResources(bool $follow = true): self

Whether a file the pages refer to that is not in the public folder (a picture an application route serves) is rendered by the renderer and written too. On by default; off, it is a broken link.

Site::resourceAttributes()

public function resourceAttributes(string ...$attributes): self

More attributes that name a file the page's scripts load (a gallery's "data-thumb"): followed as a src is, beside the ones Link\Links knows.

Site::getResourceAttributes()

public function getResourceAttributes(): array

Site::sitemap()

public function sitemap(bool $sitemap = true): self

Whether sitemap.xml is written (on by default).

Site::providers()

public function providers(): array

Site::renderer()

public function renderer(): StaticRendererInterface

Site::getPublicDir()

public function getPublicDir(): ?string

Site::manifests()

public function manifests(): array
Returns

manifest file, base path

Site::copies()

public function copies(): array

Site::notFoundPage()

public function notFoundPage(): ?StaticPage

Site::dynamicHost()

public function dynamicHost(): ?string

Site::normalisers()

public function normalisers(): array

Site::followsResources()

public function followsResources(): bool

Site::writesSitemap()

public function writesSitemap(): bool

Site::isDynamic()

public function isDynamic(string $path): bool

StaticPage class

final class StaticPage StaticPage.php:15

One address of the application to export: its path (an absolute URL path, no query string, no fragment), and what is known of it - the route and the parameters it was generated from, the action the route runs, its language and the same page in the other languages, whether the sitemap lists it.

A provider (StaticRouteProviderInterface) gives the pages; a renderer (StaticRendererInterface) answers each with a StaticResponse; the exporter writes what comes back.

const PAGE = 'page'

An ordinary page.

const NOT_FOUND = 'not-found'

The page a static host shows for an address it does not have (written to 404.html, its status 404 expected).

const RESOURCE = 'resource'

A file the pages refer to (a picture, a style sheet...) found by following their links, written as it is.

public readonly string $path

the address' path, as the application serves it ("/", "/blog/hello")

public readonly ?string $route

the route it was generated from, for the diagnostics

public readonly array $parameters

the route's parameters it was generated with

public readonly ?string $action

the action the route runs ("Class" for an invokable one, "Class::method" otherwise)

public readonly ?string $locale

its language, as the application names it

public readonly array $alternates

the same page in other languages: language => path

public readonly array $headers

the request headers to render it with (Accept...), beside the renderer's own

public readonly bool $sitemap

whether sitemap.xml lists it

public readonly string $role

self::PAGE, self::NOT_FOUND or self::RESOURCE

StaticPage::__construct()

public function __construct(public readonly string $path, public readonly ?string $route = null, public readonly array $parameters = [], public readonly ?string $action = null, public readonly ?string $locale = null, public readonly array $alternates = [], public readonly array $headers = [], public readonly bool $sitemap = true, public readonly string $role = self::PAGE)
$path

the address' path, as the application serves it ("/", "/blog/hello")

$route

the route it was generated from, for the diagnostics

$parameters

the route's parameters it was generated with

$action

the action the route runs ("Class" for an invokable one, "Class::method" otherwise)

$locale

its language, as the application names it

$alternates

the same page in other languages: language => path

$headers

the request headers to render it with (Accept...), beside the renderer's own

$sitemap

whether sitemap.xml lists it

$role

self::PAGE, self::NOT_FOUND or self::RESOURCE

StaticPage::notFound()

public static function notFound(string $path = '/404'): self

The page a static host shows for an unknown address, rendered from an address the application does not serve.

StaticPage::withAlternates()

public function withAlternates(array $alternates): self

StaticPage::describe()

public function describe(): string

What the diagnostics call it: the path, and the route it comes from.

StaticRendererInterface interface

interface StaticRendererInterface StaticRendererInterface.php:14

Renders one page at build time, by the application's own code: through its host's request handling (Render\RequestRenderer: Symfony's kernel, Laravel's), by calling the route's action itself (Render\ActionRenderer), or by any callable (Render\CallableRenderer, a plain PHP application).

A renderer answers as a visitor does: no session, no cookie, nothing a signed-in visitor would see.

StaticRendererInterface::render()

public function render(StaticPage $page): StaticResponse

StaticResponse class

final class StaticResponse StaticResponse.php:10

What a page answered at build time: its status, its type, its body - or, for a redirection, where it sends. Nothing of the request's own (cookies, caching headers) is kept: a static host answers every visitor alike.

public readonly int $status

the HTTP status

public readonly string $body

the content, as it is to be written

public readonly ?string $contentType

the Content-Type header ("text/html; charset=UTF-8")

public readonly ?string $location

where a redirection sends (its Location header)

public readonly ?string $fragment

a redirection that carries the visitor's own #fragment over: the prefix it gains on the way ("" keeps it as it is; null drops it, as a meta refresh does)

const FRAGMENT_HEADER = 'X-Static-Fragment'

The header a host's response names the fragment's prefix with, for RequestRenderer: a page of a manual merged into one page answers Location: /docs/flowjs#sticky and X-Static-Fragment: sticky- - /docs/flowjs/sticky#keys then lands on /docs/flowjs#sticky-keys.

StaticResponse::__construct()

public function __construct(public readonly int $status, public readonly string $body = '', public readonly ?string $contentType = null, public readonly ?string $location = null, public readonly ?string $fragment = null)
$status

the HTTP status

$body

the content, as it is to be written

$contentType

the Content-Type header ("text/html; charset=UTF-8")

$location

where a redirection sends (its Location header)

$fragment

a redirection that carries the visitor's own #fragment over: the prefix it gains on the way ("" keeps it as it is; null drops it, as a meta refresh does)

StaticResponse::html()

public static function html(string $body, int $status = 200): self

StaticResponse::json()

public static function json(string $body, int $status = 200): self

StaticResponse::bytes()

public static function bytes(string $body, int $status = 200): self

A file served as application/octet-stream - what a static host answers for a path without a known extension -, for a reader that takes it so: npm's and Unity's registry clients read /<package> and /-/v1/search as JSON whatever the type (omnisense/omnihub's static hub).

Exported at its path, extension or not.

StaticResponse::isBytes()

public function isBytes(): bool

Whether it is served as bytes (application/octet-stream): exportable at a path without extension.

StaticResponse::redirect()

public static function redirect(string $location, int $status = 301, ?string $fragment = null): self
$fragment

the visitor's #fragment carried over with this prefix ("" as it is); null: dropped

StaticResponse::notFound()

public static function notFound(string $body = ''): self

StaticResponse::isSuccessful()

public function isSuccessful(): bool

StaticResponse::isRedirect()

public function isRedirect(): bool

StaticResponse::mediaType()

public function mediaType(): ?string

The media type alone, lower-cased ("text/html"), or null when none was given.

StaticResponse::isHtml()

public function isHtml(): bool

StaticResponse::isCss()

public function isCss(): bool

StaticResponse::withBody()

public function withBody(string $body): self

The same response with another body (a normaliser's, a rewritten link's).

StaticRouteProviderInterface interface

interface StaticRouteProviderInterface StaticRouteProviderInterface.php:14

Where the addresses to export come from: an explicit list (Route\PageList), a router's routes with the values of their parameters (Route\RouteCollectionProvider), the application's own sitemap (Route\SitemapProvider), or the application's own class.

The order the pages come in is kept in the diagnostics; the files written do not depend on it.

StaticRouteProviderInterface::pages()

public function pages(): iterable

Omnibridge\Static\Asset

AssetManifest class

final class AssetManifest AssetManifest.php:19

The files a front-end build produced, read from its manifest, whichever tool wrote it - the exporter copies them from the public folder, as the bundler fingerprinted them:

  • Vite's manifest.json (build.manifest): entries with "file", "css", "assets", relative to Vite's output folder - $base is that folder's public path ("/build");
  • Webpack's manifest.json (webpack-manifest-plugin, Symfony Encore's): logical name => public path ("build/app.js" => "/build/app.3f2a.js");
  • Encore's entrypoints.json: {"entrypoints": {"app": {"js": [...], "css": [...]}}}.

No bundler is required, none is run: a manifest is read, nothing else.

AssetManifest::read()

public static function read(string $file, string $base = ''): array

The public paths the manifest names, sorted, each once. An address on another host (a CDN) is not one of them.

$base

the public path a Vite manifest's files are relative to

AssetManifest::parse()

public static function parse(string $json, string $base = ''): array

Omnibridge\Static\Console

Cli class

final class Cli Cli.php:29

The command line, plain PHP (bin/omnibridge-static), which the Symfony command and the artisan command of omnibridge/symfony and omnibridge/laravel call with their host:

omnibridge-static build static.php [--out=dist] [--target=github-pages] [--verify] [--strict] [--quiet] omnibridge-static check dist

build: the site the file declares (it returns a Site, or a closure that takes the host's offer - Cli::HOST_* - and returns one) exported to --out; the exit code is 1 when there is an error (with --strict, a warning too). --target=github-pages exports for GitHub Pages (Site::githubPages()). check: an export's files against its omnibridge-static.json (each there, the same checksum, nothing more) and, for a site under a folder of its origin, no internal address outside that folder - what a deployment step runs before it publishes.

const HOST_RENDERER = 'renderer'

What a host hands the site's file: a renderer through its request handling.

const HOST_ROUTES = 'routes'

...its routes (a symfony/routing RouteCollection).

const HOST_CONTAINER = 'container'

...its container (PSR-11).

const HOST_PUBLIC_DIR = 'publicDir'

...its public folder.

const HOST_NAME = 'host'

...its name ("symfony", "laravel").

Cli::__construct()

public function __construct(readonly ?\Closure $out = null)
$out

where the lines go (STDERR by default)

Cli::load()

public static function load(string $file, array $host = []): Site

The site a file declares.

$host

what the host offers (Cli::HOST_*), empty from the plain command line

Cli::run()

public function run(array $arguments, array $host = []): int
$arguments

the command line's, without the script's name

$host

what the host offers (Cli::HOST_*)

Cli::build()

public function build(string $file, array $options, array $host = []): int

Cli::check()

public function check(string $folder): int

final class Links Links.php:20

The addresses a page or a style sheet refers to, and the rewriting of some of them: what the exporter follows to check that every internal link resolves within the export, to collect the files the pages need, and to send a visitor to the dynamic host for what cannot be static.

Read from the markup's tags (not from scripts nor comments): a link's href (PAGE), a form's action (FORM, or POST for a form posted; "" for a form without one, posted to the document's own address), a src, a srcset, a poster (and the data-src, data-srcset, data-poster of the lazy loaders), a <link>'s href, a url() of a style attribute or a <style>, an SVG's <use href> and <image href> (RESOURCE), a <meta http-equiv="refresh">'s address (PAGE); from a style sheet, its url() and @import. rewriteAddresses() and rewriteCss() rewrite the same addresses (Output\BasePath moves them under a site's base path).

const POST = 'post'

A form posted (method="post"): a static host takes no post.

public static function html(string $html, array $resources = []): array
$resources

more attributes that name a file a script loads (a gallery's "data-thumb")

Returns

[kind, address], in the order they come, each address as written (entities decoded)

public static function css(string $css): array
Returns

[kind, address]

public static function rewrite(string $html, \Closure $rewrite): string

The markup with the PAGE and FORM addresses $rewrite changes rewritten: it is given the address as written (a form without an action: "", the document's own address), the kind and the tag's attributes, and returns the new address, or null to leave it. Scripts and comments are left untouched.

public static function rewriteAddresses(string $html, \Closure $rewrite, array $resources = []): string

The markup with every address html() reads that $rewrite changes rewritten (with a script's src, a <style>'s url()s, each candidate of a srcset, a refresh's address): it is given the address as written (entities decoded) and its kind, and returns the new address or null to leave it. Scripts' bodies and comments are left untouched, and so is every attribute whose address does not change.

$resources

more attributes that name a file (Site::resourceAttributes())

public static function rewriteCss(string $css, \Closure $rewrite): string

A style sheet with the addresses of its url()s and @imports that $rewrite changes rewritten; its comments left untouched.

Omnibridge\Static\Output

BasePath class

final class BasePath BasePath.php:38

The folder of its origin a static site is served under ("/repository" on https://owner.github.io/repository/), and the moving of an export's internal addresses under it. The application renders its pages at the root of the origin; once they are written, every address that names the site is moved under the base path:

  • HTML: every address Link\Links reads that starts with "/" (a link, a form, a src, a srcset, a poster, a <link>, a style's url(), a refresh, the attributes Site::resourceAttributes() adds) gets the base path; in a page that may be served at another address than its own (404.html, served at any depth; on GitHub Pages, every page, which /a/b redirects to /a/b/) a relative address is resolved against the address it was rendered at first.
  • CSS: its url()s and @imports.
  • JSON (and .webmanifest): a string value that is the root-relative address of a page or file of the export ("/guides/start").
  • Everywhere (HTML, CSS, JSON, XML feeds, sitemaps, robots.txt, SVG): an absolute URL of the origin ("https://owner.github.io/x", as written, in JSON's escaped form, or percent-encoded in a share link's query), the canonical and hreflang links among them.

An address already under the base path is left as it is: an application that knows its base path (a bundler's public path) writes them so. Not read: what a script builds at run time (fetch("/api")) - a script reads its addresses from the page (a data- attribute named by Site::resourceAttributes(), document.baseURI) to be moved with it.

escapes() lists the addresses of a written file that still point outside the base path: the exporter's check, and the command line's.

const HTML = 'html'
const CSS = 'css'
const JSON = 'json'
const TEXT = 'text'
public readonly string $origin

the site's scheme, host and port ("https://owner.github.io")

public readonly string $path

the folder, without its trailing slash ("/repository"), or "" at the root

BasePath::__construct()

public function __construct(public readonly string $origin, public readonly string $path)
$origin

the site's scheme, host and port ("https://owner.github.io")

$path

the folder, without its trailing slash ("/repository"), or "" at the root

BasePath::isRoot()

public function isRoot(): bool

BasePath::contains()

public function contains(string $path): bool

Whether an address' path is the base path or under it ("/repository", "/repository/x?y").

BasePath::strip()

public function strip(string $path): string

An address under the base path as the application serves it ("/repository/x" => "/x").

BasePath::prefix()

public function prefix(string $path): string

A root-relative address moved under the base path ("/x" => "/repository/x"), unless it is already.

BasePath::kind()

public static function kind(string $file): ?string

What a file of the export is, by its extension: self::HTML, CSS, JSON, TEXT, or null (a script, a picture...).

BasePath::apply()

public function apply(string $kind, string $body, \Closure $exported, ?string $resolveFrom = null, array $resources = []): string

A written file with its internal addresses moved under the base path.

$kind

self::kind() of the file

$exported

whether a root-relative path names a page or file of the export (for JSON)

$resolveFrom

the address a relative address is resolved against first (404.html: the address it was rendered at)

$resources

Site::resourceAttributes()

BasePath::escapes()

public function escapes(string $kind, string $body, \Closure $exported, array $resources = []): array

The addresses of a written file that point outside the base path: root-relative addresses (and, in JSON, the root-relative addresses of the export's pages and files) and absolute URLs of the origin.

Returns

each once, in the order they come

BasePath::describe()

public function describe(array $escapes): string

What escapes() found, in a line.

OutputPath class

final class OutputPath OutputPath.php:14

Where an address is written in the export, and the URL rules the exporter follows: "/" and "/blog/hello" are HTML pages written as index.html in their folder (a static host serves /blog/hello from blog/hello/index.html: nginx's try_files $uri $uri/index.html, the "pretty URLs" of the static hosts); a page whose path ends in .html, and any other file, are written at their path. Paths are percent-decoded: the file of /caf%C3%A9 is café/index.html, as a static host decodes the address before it looks.

OutputPath::page()

public static function page(string $path): string

The file an HTML page is written to, relative to the export ("blog/hello/index.html").

OutputPath::file()

public static function file(string $path): string

The file any other address is written to, relative to the export ("build/app.css").

OutputPath::hasExtension()

public static function hasExtension(string $path): bool

Whether the last segment of a path has an extension (".css", ".json").

OutputPath::key()

public static function key(string $path): string

An address' path as the exporter compares it: percent-decoded, without its trailing slash ("/" stays "/").

OutputPath::resolve()

public static function resolve(string $base, string $reference): string

A reference resolved against the address of the document it is in (RFC 3986's merge and dot segments): the path and query of the address it names.

Omnibridge\Static\Render

ActionRenderer class

final class ActionRenderer implements StaticRendererInterface ActionRenderer.php:31

Renders a page by calling the action its route runs, with no host's request handling: the action taken from a PSR-11 container, called with the route's parameters by name (and $query, an empty query string), its other parameters taken from the container by their type, or left to their default; what it returns handed to $answer, the application's own way of turning an action's result into a page (omnibase's Base\Screen\Negotiation, a template engine...).

new ActionRenderer($container, function (mixed $result, StaticPage $page) use ($negotiation): StaticResponse { $answer = $negotiation->answer($result, new Visit($page->path, 'text/html', null, null));

    return new StaticResponse($answer->status, $answer->body, $answer->headers['Content-Type'] ?? 'text/html; charset=UTF-8');
});

The page names its action (StaticPage::$action, which RouteCollectionProvider fills from the route's _controller). An action that returns null is no such page (404). What a host adds around an action - its layout listeners, its request-scoped state - is not there: the action's result alone is rendered. RequestRenderer renders the page as the host serves it.

ActionRenderer::__construct()

public function __construct(readonly ContainerInterface $container, readonly \Closure $answer)

ActionRenderer::render()

public function render(StaticPage $page): StaticResponse

CallableRenderer class

final class CallableRenderer implements StaticRendererInterface CallableRenderer.php:16

A renderer of any callable: a plain PHP application renders its pages its own way (its templates, its data) and answers a StaticResponse - or a string, an HTML page with status 200, or null, no such page (404).

new CallableRenderer(fn (StaticPage $page) => $twig->render('page.html.twig', ['path' => $page->path]));

CallableRenderer::__construct()

public function __construct(readonly \Closure $render)

CallableRenderer::render()

public function render(StaticPage $page): StaticResponse

RequestRenderer class

final class RequestRenderer implements StaticRendererInterface RequestRenderer.php:30

Renders a page the way the host serves it: a GET request of its address handled in this process by the host's own request handling - the route matched, the same action run, the same templates rendered, the host's listeners on the way - with symfony/http-foundation's Request and Response, which Symfony's kernel and Laravel's both speak (a Laravel request extends it).

// Symfony new RequestRenderer(fn (Request $request) => $kernel->handle($request), 'https://example.org'); // Laravel new RequestRenderer(fn (Request $request) => $app->make(Kernel::class)->handle(\Illuminate\Http\Request::createFromBase($request)), 'https://example.org');

The request carries no cookie and no session: the page is rendered for a visitor. The host's terminate step is not run (a host that counts a page view there counts none for the export).

const USER_AGENT = 'omnibridge-static'

RequestRenderer::__construct()

public function __construct(readonly \Closure $handle, readonly string $baseUrl, readonly array $headers = [])
$handle

the host's handling of one request

$baseUrl

the public origin the pages are rendered for ("https://example.org"): the host, scheme and port the application sees

$headers

the headers every request carries (Accept-Language...), beside a page's own

RequestRenderer::render()

public function render(StaticPage $page): StaticResponse

Omnibridge\Static\Route

PageList class

final class PageList implements StaticRouteProviderInterface PageList.php:13

The plainest provider: the addresses written out, as paths or as pages.

new PageList(['/', '/about', '/blog/hello']);

PageList::__construct()

public function __construct(readonly iterable|\Closure $pages)

PageList::pages()

public function pages(): iterable

RouteCollectionProvider class

final class RouteCollectionProvider implements StaticRouteProviderInterface, SkipReportingInterface RouteCollectionProvider.php:38

The pages of a router's routes (symfony/routing's RouteCollection - what Symfony's router holds, what omnibridge/laravel's Routing\ActionRoutes reads from an application's #[Route] actions, what symfony/routing's attribute loader gives a plain PHP application).

A route without a variable is one page. A route with variables is exported for the values a source gives, by the route's name (or, for a localized route such as "blog.fr", by its canonical name "blog"); without one it is left out and said so (skipped()): a parameter has no values the exporter could guess.

new RouteCollectionProvider($router->getRouteCollection(),
    parameters: ['article' => fn () => [['slug' => 'hello'], ['slug' => 'world']]],
    include: ['app_*'],
    exclude: ['app_*_comments'],
);

Only the routes that answer GET are read. A localized route's language is the page's locale, and the same parameters under the route's other languages its alternates (sitemap.xml lists them). The path is generated by symfony/routing's UrlGenerator: requirements are checked, a parameter the path does not name is not added as a query string.

RouteCollectionProvider::__construct()

public function __construct(readonly RouteCollection $routes, readonly array $parameters = [], readonly ?array $include = null, readonly array $exclude = [], readonly array $actions = [], readonly array $noSitemap = [])
$parameters

route name (or canonical name) => the parameter sets

$include

the routes to read, by name (fnmatch patterns); null for all

$exclude

the routes to leave out, by name (fnmatch patterns)

$actions

the actions to read, by class prefix ("App\Action\"); empty for all

$noSitemap

the routes whose pages sitemap.xml does not list (fnmatch patterns)

RouteCollectionProvider::pages()

public function pages(): iterable

RouteCollectionProvider::skipped()

public function skipped(): array

SitemapProvider class

final class SitemapProvider implements StaticRouteProviderInterface, SkipReportingInterface SitemapProvider.php:22

The pages an application's own sitemap lists (sitemaps.org's urlset, its xhtml:link alternates): a site that already enumerates its addresses for the crawlers enumerates them for the export too. The sitemap is read from a file, or rendered at build time by the renderer (its path, "/sitemap.xml" by default). A sitemap index (sitemapindex) is followed, one level.

new SitemapProvider(renderer: $renderer); new SitemapProvider(file: 'public/sitemap.xml');

An address with a query string, or on another host than the sitemap's first, is left out and said so (skipped()).

SitemapProvider::__construct()

public function __construct(readonly ?StaticRendererInterface $renderer = null, readonly string $path = '/sitemap.xml', readonly ?string $file = null)

SitemapProvider::pages()

public function pages(): iterable

SitemapProvider::skipped()

public function skipped(): array

SkipReportingInterface interface

interface SkipReportingInterface SkipReportingInterface.php:11

A provider that leaves routes out says which and why (a route of a method other than GET, a parameter nobody gave values for...): the exporter lists them in its diagnostics, so that nothing is left out silently.

SkipReportingInterface::skipped()

public function skipped(): array

What the last pages() left out.

Returns

subject (a route's name) => why