Merge pull request #10 from avalon-vanguard/develop
Link the live docs site
This commit is contained in:
@@ -25,9 +25,10 @@ const user = fromJsonSync(User, body); // a real User
|
|||||||
user.greet(); // your methods are still there
|
user.greet(); // your methods are still there
|
||||||
```
|
```
|
||||||
|
|
||||||
`docs/index.html` is a self-contained page with an interactive playground that runs this
|
**[avalon-vanguard.github.io/cereale](https://avalon-vanguard.github.io/cereale/)** — an
|
||||||
library in the browser. Build its assets with `npm run build:docs` and open the file — it
|
interactive playground that runs this library in your browser, the full decorator reference,
|
||||||
loads nothing from the network.
|
and the toolchain matrix. The page is self-contained and loads nothing from the network; it is
|
||||||
|
served from `docs/` on `main`, and `npm run build:docs` rebuilds its assets to open locally.
|
||||||
|
|
||||||
## Where it fits
|
## Where it fits
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,20 @@
|
|||||||
<title>cereale — validated domain objects, not validated data</title>
|
<title>cereale — validated domain objects, not validated data</title>
|
||||||
<meta name="description" content="Zero-dependency JSON mapping and validation for TypeScript classes. Maps JSON onto your own classes and checks the validation rules against the fields they are attached to, at compile time.">
|
<meta name="description" content="Zero-dependency JSON mapping and validation for TypeScript classes. Maps JSON onto your own classes and checks the validation rules against the fields they are attached to, at compile time.">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
|
<link rel="canonical" href="https://avalon-vanguard.github.io/cereale/">
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🌾</text></svg>">
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🌾</text></svg>">
|
||||||
|
|
||||||
|
<!-- Link previews. No og:image: a preview card with a broken image is worse than one
|
||||||
|
without, and there is no artwork to point at yet. -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://avalon-vanguard.github.io/cereale/">
|
||||||
|
<meta property="og:site_name" content="cereale">
|
||||||
|
<meta property="og:title" content="cereale — validated domain objects, not validated data">
|
||||||
|
<meta property="og:description" content="Zero-dependency JSON mapping and validation for TypeScript classes. Maps JSON onto your own classes and checks every rule against the field it is attached to, at compile time.">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta name="twitter:title" content="cereale — validated domain objects, not validated data">
|
||||||
|
<meta name="twitter:description" content="Zero-dependency JSON mapping and validation for TypeScript classes. Rules are checked against fields at compile time.">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* ---------------------------------------------------------------- tokens */
|
/* ---------------------------------------------------------------- tokens */
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/avalon-vanguard/cereale/issues"
|
"url": "https://github.com/avalon-vanguard/cereale/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/avalon-vanguard/cereale#readme",
|
"homepage": "https://avalon-vanguard.github.io/cereale/",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/standalone": "^8.0.4",
|
"@babel/standalone": "^8.0.4",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
|
|||||||
+21
-1
@@ -22,12 +22,23 @@ const failures = [];
|
|||||||
/** Subresource references — the things a browser fetches without being clicked. */
|
/** Subresource references — the things a browser fetches without being clicked. */
|
||||||
const SUBRESOURCES = [
|
const SUBRESOURCES = [
|
||||||
[/<script\b[^>]*\bsrc\s*=\s*["']([^"']+)["']/gi, 'script src'],
|
[/<script\b[^>]*\bsrc\s*=\s*["']([^"']+)["']/gi, 'script src'],
|
||||||
[/<link\b[^>]*\bhref\s*=\s*["']([^"']+)["']/gi, 'link href'],
|
|
||||||
[/<(?:img|iframe|video|audio|source|embed)\b[^>]*\bsrc\s*=\s*["']([^"']+)["']/gi, 'media src'],
|
[/<(?:img|iframe|video|audio|source|embed)\b[^>]*\bsrc\s*=\s*["']([^"']+)["']/gi, 'media src'],
|
||||||
[/@import\s+(?:url\()?["']([^"']+)["']/gi, 'css @import'],
|
[/@import\s+(?:url\()?["']([^"']+)["']/gi, 'css @import'],
|
||||||
[/url\(\s*["']?(https?:\/\/[^)"']+)/gi, 'css url()'],
|
[/url\(\s*["']?(https?:\/\/[^)"']+)/gi, 'css url()'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `<link>` relations the browser actually fetches or connects to.
|
||||||
|
*
|
||||||
|
* Checked against `rel` rather than flagging every `<link href>`, because the metadata
|
||||||
|
* relations — `canonical` above all — are declarations about the document, not requests. A
|
||||||
|
* check that cannot tell the difference gets switched off the first time it is wrong.
|
||||||
|
*/
|
||||||
|
const FETCHING_REL = new Set([
|
||||||
|
'stylesheet', 'icon', 'shortcut icon', 'apple-touch-icon', 'apple-touch-icon-precomposed',
|
||||||
|
'manifest', 'preload', 'modulepreload', 'prefetch', 'prerender', 'preconnect', 'dns-prefetch',
|
||||||
|
]);
|
||||||
|
|
||||||
const isRemote = (url) => /^(?:https?:)?\/\//i.test(url);
|
const isRemote = (url) => /^(?:https?:)?\/\//i.test(url);
|
||||||
|
|
||||||
const html = (await readdir(docs)).filter((name) => name.endsWith('.html'));
|
const html = (await readdir(docs)).filter((name) => name.endsWith('.html'));
|
||||||
@@ -40,6 +51,15 @@ for (const name of html) {
|
|||||||
if (isRemote(match[1])) failures.push(`docs/${name}: remote ${kind} — ${match[1]}`);
|
if (isRemote(match[1])) failures.push(`docs/${name}: remote ${kind} — ${match[1]}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const match of source.matchAll(/<link\b([^>]*)>/gi)) {
|
||||||
|
const attrs = match[1];
|
||||||
|
const rel = (/\brel\s*=\s*["']([^"']+)["']/i.exec(attrs)?.[1] ?? '').trim().toLowerCase();
|
||||||
|
const href = /\bhref\s*=\s*["']([^"']+)["']/i.exec(attrs)?.[1];
|
||||||
|
if (href && isRemote(href) && FETCHING_REL.has(rel)) {
|
||||||
|
failures.push(`docs/${name}: remote link rel="${rel}" — ${href}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
// A fetch to a CDN would not be caught by the markup scan.
|
// A fetch to a CDN would not be caught by the markup scan.
|
||||||
for (const match of source.matchAll(/\b(?:fetch|importScripts)\(\s*["'`](https?:\/\/[^"'`]+)/gi)) {
|
for (const match of source.matchAll(/\b(?:fetch|importScripts)\(\s*["'`](https?:\/\/[^"'`]+)/gi)) {
|
||||||
failures.push(`docs/${name}: remote fetch — ${match[1]}`);
|
failures.push(`docs/${name}: remote fetch — ${match[1]}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user