@haverstack/eleventy 0.2.0
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.
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/assets.d.ts +52 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +148 -0
- package/dist/assets.js.map +1 -0
- package/dist/check.d.ts +35 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +141 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +122 -0
- package/dist/cli.js.map +1 -0
- package/dist/emit.d.ts +72 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +147 -0
- package/dist/emit.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/feeds.d.ts +24 -0
- package/dist/feeds.d.ts.map +1 -0
- package/dist/feeds.js +103 -0
- package/dist/feeds.js.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +86 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +258 -0
- package/dist/load.js.map +1 -0
- package/dist/markdown.d.ts +23 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +81 -0
- package/dist/markdown.js.map +1 -0
- package/dist/publish.d.ts +45 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +79 -0
- package/dist/publish.js.map +1 -0
- package/dist/resolve.d.ts +119 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +411 -0
- package/dist/resolve.js.map +1 -0
- package/dist/scaffold.d.ts +22 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +98 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/templates.d.ts +34 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +171 -0
- package/dist/templates.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +123 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @haverstack/eleventy — `eject`
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* Writes a starter `haverstack-base` layout into the site's `_includes`
|
|
5
|
+
* so the whole build can flow through an editable Eleventy layout. The
|
|
6
|
+
* build never writes here — ejecting is a deliberate one-off.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
10
|
+
import { join, resolve as resolvePath } from 'node:path';
|
|
11
|
+
const HAVERSTACK_BASE = `{#
|
|
12
|
+
haverstack-base — a starting point, generated by \`haverstack-eleventy eject\`.
|
|
13
|
+
Turn it on with \`templates: { base: 'haverstack-base' }\` in the plugin
|
|
14
|
+
options, then edit it however you like.
|
|
15
|
+
|
|
16
|
+
Data on every page: content, title, record, meta, url, canonical, body
|
|
17
|
+
(rendered HTML), bodyRaw (markdown, image links resolved), and on listing
|
|
18
|
+
pages, collection. Globals: haverstack.site / .sites / .owner / .pages /
|
|
19
|
+
.menus / .collections.
|
|
20
|
+
#}
|
|
21
|
+
<!doctype html>
|
|
22
|
+
<html lang="en">
|
|
23
|
+
<head>
|
|
24
|
+
<meta charset="utf-8" />
|
|
25
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
26
|
+
<title>{% if title %}{{ title }} · {% endif %}{{ haverstack.site.content.title }}</title>
|
|
27
|
+
{% if haverstack.site.content.description %}
|
|
28
|
+
<meta name="description" content="{{ haverstack.site.content.description }}" />
|
|
29
|
+
{% endif %}
|
|
30
|
+
{% if canonical %}<link rel="canonical" href="{{ canonical }}" />{% endif %}
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<header>
|
|
34
|
+
<a href="/">{{ haverstack.site.content.title }}</a>
|
|
35
|
+
{%- set topNav = haverstack.menus["top-nav"] %}
|
|
36
|
+
{%- if topNav %}
|
|
37
|
+
<nav>
|
|
38
|
+
{%- for item in topNav.items %}
|
|
39
|
+
<a href="{{ item.url }}"{% if item.rel %} rel="{{ item.rel }}"{% endif %}>{{ item.label }}</a>
|
|
40
|
+
{%- endfor %}
|
|
41
|
+
</nav>
|
|
42
|
+
{%- endif %}
|
|
43
|
+
</header>
|
|
44
|
+
|
|
45
|
+
<main>
|
|
46
|
+
{{ content | safe }}
|
|
47
|
+
{%- if collection %}
|
|
48
|
+
<ul>
|
|
49
|
+
{%- for m in collection.members %}
|
|
50
|
+
<li>
|
|
51
|
+
<a href="{{ m.url }}">{{ m.record.content.title or m.record.content.caption or m.record.id }}</a>
|
|
52
|
+
</li>
|
|
53
|
+
{%- endfor %}
|
|
54
|
+
</ul>
|
|
55
|
+
{%- endif %}
|
|
56
|
+
</main>
|
|
57
|
+
|
|
58
|
+
<footer>
|
|
59
|
+
{%- set social = haverstack.menus.social %}
|
|
60
|
+
{%- if social %}{% for item in social.items %}<a href="{{ item.url }}" rel="{{ item.rel }}">{{ item.label }}</a> {% endfor %}{% endif %}
|
|
61
|
+
{%- if haverstack.owner %}<p>© {{ haverstack.owner.content.name }}</p>{% endif %}
|
|
62
|
+
</footer>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
65
|
+
`;
|
|
66
|
+
export const EJECTABLE_TEMPLATES = [
|
|
67
|
+
{ filename: 'haverstack-base.njk', contents: HAVERSTACK_BASE },
|
|
68
|
+
];
|
|
69
|
+
/** Write each ejectable template into `includesDir`, skipping existing files unless `force`. */
|
|
70
|
+
export async function runEject(includesDir, opts = {}) {
|
|
71
|
+
const dir = resolvePath(process.cwd(), includesDir);
|
|
72
|
+
await mkdir(dir, { recursive: true });
|
|
73
|
+
const written = [];
|
|
74
|
+
const skipped = [];
|
|
75
|
+
for (const template of EJECTABLE_TEMPLATES) {
|
|
76
|
+
const dest = join(dir, template.filename);
|
|
77
|
+
if (existsSync(dest) && !opts.force) {
|
|
78
|
+
skipped.push(template.filename);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
await writeFile(dest, template.contents);
|
|
82
|
+
written.push(template.filename);
|
|
83
|
+
}
|
|
84
|
+
return { written, skipped };
|
|
85
|
+
}
|
|
86
|
+
export function formatEjectResult(result, includesDir) {
|
|
87
|
+
const lines = [];
|
|
88
|
+
for (const name of result.written)
|
|
89
|
+
lines.push(` wrote ${includesDir}/${name}`);
|
|
90
|
+
for (const name of result.skipped)
|
|
91
|
+
lines.push(` skipped ${includesDir}/${name} (exists — pass --force to overwrite)`);
|
|
92
|
+
if (result.written.length > 0) {
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push("Set `templates: { base: 'haverstack-base' }` in the plugin options to use it.");
|
|
95
|
+
}
|
|
96
|
+
return lines.join('\n');
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAOzD,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDvB,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAwB;IACtD,EAAE,QAAQ,EAAE,qBAAqB,EAAE,QAAQ,EAAE,eAAe,EAAE;CAC/D,CAAC;AAOF,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,WAAmB,EACnB,OAA4B,EAAE;IAE9B,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,mBAAmB,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAChC,SAAS;QACX,CAAC;QACD,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAmB,EAAE,WAAmB;IACxE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,IAAI,IAAI,EAAE,CAAC,CAAC;IACnF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO;QAC/B,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,IAAI,IAAI,uCAAuC,CAAC,CAAC;IACvF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @haverstack/eleventy — built-in templates
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* A minimal default set so a stack builds a legible site with no template
|
|
5
|
+
* work. They render complete HTML documents; a site that brings its own
|
|
6
|
+
* templates replaces them (see the plugin's `templates` option). Kept
|
|
7
|
+
* deliberately small and lightly styled — hard-to-override defaults are
|
|
8
|
+
* worse than none.
|
|
9
|
+
*/
|
|
10
|
+
import type { RecordId } from '@haverstack/core';
|
|
11
|
+
import type { AssetPlan } from './assets.js';
|
|
12
|
+
import type { FeedSpec } from './feeds.js';
|
|
13
|
+
import type { ResolvedMember, ResolvedPage, ResolvedSite } from './resolve.js';
|
|
14
|
+
export interface RenderContext {
|
|
15
|
+
resolved: ResolvedSite;
|
|
16
|
+
assets: AssetPlan;
|
|
17
|
+
feeds: FeedSpec[];
|
|
18
|
+
/** recordId → rendered body HTML, for every built page and member. */
|
|
19
|
+
bodyByRecord: Map<RecordId, string>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The inner content for a page when its `template` is mapped to a site
|
|
23
|
+
* layout: the page's own rendered body, no chrome and no member list. A
|
|
24
|
+
* listing layout builds its list from the `collection` in page data; this
|
|
25
|
+
* is just the intro. `content`/`home` get the `<article>` wrapper.
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderPageFragment(page: ResolvedPage, ctx: RenderContext): string;
|
|
28
|
+
/** Inner content for a member — the `<article>` / `<figure>` markup, no chrome. */
|
|
29
|
+
export declare function renderMemberFragment(member: ResolvedMember, ctx: RenderContext): string;
|
|
30
|
+
/** A complete HTML document for a page, using the built-in chrome. */
|
|
31
|
+
export declare function renderPage(page: ResolvedPage, ctx: RenderContext): string;
|
|
32
|
+
/** A complete HTML document for a member, using the built-in chrome. */
|
|
33
|
+
export declare function renderMember(member: ResolvedMember, ctx: RenderContext): string;
|
|
34
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,kBAAkB,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAgB,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAwF7F,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,sEAAsE;IACtE,YAAY,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;CACrC;AA2DD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAKjF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAEvF;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAazE;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAQ/E"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @haverstack/eleventy — built-in templates
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* A minimal default set so a stack builds a legible site with no template
|
|
5
|
+
* work. They render complete HTML documents; a site that brings its own
|
|
6
|
+
* templates replaces them (see the plugin's `templates` option). Kept
|
|
7
|
+
* deliberately small and lightly styled — hard-to-override defaults are
|
|
8
|
+
* worse than none.
|
|
9
|
+
*/
|
|
10
|
+
import { PHOTO } from '@haverstack/commons';
|
|
11
|
+
const baseId = (typeId) => typeId.split('@')[0];
|
|
12
|
+
const esc = (s) => String(s ?? '')
|
|
13
|
+
.replace(/&/g, '&')
|
|
14
|
+
.replace(/</g, '<')
|
|
15
|
+
.replace(/>/g, '>')
|
|
16
|
+
.replace(/"/g, '"');
|
|
17
|
+
const CSS = `
|
|
18
|
+
:root{--fg:#1a1a1a;--muted:#666;--accent:#0b5;--bg:#fff}
|
|
19
|
+
@media(prefers-color-scheme:dark){:root{--fg:#e8e8e8;--muted:#999;--accent:#3d9;--bg:#161616}}
|
|
20
|
+
*{box-sizing:border-box}
|
|
21
|
+
body{color:var(--fg);background:var(--bg);font:16px/1.6 system-ui,sans-serif;margin:0}
|
|
22
|
+
.wrap{max-width:42rem;margin:0 auto;padding:2rem 1rem}
|
|
23
|
+
header.site{display:flex;gap:1rem;align-items:baseline;flex-wrap:wrap;border-bottom:1px solid #8884;padding-bottom:1rem;margin-bottom:2rem}
|
|
24
|
+
header.site .title{font-weight:700;text-decoration:none;color:inherit}
|
|
25
|
+
nav a{margin-right:.75rem;color:var(--muted);text-decoration:none}
|
|
26
|
+
nav a:hover{color:var(--accent)}
|
|
27
|
+
main :is(h1,h2){line-height:1.25}
|
|
28
|
+
time{color:var(--muted);font-size:.9rem}
|
|
29
|
+
ul.listing{list-style:none;padding:0}
|
|
30
|
+
ul.listing li{margin:.75rem 0}
|
|
31
|
+
ul.listing a{font-weight:600;text-decoration:none;color:inherit}
|
|
32
|
+
ul.listing a:hover{color:var(--accent)}
|
|
33
|
+
img{max-width:100%;height:auto}
|
|
34
|
+
pre{overflow-x:auto;padding:1rem;background:#8881;border-radius:6px}
|
|
35
|
+
footer.site{border-top:1px solid #8884;margin-top:3rem;padding-top:1rem;color:var(--muted);font-size:.9rem}
|
|
36
|
+
`.trim();
|
|
37
|
+
function menuHtml(menu) {
|
|
38
|
+
if (!menu || menu.items.length === 0)
|
|
39
|
+
return '';
|
|
40
|
+
const links = menu.items
|
|
41
|
+
.map((item) => `<a href="${esc(item.url)}"${item.rel ? ` rel="${esc(item.rel)}"` : ''}>${esc(item.label)}</a>`)
|
|
42
|
+
.join('');
|
|
43
|
+
return `<nav aria-label="${esc(menu.handle)}">${links}</nav>`;
|
|
44
|
+
}
|
|
45
|
+
function documentShell(opts) {
|
|
46
|
+
const { resolved } = opts;
|
|
47
|
+
const siteTitle = resolved.site ? String(resolved.site.content.title ?? '') : '';
|
|
48
|
+
const description = resolved.site?.content.description;
|
|
49
|
+
const baseUrl = String(resolved.site?.content.baseUrl ?? '').replace(/\/+$/, '');
|
|
50
|
+
const fullTitle = [opts.title, siteTitle].filter(Boolean).join(' · ') || 'Site';
|
|
51
|
+
const feedLinks = opts.feeds
|
|
52
|
+
.map((f) => `<link rel="alternate" type="application/atom+xml" title="${esc(f.title)}" href="${esc(baseUrl + f.path)}">`)
|
|
53
|
+
.join('');
|
|
54
|
+
return (`<!doctype html>\n<html lang="en">\n<head>\n` +
|
|
55
|
+
`<meta charset="utf-8">\n<meta name="viewport" content="width=device-width, initial-scale=1">\n` +
|
|
56
|
+
`<title>${esc(fullTitle)}</title>\n` +
|
|
57
|
+
(typeof description === 'string' && description
|
|
58
|
+
? `<meta name="description" content="${esc(description)}">\n`
|
|
59
|
+
: '') +
|
|
60
|
+
(opts.canonical ? `<link rel="canonical" href="${esc(opts.canonical)}">\n` : '') +
|
|
61
|
+
`${feedLinks}\n<style>${CSS}</style>\n</head>\n<body>\n<div class="wrap">\n` +
|
|
62
|
+
`<header class="site"><a class="title" href="/">${esc(siteTitle || 'Home')}</a>${menuHtml(resolved.menus.get('top-nav'))}</header>\n` +
|
|
63
|
+
`<main>\n${opts.main}\n</main>\n` +
|
|
64
|
+
`<footer class="site">${menuHtml(resolved.menus.get('social'))}` +
|
|
65
|
+
(resolved.owner?.content.name ? `<p>© ${esc(resolved.owner.content.name)}</p>` : '') +
|
|
66
|
+
`</footer>\n</div>\n</body>\n</html>\n`);
|
|
67
|
+
}
|
|
68
|
+
function publishedTime(record) {
|
|
69
|
+
const publishedAt = record.content.publishedAt;
|
|
70
|
+
if (typeof publishedAt !== 'string')
|
|
71
|
+
return '';
|
|
72
|
+
const date = new Date(publishedAt);
|
|
73
|
+
if (Number.isNaN(date.getTime()))
|
|
74
|
+
return '';
|
|
75
|
+
return `<time datetime="${esc(publishedAt)}">${date.toISOString().slice(0, 10)}</time>`;
|
|
76
|
+
}
|
|
77
|
+
function contentMain(title, body) {
|
|
78
|
+
const heading = title ? `<h1>${esc(title)}</h1>\n` : '';
|
|
79
|
+
return `<article>\n${heading}${body}\n</article>`;
|
|
80
|
+
}
|
|
81
|
+
function listingMain(page, body, ctx) {
|
|
82
|
+
const collection = ctx.resolved.collections.get(String(page.record.content.slug));
|
|
83
|
+
const items = (collection?.members ?? [])
|
|
84
|
+
.map((m) => {
|
|
85
|
+
const label = esc(m.record.content.title ?? m.record.content.caption ?? m.record.id);
|
|
86
|
+
return `<li><a href="${esc(m.url)}">${label}</a> ${publishedTime(m.record)}</li>`;
|
|
87
|
+
})
|
|
88
|
+
.join('\n');
|
|
89
|
+
return `<article>\n${body}\n<ul class="listing">\n${items}\n</ul>\n</article>`;
|
|
90
|
+
}
|
|
91
|
+
function listingInlineMain(page, body, ctx) {
|
|
92
|
+
const collection = ctx.resolved.collections.get(String(page.record.content.slug));
|
|
93
|
+
const entries = (collection?.members ?? [])
|
|
94
|
+
.map((m) => {
|
|
95
|
+
const title = m.record.content.title;
|
|
96
|
+
const heading = title ? `<h2><a href="${esc(m.url)}">${esc(title)}</a></h2>\n` : '';
|
|
97
|
+
return `<article>\n${heading}${publishedTime(m.record)}\n${ctx.bodyByRecord.get(m.record.id) ?? ''}\n</article>`;
|
|
98
|
+
})
|
|
99
|
+
.join('\n');
|
|
100
|
+
return `<div class="intro">\n${body}\n</div>\n${entries}`;
|
|
101
|
+
}
|
|
102
|
+
function memberMain(member, body, ctx) {
|
|
103
|
+
const record = member.record;
|
|
104
|
+
if (baseId(record.typeId) === baseId(PHOTO.id)) {
|
|
105
|
+
const staged = ctx.assets.files.get(String(record.content.image));
|
|
106
|
+
const img = staged
|
|
107
|
+
? `<img src="${esc(staged.assetPath)}" alt="${esc(record.content.alt ?? '')}">`
|
|
108
|
+
: '';
|
|
109
|
+
const caption = record.content.caption
|
|
110
|
+
? `<figcaption>${esc(record.content.caption)}</figcaption>`
|
|
111
|
+
: '';
|
|
112
|
+
return `<figure>\n${img}\n${caption}\n</figure>\n${body}`;
|
|
113
|
+
}
|
|
114
|
+
const title = record.content.title;
|
|
115
|
+
const linkOut = typeof record.content.url === 'string' && !member.canonical
|
|
116
|
+
? ''
|
|
117
|
+
: member.canonical
|
|
118
|
+
? `<p><a href="${esc(member.canonical)}">Originally published elsewhere ↗</a></p>`
|
|
119
|
+
: '';
|
|
120
|
+
const heading = typeof record.content.url === 'string' && title && !member.canonical
|
|
121
|
+
? `<h1><a href="${esc(record.content.url)}">${esc(title)}</a></h1>\n`
|
|
122
|
+
: title
|
|
123
|
+
? `<h1>${esc(title)}</h1>\n`
|
|
124
|
+
: '';
|
|
125
|
+
return `<article>\n${heading}${publishedTime(record)}\n${body}\n${linkOut}\n</article>`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The inner content for a page when its `template` is mapped to a site
|
|
129
|
+
* layout: the page's own rendered body, no chrome and no member list. A
|
|
130
|
+
* listing layout builds its list from the `collection` in page data; this
|
|
131
|
+
* is just the intro. `content`/`home` get the `<article>` wrapper.
|
|
132
|
+
*/
|
|
133
|
+
export function renderPageFragment(page, ctx) {
|
|
134
|
+
const body = ctx.bodyByRecord.get(page.record.id) ?? '';
|
|
135
|
+
if (page.template === 'listing' || page.template === 'listing-inline')
|
|
136
|
+
return body;
|
|
137
|
+
// The home page's body usually carries its own hero heading; don't double it.
|
|
138
|
+
return contentMain(page.template === 'home' ? undefined : page.record.content.title, body);
|
|
139
|
+
}
|
|
140
|
+
/** Inner content for a member — the `<article>` / `<figure>` markup, no chrome. */
|
|
141
|
+
export function renderMemberFragment(member, ctx) {
|
|
142
|
+
return memberMain(member, ctx.bodyByRecord.get(member.record.id) ?? '', ctx);
|
|
143
|
+
}
|
|
144
|
+
/** A complete HTML document for a page, using the built-in chrome. */
|
|
145
|
+
export function renderPage(page, ctx) {
|
|
146
|
+
const body = ctx.bodyByRecord.get(page.record.id) ?? '';
|
|
147
|
+
let main;
|
|
148
|
+
if (page.template === 'listing')
|
|
149
|
+
main = listingMain(page, body, ctx);
|
|
150
|
+
else if (page.template === 'listing-inline')
|
|
151
|
+
main = listingInlineMain(page, body, ctx);
|
|
152
|
+
else
|
|
153
|
+
main = contentMain(page.template === 'home' ? undefined : page.record.content.title, body);
|
|
154
|
+
return documentShell({
|
|
155
|
+
title: String(page.record.content.title ?? ''),
|
|
156
|
+
resolved: ctx.resolved,
|
|
157
|
+
feeds: ctx.feeds,
|
|
158
|
+
main,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** A complete HTML document for a member, using the built-in chrome. */
|
|
162
|
+
export function renderMember(member, ctx) {
|
|
163
|
+
return documentShell({
|
|
164
|
+
title: String(member.record.content.title ?? member.record.content.caption ?? ''),
|
|
165
|
+
resolved: ctx.resolved,
|
|
166
|
+
feeds: ctx.feeds,
|
|
167
|
+
canonical: member.canonical,
|
|
168
|
+
main: renderMemberFragment(member, ctx),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @haverstack/eleventy — type registration
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* The record types this integration reads and the two sidecar types it
|
|
5
|
+
* owns, plus `defineEleventyTypes()` to register the whole set on a stack.
|
|
6
|
+
*
|
|
7
|
+
* Consumed commons types are registered exactly as `@haverstack/commons`
|
|
8
|
+
* defines them. The sidecars — `page-meta` and `menu` — are this package's
|
|
9
|
+
* own, minted under `org.haverstack.eleventy`: a first-party namespace
|
|
10
|
+
* under the same authority as the commons, but not a commons type and not
|
|
11
|
+
* under commons governance. See docs/design.md § Types.
|
|
12
|
+
*/
|
|
13
|
+
import { Stack, type TypeId, type TypeSchema } from '@haverstack/core';
|
|
14
|
+
/** Reverse-DNS namespace for the sidecar types this package owns. */
|
|
15
|
+
export declare const ELEVENTY_NAMESPACE = "org.haverstack.eleventy";
|
|
16
|
+
/**
|
|
17
|
+
* Association label that scopes a `page-meta` sidecar to one site. This
|
|
18
|
+
* package's own label, deliberately distinct from the commons `site`
|
|
19
|
+
* membership convention below: a sidecar carrying `for-site` is published
|
|
20
|
+
* nowhere — it is metadata that applies when that site builds. See
|
|
21
|
+
* docs/design.md § Sidecars are scoped, and they cascade.
|
|
22
|
+
*/
|
|
23
|
+
export declare const FOR_SITE_LABEL = "for-site";
|
|
24
|
+
/**
|
|
25
|
+
* Commons cross-type convention: an `article`, `post`, `photo` or
|
|
26
|
+
* `bookmark` carrying this relationship is published on that site.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SITE_MEMBERSHIP_LABEL = "site";
|
|
29
|
+
/** Commons cross-type convention for body-embedded media. */
|
|
30
|
+
export declare const EMBED_LABEL = "embed";
|
|
31
|
+
/** A registrable type: an id, a display name, and a content schema. */
|
|
32
|
+
export interface EleventyType {
|
|
33
|
+
readonly id: TypeId;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly schema: TypeSchema;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `org.haverstack.eleventy/page-meta@1` — generator metadata about a record
|
|
39
|
+
* it does not own, linked to that record by `parentId`. Every field is
|
|
40
|
+
* optional: a page-meta record exists only when it has something to say.
|
|
41
|
+
* See docs/design.md § Types.
|
|
42
|
+
*/
|
|
43
|
+
export declare const PAGE_META: EleventyType;
|
|
44
|
+
/**
|
|
45
|
+
* `org.haverstack.eleventy/menu@1` — a named, ordered navigation menu
|
|
46
|
+
* belonging to one site (`parentId` = the site). Items live in the content
|
|
47
|
+
* array rather than as separate records because menus are small and edited
|
|
48
|
+
* as a unit. See docs/design.md § Types.
|
|
49
|
+
*/
|
|
50
|
+
export declare const MENU: EleventyType;
|
|
51
|
+
/**
|
|
52
|
+
* Content shape of a `page-meta@1` record. `slug` overrides a listing
|
|
53
|
+
* member's derived permalink; `template` names a template in the building
|
|
54
|
+
* site's own vocabulary; `order` is a reserved curated-position field, not
|
|
55
|
+
* read until curated collections land; `hidden` keeps the record out of
|
|
56
|
+
* this site's indexes while still building it; `draft` keeps it from being
|
|
57
|
+
* built at all on this site.
|
|
58
|
+
*/
|
|
59
|
+
export interface PageMeta {
|
|
60
|
+
slug?: string;
|
|
61
|
+
template?: string;
|
|
62
|
+
order?: number;
|
|
63
|
+
hidden?: boolean;
|
|
64
|
+
draft?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** One item in a `menu@1`. An item sets `url` or `recordId`, never both. */
|
|
67
|
+
export interface MenuItem {
|
|
68
|
+
label: string;
|
|
69
|
+
order: number;
|
|
70
|
+
url?: string;
|
|
71
|
+
recordId?: string;
|
|
72
|
+
rel?: string;
|
|
73
|
+
}
|
|
74
|
+
/** Content shape of a `menu@1` record. */
|
|
75
|
+
export interface Menu {
|
|
76
|
+
handle: string;
|
|
77
|
+
label?: string;
|
|
78
|
+
items: MenuItem[];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The commons publishing types this integration reads. `_entity@1` and
|
|
82
|
+
* `_attachment@1` are also read but are system types every stack already
|
|
83
|
+
* seeds, so they need no registration here.
|
|
84
|
+
*/
|
|
85
|
+
export declare const CONSUMED_COMMONS_TYPES: readonly EleventyType[];
|
|
86
|
+
/** The sidecar types this package owns. */
|
|
87
|
+
export declare const ELEVENTY_TYPES: readonly EleventyType[];
|
|
88
|
+
/**
|
|
89
|
+
* Register every type the integration reads or owns. Idempotent — an
|
|
90
|
+
* identical schema is a no-op that leaves `createdAt` untouched — so
|
|
91
|
+
* calling it every build is cheap. Safe to run under a non-owner
|
|
92
|
+
* credential: types that already exist are left alone and a permission
|
|
93
|
+
* error on an already-registered type is swallowed.
|
|
94
|
+
*/
|
|
95
|
+
export declare function defineEleventyTypes(stack: Stack): Promise<void>;
|
|
96
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,EAAwB,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG7F,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAE5C,6DAA6D;AAC7D,eAAO,MAAM,WAAW,UAAU,CAAC;AAEnC,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,YAUvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,YAoBlB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,0CAA0C;AAC1C,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,YAAY,EAOzD,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAAsB,CAAC;AAqBzE;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrE"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @haverstack/eleventy — type registration
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* The record types this integration reads and the two sidecar types it
|
|
5
|
+
* owns, plus `defineEleventyTypes()` to register the whole set on a stack.
|
|
6
|
+
*
|
|
7
|
+
* Consumed commons types are registered exactly as `@haverstack/commons`
|
|
8
|
+
* defines them. The sidecars — `page-meta` and `menu` — are this package's
|
|
9
|
+
* own, minted under `org.haverstack.eleventy`: a first-party namespace
|
|
10
|
+
* under the same authority as the commons, but not a commons type and not
|
|
11
|
+
* under commons governance. See docs/design.md § Types.
|
|
12
|
+
*/
|
|
13
|
+
import { Stack, StackPermissionError } from '@haverstack/core';
|
|
14
|
+
import { ARTICLE, BOOKMARK, PAGE, PHOTO, POST, SITE } from '@haverstack/commons';
|
|
15
|
+
/** Reverse-DNS namespace for the sidecar types this package owns. */
|
|
16
|
+
export const ELEVENTY_NAMESPACE = 'org.haverstack.eleventy';
|
|
17
|
+
/**
|
|
18
|
+
* Association label that scopes a `page-meta` sidecar to one site. This
|
|
19
|
+
* package's own label, deliberately distinct from the commons `site`
|
|
20
|
+
* membership convention below: a sidecar carrying `for-site` is published
|
|
21
|
+
* nowhere — it is metadata that applies when that site builds. See
|
|
22
|
+
* docs/design.md § Sidecars are scoped, and they cascade.
|
|
23
|
+
*/
|
|
24
|
+
export const FOR_SITE_LABEL = 'for-site';
|
|
25
|
+
/**
|
|
26
|
+
* Commons cross-type convention: an `article`, `post`, `photo` or
|
|
27
|
+
* `bookmark` carrying this relationship is published on that site.
|
|
28
|
+
*/
|
|
29
|
+
export const SITE_MEMBERSHIP_LABEL = 'site';
|
|
30
|
+
/** Commons cross-type convention for body-embedded media. */
|
|
31
|
+
export const EMBED_LABEL = 'embed';
|
|
32
|
+
/**
|
|
33
|
+
* `org.haverstack.eleventy/page-meta@1` — generator metadata about a record
|
|
34
|
+
* it does not own, linked to that record by `parentId`. Every field is
|
|
35
|
+
* optional: a page-meta record exists only when it has something to say.
|
|
36
|
+
* See docs/design.md § Types.
|
|
37
|
+
*/
|
|
38
|
+
export const PAGE_META = {
|
|
39
|
+
id: `${ELEVENTY_NAMESPACE}/page-meta@1`,
|
|
40
|
+
name: 'Page Metadata',
|
|
41
|
+
schema: {
|
|
42
|
+
slug: { kind: 'string' },
|
|
43
|
+
template: { kind: 'string' },
|
|
44
|
+
order: { kind: 'number' },
|
|
45
|
+
hidden: { kind: 'boolean' },
|
|
46
|
+
draft: { kind: 'boolean' },
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* `org.haverstack.eleventy/menu@1` — a named, ordered navigation menu
|
|
51
|
+
* belonging to one site (`parentId` = the site). Items live in the content
|
|
52
|
+
* array rather than as separate records because menus are small and edited
|
|
53
|
+
* as a unit. See docs/design.md § Types.
|
|
54
|
+
*/
|
|
55
|
+
export const MENU = {
|
|
56
|
+
id: `${ELEVENTY_NAMESPACE}/menu@1`,
|
|
57
|
+
name: 'Menu',
|
|
58
|
+
schema: {
|
|
59
|
+
handle: { kind: 'string', required: true },
|
|
60
|
+
label: { kind: 'string' },
|
|
61
|
+
items: {
|
|
62
|
+
kind: 'array',
|
|
63
|
+
items: {
|
|
64
|
+
kind: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
label: { kind: 'string', required: true },
|
|
67
|
+
order: { kind: 'number', required: true },
|
|
68
|
+
url: { kind: 'string' },
|
|
69
|
+
recordId: { kind: 'record-ref' },
|
|
70
|
+
rel: { kind: 'string' },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The commons publishing types this integration reads. `_entity@1` and
|
|
78
|
+
* `_attachment@1` are also read but are system types every stack already
|
|
79
|
+
* seeds, so they need no registration here.
|
|
80
|
+
*/
|
|
81
|
+
export const CONSUMED_COMMONS_TYPES = [
|
|
82
|
+
SITE,
|
|
83
|
+
PAGE,
|
|
84
|
+
ARTICLE,
|
|
85
|
+
POST,
|
|
86
|
+
PHOTO,
|
|
87
|
+
BOOKMARK,
|
|
88
|
+
];
|
|
89
|
+
/** The sidecar types this package owns. */
|
|
90
|
+
export const ELEVENTY_TYPES = [PAGE_META, MENU];
|
|
91
|
+
/**
|
|
92
|
+
* Register one type, tolerating a scoped credential that cannot define
|
|
93
|
+
* types: a non-owner build is legitimate as long as whoever populated the
|
|
94
|
+
* stack already registered it. A genuine schema conflict
|
|
95
|
+
* (`StackSchemaDriftError`) still propagates — that is a real error.
|
|
96
|
+
*/
|
|
97
|
+
async function ensureType(stack, type) {
|
|
98
|
+
try {
|
|
99
|
+
await stack.defineType(type.id, type.name, type.schema);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err instanceof StackPermissionError) {
|
|
103
|
+
const existing = await stack.getType(type.id);
|
|
104
|
+
if (!existing)
|
|
105
|
+
throw err;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Register every type the integration reads or owns. Idempotent — an
|
|
113
|
+
* identical schema is a no-op that leaves `createdAt` untouched — so
|
|
114
|
+
* calling it every build is cheap. Safe to run under a non-owner
|
|
115
|
+
* credential: types that already exist are left alone and a permission
|
|
116
|
+
* error on an already-registered type is swallowed.
|
|
117
|
+
*/
|
|
118
|
+
export async function defineEleventyTypes(stack) {
|
|
119
|
+
for (const type of [...CONSUMED_COMMONS_TYPES, ...ELEVENTY_TYPES]) {
|
|
120
|
+
await ensureType(stack, type);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@haverstack/eleventy",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Eleventy plugin that builds a static site from a Haverstack stack — records are the content source, no content files on disk",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
},
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"bin": {
|
|
16
|
+
"haverstack-eleventy": "./dist/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=22"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/haverstack/eleventy.git"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"haverstack",
|
|
31
|
+
"eleventy",
|
|
32
|
+
"11ty",
|
|
33
|
+
"static site generator",
|
|
34
|
+
"personal data",
|
|
35
|
+
"records"
|
|
36
|
+
],
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@11ty/eleventy": ">=3.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@haverstack/commons": "^0.20.0",
|
|
42
|
+
"@haverstack/core": "^0.26.0",
|
|
43
|
+
"markdown-it": "^15.0.1",
|
|
44
|
+
"sanitize-html": "^2.17.7"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@11ty/eleventy": "^3.1.6",
|
|
48
|
+
"@changesets/changelog-github": "^1.0.1",
|
|
49
|
+
"@changesets/cli": "^3.0.2",
|
|
50
|
+
"@eslint/js": "^10.0.1",
|
|
51
|
+
"@types/markdown-it": "^14.2.0",
|
|
52
|
+
"@types/node": "^22.0.0",
|
|
53
|
+
"@types/sanitize-html": "^2.16.1",
|
|
54
|
+
"eslint": "^10.2.1",
|
|
55
|
+
"eslint-config-prettier": "^10.1.8",
|
|
56
|
+
"prettier": "^3.8.3",
|
|
57
|
+
"typescript": "^5.5.0",
|
|
58
|
+
"typescript-eslint": "^8.59.1",
|
|
59
|
+
"vitest": "^2.0.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsc -p tsconfig.build.json",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"typecheck": "tsc --noEmit",
|
|
65
|
+
"lint": "eslint src tests",
|
|
66
|
+
"format": "prettier --write .",
|
|
67
|
+
"format:check": "prettier --check .",
|
|
68
|
+
"changeset": "changeset",
|
|
69
|
+
"version-packages": "changeset version && pnpm run format",
|
|
70
|
+
"release": "pnpm run build && changeset publish"
|
|
71
|
+
}
|
|
72
|
+
}
|