summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Fred K. Schott <fkschott@gmail.com> 2021-03-21 00:44:42 -0700
committerGravatar Fred K. Schott <fkschott@gmail.com> 2021-03-21 00:44:42 -0700
commit417657f138fbc5e194df3dd511e3b9c8e53920fd (patch)
treec15f73c625d3c222304557f4f753204c65304607
parent2082001ff8702ec48072b59caafe85573a3b2891 (diff)
downloadastro-417657f138fbc5e194df3dd511e3b9c8e53920fd.tar.gz
astro-417657f138fbc5e194df3dd511e3b9c8e53920fd.tar.zst
astro-417657f138fbc5e194df3dd511e3b9c8e53920fd.zip
lots of improvements
-rw-r--r--examples/snowpack/astro/components/Banner.hmx20
-rw-r--r--examples/snowpack/astro/components/Hero.hmx23
-rw-r--r--examples/snowpack/astro/components/Menu.hmx2
-rw-r--r--examples/snowpack/astro/components/Nav.hmx113
-rw-r--r--examples/snowpack/astro/components/Subnav.hmx26
-rw-r--r--examples/snowpack/astro/layouts/base.hmx52
-rw-r--r--examples/snowpack/astro/layouts/content-with-cover.hmx24
-rw-r--r--examples/snowpack/astro/layouts/content.hmx35
-rw-r--r--examples/snowpack/astro/layouts/main.hmx18
-rw-r--r--examples/snowpack/astro/layouts/post.hmx18
-rw-r--r--examples/snowpack/astro/pages/404.hmx13
-rw-r--r--examples/snowpack/astro/pages/guides.hmx67
-rw-r--r--examples/snowpack/astro/pages/index.hmx25
-rw-r--r--examples/snowpack/astro/pages/news.hmx34
-rw-r--r--examples/snowpack/astro/pages/plugins.hmx31
-rw-r--r--examples/snowpack/astro/pages/proof-of-concept-dynamic/[slug].hmx6
-rw-r--r--package-lock.json21
-rw-r--r--package.json2
-rw-r--r--snowpack-plugin.cjs50
-rw-r--r--src/@types/astro.ts3
-rw-r--r--src/codegen/index.ts64
-rw-r--r--src/compiler/interfaces.ts36
-rw-r--r--src/compiler/parse/index.ts33
-rw-r--r--src/compiler/parse/read/script.ts13
-rw-r--r--src/compiler/parse/state/tag.ts42
-rw-r--r--src/generate.ts1
-rw-r--r--src/markdown-encode.ts32
-rw-r--r--src/micromark-collect-headers.ts35
-rw-r--r--src/runtime.ts9
-rw-r--r--src/transform2.ts130
-rw-r--r--test/fixtures/hmx-basic/astro/pages/index.hmx10
31 files changed, 513 insertions, 475 deletions
diff --git a/examples/snowpack/astro/components/Banner.hmx b/examples/snowpack/astro/components/Banner.hmx
index 233eedb3f..8879bf939 100644
--- a/examples/snowpack/astro/components/Banner.hmx
+++ b/examples/snowpack/astro/components/Banner.hmx
@@ -1,12 +1,10 @@
-<Component>
- <section class="grid-banner">
- <div class="notification">
- <div class="container">
- Snowpack 3.0 is out now!
- <a href="/posts/2021-01-13-snowpack-3-0">
- Read the announcement post →
- </a>
- </div>
+<section class="grid-banner">
+ <div class="notification">
+ <div class="container">
+ Snowpack 3.0 is out now!
+ <a href="/posts/2021-01-13-snowpack-3-0">
+ Read the announcement post →
+ </a>
</div>
- </section>
-</Component> \ No newline at end of file
+ </div>
+</section> \ No newline at end of file
diff --git a/examples/snowpack/astro/components/Hero.hmx b/examples/snowpack/astro/components/Hero.hmx
index e3dabe87a..d77f48573 100644
--- a/examples/snowpack/astro/components/Hero.hmx
+++ b/examples/snowpack/astro/components/Hero.hmx
@@ -1,5 +1,4 @@
-<Component>
- <div class="hero">
+<div class="hero">
<div class="section">
<h1 class="header-snowpack">Snowpack</h1>
<p class="header-snowpack-subtitle">The faster frontend build tool.</p>
@@ -7,11 +6,15 @@
<div class="hero-cta">
<a href="/tutorials/quick-start" class="button button-primary">Get started</a>
<div style="margin: 0.5rem"></div>
- <button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack">
+ <button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack">
<span class="faded" style="margin-right: 0.75rem;">$</span>
<span id="copy-button-text">npm install snowpack</span>
- <svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false" data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
- <path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path>
+ <svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false"
+ data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img"
+ xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
+ <path fill="currentColor"
+ d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z">
+ </path>
</svg>
</button>
<script type="module">
@@ -19,10 +22,10 @@
const clippy = new Clipboard('.copy-button');
const copyText = document.getElementById('copy-button').innerHTML;
clippy.on('success', function (e) {
- document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth;
+ document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth;
console.info('Trigger:', e);
document.getElementById('copy-button').innerHTML = '<span>copied to clipboard!</span>';
- document.getElementById('copy-button').addEventListener("mouseleave", function( event ) {
+ document.getElementById('copy-button').addEventListener("mouseleave", function (event) {
document.getElementById('copy-button').innerHTML = copyText;
}, false);
@@ -39,9 +42,9 @@
<div class="hero-cta">
<!-- Place this tag where you want the button to render. -->
<div class="hidden-mobile" style="text-align: center; height: 36px;">
- <a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a >
+ <a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star"
+ data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a>
</div>
</div>
</div>
-</div>
-</Component>
+</div> \ No newline at end of file
diff --git a/examples/snowpack/astro/components/Menu.hmx b/examples/snowpack/astro/components/Menu.hmx
index b1bc38a77..f94e28ee2 100644
--- a/examples/snowpack/astro/components/Menu.hmx
+++ b/examples/snowpack/astro/components/Menu.hmx
@@ -1,4 +1,3 @@
-<Component>
<nav class="snow-toc">
<ol class="snow-toc-contents">
<li class="snow-toc-section">
@@ -83,4 +82,3 @@
</li>
</ol>
</nav>
-</Component>
diff --git a/examples/snowpack/astro/components/Nav.hmx b/examples/snowpack/astro/components/Nav.hmx
index 3d3ed1ac1..4a463634c 100644
--- a/examples/snowpack/astro/components/Nav.hmx
+++ b/examples/snowpack/astro/components/Nav.hmx
@@ -1,21 +1,27 @@
-<Component>
<nav class="snow-nav">
- <button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false" aria-controls="nav-primary">
+ <button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false"
+ aria-controls="nav-primary">
<svg focusable="false" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 448 512">
<title>Toggle mobile menu</title>
- <path d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"></path>
+ <path
+ d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z">
+ </path>
</svg>
</button>
<a class="snow-nav-logo snow-logo" href="/">
- <svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(-1.000000, 0.000000)" fill-rule="nonzero">
- <path d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z" id="Shape"></path>
+ <path
+ d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z"
+ id="Shape"></path>
</g>
</svg>
<span class="snow-logo-type">Snowpack</span>
</a>
<div class="search-form">
- <input type="text" name="search" placeholder="Search documentation..." class="search-form-input" id="search-form-input">
+ <input type="text" name="search" placeholder="Search documentation..." class="search-form-input"
+ id="search-form-input">
<span class="search-form-hint">
<span class="sr-only">Press </span>
<kbd class="font-sans"><abbr title="Command" style="text-decoration: none;">⌘</abbr></kbd>
@@ -29,64 +35,75 @@
{`v${props.version}`}
</a>
<a href="https://github.com/snowpackjs/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
- <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512">
- <path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path>
+ <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img"
+ xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512">
+ <path fill="currentColor"
+ d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z">
+ </path>
</svg>
</a>
<a href="https://twitter.com/snowpackjs" target="_blank" class="snow-nav-link snow-nav-link__desktop">
- <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
- <path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path>
+ <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img"
+ xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
+ <path fill="currentColor"
+ d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z">
+ </path>
</svg>
</a>
<a href="https://discord.gg/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
- <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240"><path d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z"/><path fill="currentColor" d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z"/></svg>
+ <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img"
+ xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240">
+ <path
+ d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z" />
+ <path fill="currentColor"
+ d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z" />
+ </svg>
</a>
</nav>
- <script>
- function handleMobileNav(evt) {
- evt.preventDefault();
- /*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we
- if we are at mobile fixed body position, so that its not scrollable(which currently causing bug) and navbar handling its
- owns scroll. Case to consider there are chance use can open navbar using toggle button and user when click on any link
- body postion should be unset
- */
- document.body.classList.toggle('is-nav-open');
- const isOpen = document.body.classList.contains('is-nav-open');
- if (isOpen) {
- evt.target.setAttribute('aria-expanded', 'true');
- } else {
- evt.target.setAttribute('aria-expanded', 'false');
- }
+<script>
+ function handleMobileNav(evt) {
+ evt.preventDefault();
+ /*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we
+ if we are at mobile fixed body position, so that its not scrollable(which currently causing bug) and navbar handling its
+ owns scroll. Case to consider there are chance use can open navbar using toggle button and user when click on any link
+ body postion should be unset
+ */
+ document.body.classList.toggle('is-nav-open');
+ const isOpen = document.body.classList.contains('is-nav-open');
+ if (isOpen) {
+ evt.target.setAttribute('aria-expanded', 'true');
+ } else {
+ evt.target.setAttribute('aria-expanded', 'false');
}
+ }
- const mobileNavBtn = document.getElementById('toc-drawer-button');
- mobileNavBtn.addEventListener('click', handleMobileNav);
- mobileNavBtn.addEventListener('touchend', handleMobileNav);
- if (window.location.pathname.startsWith('/posts')) {
- mobileNavBtn.style.display = 'none';
- }
+ const mobileNavBtn = document.getElementById('toc-drawer-button');
+ mobileNavBtn.addEventListener('click', handleMobileNav);
+ mobileNavBtn.addEventListener('touchend', handleMobileNav);
+ if (window.location.pathname.startsWith('/posts')) {
+ mobileNavBtn.style.display = 'none';
+ }
- const searchFormInputEl = document.getElementById('search-form-input');
- searchFormInputEl.addEventListener('keyup', () => {
+ const searchFormInputEl = document.getElementById('search-form-input');
+ searchFormInputEl.addEventListener('keyup', () => {
const gridTocEl = document.querySelector('#nav-primary');
- if (searchFormInputEl.value) {
- gridTocEl.classList.add('is-mobile-hidden');
- } else {
- gridTocEl.classList.remove('is-mobile-hidden');
- }
- });
+ if (searchFormInputEl.value) {
+ gridTocEl.classList.add('is-mobile-hidden');
+ } else {
+ gridTocEl.classList.remove('is-mobile-hidden');
+ }
+ });
- document.onkeydown = function (e) {
- if ((e.ctrlKey || e.metaKey) && e.which == 75) {
- e.preventDefault();
- searchFormInputEl.focus();
- }
- };
+ document.onkeydown = function (e) {
+ if ((e.ctrlKey || e.metaKey) && e.which == 75) {
+ e.preventDefault();
+ searchFormInputEl.focus();
+ }
+ };
</script>
<script type="module" defer>
import docsearch from 'docsearch.js/dist/cdn/docsearch.min.js';
docsearch({
apiKey: '562139304880b94536fc53f5d65c5c19', indexName: 'snowpack', inputSelector: '.search-form-input', debug: true // Set debug to true if you want to inspect the dropdown
});
-</script>
-</Component>
+</script> \ No newline at end of file
diff --git a/examples/snowpack/astro/components/Subnav.hmx b/examples/snowpack/astro/components/Subnav.hmx
index 49900e04b..3e2834595 100644
--- a/examples/snowpack/astro/components/Subnav.hmx
+++ b/examples/snowpack/astro/components/Subnav.hmx
@@ -1,19 +1,21 @@
-<Component>
- <script type="module" defer src="/js/index.js"></script>
- <aside class="snow-toc snow-toc__subnav snow-view-subnav">
- <h2 class="content-title">
- {props.title}
- </h2>
+<script type="module" defer src="/js/index.js"></script>
+<aside class="snow-toc snow-toc__subnav snow-view-subnav">
+ <h2 class="content-title">
+ {props.title}
+ </h2>
+
+ {props.headers.length > 0 && <div>
<h4 class="snow-toc-section-header">On this page</h4>
<nav class="toc">
<ol>
- {props.headings.map((heading) => {
- return <li><a href={heading.url}>{heading.text}</a></li>
+ {props.headers.map((heading) => {
+ return <li><a href={"#" + heading.slug}>{heading.text}</a></li>
})}
</ol>
</nav>
<hr />
- <h4 class="snow-toc-section-header">Suggest a change</h4>
- <a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a>
- </aside>
-</Component> \ No newline at end of file
+ </div>}
+
+ <h4 class="snow-toc-section-header">Suggest a change</h4>
+ <a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a>
+</aside> \ No newline at end of file
diff --git a/examples/snowpack/astro/layouts/base.hmx b/examples/snowpack/astro/layouts/base.hmx
index 75150ad5d..c002416e7 100644
--- a/examples/snowpack/astro/layouts/base.hmx
+++ b/examples/snowpack/astro/layouts/base.hmx
@@ -1,56 +1,56 @@
-<script hmx="setup">
+<script astro>
import Banner from '../components/Banner.hmx';
import Nav from '../components/Nav.hmx';
- export function setup() {
+ export function setup({ context }) {
return {
- title: 'Snowpack',
- description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.',
- props: {
- version: '3.0.13',
+ context: {
+ title: 'Snowpack',
+ description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.',
+ currentSnowpackVersion: '3.0.13',
}
};
}
</script>
-<head>
+<slot:head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
- <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"/>
+ <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
<link rel="manifest" href="/favicon/site.webmanifest" />
<!-- Primary Meta Tags -->
- <title>{title}</title>
- <meta name="title" content={title} />
- <meta name="description" content="{description}" />
+ <title>{context.title}</title>
+ <meta name="title" content={context.title} />
+ <meta name="description" content="{context.description}" />
<!-- Open Graph / Facebook -->
- <meta property="og:type" content="website"/>
- <meta property="og:url" content="https://www.snowpack.dev{props.permalink}"/>
- <meta property="og:title" content={title}/>
- <meta property="og:description" content={description}/>
- <meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg"/>
+ <meta property="og:type" content="website" />
+ <meta property="og:url" content={context.permalink}/>
+ <meta property="og:title" content={context.title} />
+ <meta property="og:description" content={context.description} />
+ <meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg" />
<!-- Twitter -->
- <meta property="twitter:card" content="summary_large_image"/>
- <meta property="twitter:url" content="https://www.snowpack.dev{props.permalink}"/>
- <meta property="twitter:title" content={title}/>
- <meta property="twitter:description" content={description}/>
- <meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg"/>
+ <meta property="twitter:card" content="summary_large_image" />
+ <meta property="twitter:url" content={context.permalink}/>
+ <meta property="twitter:title" content={context.title} />
+ <meta property="twitter:description" content={context.description} />
+ <meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg" />
<!-- Global Stylesheets -->
<link rel="stylesheet" href="/css/app.css" />
- <link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet"/>
+ <link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet" />
<!-- Note: You can then add additional, custom things here as well. -->
<!-- if no slot given, assume add to bottom -->
<slot></slot>
-</head>
+</slot:head>
-<body class="base 2">
+<slot:body>
<Banner></Banner>
- <Nav version={props.version} />
+ <Nav version={context.currentSnowpackVersion} />
<!-- if no slot given, assume add to bottom -->
<slot></slot>
@@ -65,4 +65,4 @@
gtag('js', new Date());
gtag('config', 'UA-130280175-9', { page_path: location.pathname === '/' ? (location.pathname + location.hash) : (location.pathname) });
</script>
-</body>
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/layouts/content-with-cover.hmx b/examples/snowpack/astro/layouts/content-with-cover.hmx
index 7ec875a3c..2934ec307 100644
--- a/examples/snowpack/astro/layouts/content-with-cover.hmx
+++ b/examples/snowpack/astro/layouts/content-with-cover.hmx
@@ -1,12 +1,14 @@
-<script hmx="setup">
+<script astro>
import Menu from '../components/Menu.hmx';
import Subnav from '../components/Subnav.hmx';
- export function setup() {
- return {layout: 'layouts/base.hmx', props: {}};
+
+ export const layout = 'layouts/base.hmx';
+ export function setup({ context }) {
+ return {};
}
</script>
-<head>
+<slot:head>
<style>
.cover-wrapper {
width: 100%;
@@ -47,13 +49,13 @@
</style>
<slot></slot>
-</head>
+</slot:head>
-<body>
+<slot:body>
<div class="cover-wrapper">
- <img class="cover-blur" src={props.cover} alt=""/>
- <img class="cover" src={props.cover} alt=""/>
+ <img class="cover-blur" src={context.cover} alt=""/>
+ <img class="cover" src={context.cover} alt=""/>
</div>
<div class="container">
@@ -66,7 +68,7 @@
<article class="snow-view-main">
<div class="content">
<h2 class="content-title">
- {title}
+ {context.title}
</h2>
<div class="content-layout">
<div class="content-body">
@@ -76,7 +78,7 @@
</div>
</article>
- <Subnav title={title} />
+ <Subnav title={context.title} headers={context.content.headers} />
</section>
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/layouts/content.hmx b/examples/snowpack/astro/layouts/content.hmx
index 2ca634a44..e040a47bf 100644
--- a/examples/snowpack/astro/layouts/content.hmx
+++ b/examples/snowpack/astro/layouts/content.hmx
@@ -1,33 +1,22 @@
-<script hmx="setup">
+<script astro>
import Subnav from '../components/Subnav.hmx';
import Menu from '../components/Menu.hmx';
- import markdownToAst from "mdast-util-from-markdown";
- import markdownTableOfContents from "mdast-util-toc";
- export function setup({content}) {
- const mdAst = markdownToAst(content.source);
- // This is super gross, and just me trying to get an existing table of contents generator to work
- // we can either do this internally as helpful sugar, or build a simpler one as a plugin
- const headingsAst = markdownTableOfContents(mdAst);
- const headings = headingsAst.map ? headingsAst.map.children.map(ch => {
- return {depth: 1, url: ch.children[0].children[0].url, text: ch.children[0].children[0].children[0].value};
- }) : [];
-
- return {
- layout: 'layouts/base.hmx',
- props: {
- headings,
- }
+ export const layout = 'layouts/base.hmx';
+ export function setup({ context }) {
+ return {
+ context: {
+ }
};
}
</script>
-<head>
+<slot:head>
<slot></slot>
-</head>
+</slot:head>
-<body>
+<slot:body>
<div class="container">
<section class="snow-view__docs has-subnav">
@@ -35,12 +24,12 @@
<Menu />
</aside>
- <Subnav title={title} headings={props.headings} />
+ <Subnav title={context.title} headers={context.content.headers} />
<article class="snow-view-main">
<div class="content">
<h2 class="content-title">
- {title}
+ {context.title}
</h2>
<div class="content-layout">
<div class="content-body">
@@ -52,4 +41,4 @@
</section>
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/layouts/main.hmx b/examples/snowpack/astro/layouts/main.hmx
index e2bbac677..c0793e3b8 100644
--- a/examples/snowpack/astro/layouts/main.hmx
+++ b/examples/snowpack/astro/layouts/main.hmx
@@ -1,20 +1,18 @@
-<script hmx="setup">
+<script astro>
import Menu from '../components/Menu.hmx';
- export function setup() {
- return {
- layout: 'layouts/base.hmx',
- props: {}
- };
+ export const layout = 'layouts/base.hmx';
+ export function setup({ context }) {
+ return {};
}
</script>
-<head>
+<slot:head>
<!-- hi -->
<slot></slot>
-</head>
+</slot:head>
-<body class="base 2">
+<slot:body>
<div class="container">
<section class="snow-view__docs is-full">
@@ -28,4 +26,4 @@
</section>
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/layouts/post.hmx b/examples/snowpack/astro/layouts/post.hmx
index 6e5841633..fef70a4ac 100644
--- a/examples/snowpack/astro/layouts/post.hmx
+++ b/examples/snowpack/astro/layouts/post.hmx
@@ -1,11 +1,12 @@
-<script hmx="setup">
+<script astro>
import {format as formatDate, parseISO} from 'date-fns';
- export function setup() {
- return { layout: 'layouts/base.hmx', props: {} };
+ export const layout = 'layouts/base.hmx';
+ export function setup({ context }) {
+ return {};
}
</script>
-<head>
+<slot:head>
<link rel="stylesheet" href="/css/legacy-post.css" />
<style>
.markdown-body img,
@@ -99,10 +100,9 @@
}
</style>
<slot></slot>
-</head>
-
-<body>
+</slot:head>
+<slot:body>
<div class="grid-extra-space">
<div class="grid-body-header">
<svg height="80px" style="padding-left: 8px;" viewBox="0 0 640 512" version="1.1"
@@ -115,7 +115,7 @@
</g>
</g>
</svg>
- <h1 class="header-snowpack">{title}</h1>
+ <h1 class="header-snowpack">{context.title}</h1>
<p>
@@ -140,4 +140,4 @@
<slot></slot>
</article>
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/pages/404.hmx b/examples/snowpack/astro/pages/404.hmx
index a1799cf6e..f82e303ff 100644
--- a/examples/snowpack/astro/pages/404.hmx
+++ b/examples/snowpack/astro/pages/404.hmx
@@ -1,16 +1,17 @@
-<script hmx="setup">
- export function setup() {
+<script astro>
+ export const layout = 'layouts/main.hmx';
+
+ export function setup({ context }) {
return {
- title: '404 - Not Found',
- layout: 'layouts/main.hmx',
- props: {
+ context: {
+ title: '404 - Not Found',
}
};
}
</script>
<h2 class="content-title">
- {title}
+ {context.title}
</h2>
<div class="content">
diff --git a/examples/snowpack/astro/pages/guides.hmx b/examples/snowpack/astro/pages/guides.hmx
index 6660d2f79..20a22baaf 100644
--- a/examples/snowpack/astro/pages/guides.hmx
+++ b/examples/snowpack/astro/pages/guides.hmx
@@ -1,52 +1,56 @@
-<script hmx="setup">
+<script astro>
import Card from '../components/Card.jsx';
+ export const layout = 'layouts/main.hmx';
+
// mocked for now, to be added later
// 1. import {paginate} from 'magicthing';
// 2. export default function ({paginate}) {
function paginate(options) {
if (options.tag === 'guide') {
return [
- {title: 'Test guide 1', href:"#"},
- {title: 'Test guide 2', href:"#"},
+ { title: 'Test guide 1', href: "#" },
+ { title: 'Test guide 2', href: "#" },
];
}
if (options.tag === 'communityGuides') {
- return [{title: 'Test communityGuides', href:"#"}];
+ return [{ title: 'Test communityGuides', href: "#" }];
}
return [];
}
- export function setup({/* paginate */}) {
+
+ export function setup({ context, /* paginate */ }) {
return {
- title: 'Guides',
- description: "Snowpack's usage and integration guides.",
- layout: 'layouts/main.hmx',
- props: {
- guides: paginate({
- files: '/posts/guides/*.md',
- // sort: ((a, b) => new Date(b) - new Date(a)),
- tag: 'guide',
- limit: 10,
- // page: query.page,
- }),
- communityGuides: paginate({
- files: '/posts/guides/*.md',
- // sort: ((a, b) => new Date(b) - new Date(a)),
- tag: 'communityGuides',
- limit: 10,
- }),
+ context: {
+ title: 'Guides',
+ description: "Snowpack's usage and integration guides.",
+ props: {
+ guides: paginate({
+ files: '/posts/guides/*.md',
+ // sort: ((a, b) => new Date(b) - new Date(a)),
+ tag: 'guide',
+ limit: 10,
+ // page: query.page,
+ }),
+ communityGuides: paginate({
+ files: '/posts/guides/*.md',
+ // sort: ((a, b) => new Date(b) - new Date(a)),
+ tag: 'communityGuides',
+ limit: 10,
+ }),
+ }
}
};
}
</script>
-<head>
+<slot:head>
-</head>
+</slot:head>
-<body>
+<slot:body>
<h2 class="content-title">
- {title}
+ {context.title}
</h2>
<h3 class="content-title">
@@ -56,13 +60,13 @@
<div class="content">
<ul>
{props.guides.map((post) => {
- return <li><a href={post.href}>{post.title}</a></li>;
+ return <li><a href={post.href}>{post.title}</a></li>;
})}
</ul>
</div>
- <br/>
- <br/>
+ <br />
+ <br />
<h3 class="content-title">
Popular Integration Guides
@@ -70,7 +74,8 @@
<div class="card-grid card-grid-4">
{props.communityGuides.map((post) => {
- return <Card item={post} />;
+ return
+ <Card item={post} />;
})}
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/pages/index.hmx b/examples/snowpack/astro/pages/index.hmx
index d32992920..03f03f8ce 100644
--- a/examples/snowpack/astro/pages/index.hmx
+++ b/examples/snowpack/astro/pages/index.hmx
@@ -1,22 +1,21 @@
-<script hmx="setup">
+<script astro>
import Menu from '../components/Menu.hmx';
import Hero from '../components/Hero.hmx';
- export function setup() {
- return {
- layout: 'layouts/base.hmx',
- props: {}
- }
+
+ export const layout = 'layouts/base.hmx';
+ export function setup({context}) {
+ return {}
}
</script>
-<head>
- <!-- Head Stuff -->
-</head>
+<slot:head>
+ <meta charset="AAA" />
+</slot:head>
-<body>
- <Hero bar={title}></Hero>
+<slot:body>
+ <Hero bar={context.title}></Hero>
- <div foo={title} class="container" style="margin: 0 auto">
+ <div foo={context.title} class="container" style="margin: 0 auto">
<section class="snow-view__docs is-full is-home">
<aside id="nav-primary" class="snow-view-nav">
@@ -95,4 +94,4 @@
<!-- Place this tag in your head or just before your close body tag. -->
<script async="async" defer="defer" src="https://buttons.github.io/buttons.js"></script>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/pages/news.hmx b/examples/snowpack/astro/pages/news.hmx
index 91595d625..5920cba4f 100644
--- a/examples/snowpack/astro/pages/news.hmx
+++ b/examples/snowpack/astro/pages/news.hmx
@@ -1,31 +1,33 @@
-<script hmx="setup">
+<script astro>
import Card from '../components/Card.jsx';
import CompanyLogo from '../components/CompanyLogo.jsx';
import NewsAssets from '../components/NewsAssets.svelte';
import NewsTitle from '../components/NewsTitle.vue';
+ export const layout = 'layouts/main.hmx';
+
import news from '../data/news.json';
import users from '../data/users.json';
- export function setup({ findContent }) {
+ export function setup({ context, request }) {
+ console.log(request);
return {
- title: 'Community & News',
- description: "Snowpack community news and companies that use Snowpack.",
- layout: 'layouts/main.hmx',
- // Using Snowpack? Want to be featured on snowpack.dev?
- // Add your project, organization, or company to the end of this list!
- props: {
+ context: {
+ title: 'Community & News',
+ description: "Snowpack community news and companies that use Snowpack.",
+ // Using Snowpack? Want to be featured on snowpack.dev?
+ // Add your project, organization, or company to the end of this list!
news,
users,
}
- };
+ }
}
</script>
-<head> </head>
+<slot:head> </slot:head>
-<body>
- <NewsTitle title={title} />
+<slot:body>
+ <NewsTitle title={context.title} />
<p>
Get the latest news, blog posts, and tutorials on Snowpack. <a href="/feed.xml">Also available via RSS.</a>
@@ -45,7 +47,8 @@
working on!</div>
</article>
- {props.news.reverse().map((item) => <Card:dynamic item={item} />)}
+ {context.news.reverse().map((item) =>
+ <Card:dynamic item={item} />)}
</div>
<div class="content">
@@ -54,7 +57,8 @@
<div class="company-logos">
- {props.users.map((user) => <CompanyLogo user={user} />)}
+ {context.users.map((user) =>
+ <CompanyLogo user={user} />)}
<a href="https://github.com/snowpackjs/snowpack/edit/main/www/_template/news.md" target="_blank"
title="Add Your Project/Company!" class="add-company-button">
@@ -70,4 +74,4 @@
<NewsAssets />
</div>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/pages/plugins.hmx b/examples/snowpack/astro/pages/plugins.hmx
index 6bda1ebda..8749f0169 100644
--- a/examples/snowpack/astro/pages/plugins.hmx
+++ b/examples/snowpack/astro/pages/plugins.hmx
@@ -1,29 +1,24 @@
-<script hmx="setup">
- import news from '../data/news.json';
- import users from '../data/users.json';
+<script astro>
import PluginSearchPage from '../components/PluginSearchPage.jsx';
- export function setup({ findContent }) {
+ export const layout = 'layouts/main.hmx';
+
+ export function setup({ context }) {
return {
- title: 'The Snowpack Plugin Catalog',
- description: 'Snowpack plugins allow for configuration-minimal tooling integration.',
- layout: 'layouts/main.hmx',
- // Using Snowpack? Want to be featured on snowpack.dev?
- // Add your project, organization, or company to the end of this list!
- props: {
- news,
- users,
+ context: {
+ title: 'The Snowpack Plugin Catalog',
+ description: 'Snowpack plugins allow for configuration-minimal tooling integration.',
}
};
}
</script>
-<head>
-</head>
-
-<body>
+<slot:head>
+</slot:head>
+
+<slot:body>
<h2 class="content-title">
- { title }
+ { context.title }
</h2>
<h3 class="pluginPage-subheading">Customize Snowpack with optimized build plugins.</h3>
@@ -33,4 +28,4 @@
</p>
<PluginSearchPage:dynamic />
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file
diff --git a/examples/snowpack/astro/pages/proof-of-concept-dynamic/[slug].hmx b/examples/snowpack/astro/pages/proof-of-concept-dynamic/[slug].hmx
index 0535f4625..55ea99f75 100644
--- a/examples/snowpack/astro/pages/proof-of-concept-dynamic/[slug].hmx
+++ b/examples/snowpack/astro/pages/proof-of-concept-dynamic/[slug].hmx
@@ -1,4 +1,4 @@
-<script hmx="setup">
+<script astro>
import Subnav from '../components/Subnav.hmx';
import { content as Menu } from '../components/Menu.hmx';
// import contentful from 'skypack:contentful';
@@ -16,12 +16,12 @@
<Menu />
</aside>
- <Subnav title={title} />
+ <Subnav title={context.title} headers={context.content.headers} />
<article class="snow-view-main">
<div class="content">
<h2 class="content-title">
- {title}
+ {context.title}
</h2>
<div class="content-layout">
<div class="content-body">
diff --git a/package-lock.json b/package-lock.json
index 1d4c4cb77..3e3ac71ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -167,6 +167,12 @@
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
"integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg=="
},
+ "@types/github-slugger": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
+ "integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
+ "dev": true
+ },
"@types/json-schema": {
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
@@ -1562,6 +1568,21 @@
"pump": "^3.0.0"
}
},
+ "github-slugger": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
+ "integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
+ "requires": {
+ "emoji-regex": ">=6.0.0 <=6.1.1"
+ },
+ "dependencies": {
+ "emoji-regex": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
+ "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4="
+ }
+ }
+ },
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
diff --git a/package.json b/package.json
index 0dd8b04f9..9681b06f1 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
"deepmerge": "^4.2.2",
"domhandler": "^4.0.0",
"es-module-lexer": "^0.4.1",
+ "github-slugger": "^1.3.0",
"gray-matter": "^4.0.2",
"htmlparser2": "^6.0.0",
"kleur": "^4.1.4",
@@ -54,6 +55,7 @@
"yargs-parser": "^20.2.7"
},
"devDependencies": {
+ "@types/github-slugger": "^1.3.0",
"@types/sass": "^1.16.0",
"@types/yargs-parser": "^20.2.0",
"@typescript-eslint/eslint-plugin": "^4.18.0",
diff --git a/snowpack-plugin.cjs b/snowpack-plugin.cjs
index 82be28b13..969b6075e 100644
--- a/snowpack-plugin.cjs
+++ b/snowpack-plugin.cjs
@@ -12,58 +12,10 @@ module.exports = function (snowpackConfig, { resolve } = {}) {
output: ['.js'],
},
async load({ filePath }) {
- const { compilePage, compileComponent } = await transformPromise;
+ const { compileComponent } = await transformPromise;
const projectRoot = snowpackConfig.root;
const contents = await readFile(filePath, 'utf-8');
-
- if (!filePath.includes('/pages/') && !filePath.includes('/layouts/')) {
const result = await compileComponent(contents, { compileOptions: { resolve }, filename: filePath, projectRoot });
- return result.contents;
- }
- const result = await compilePage(contents, {
- compileOptions: { resolve },
- filename: filePath,
- projectRoot,
- });
-
- try {
- return /* js */ `
- ${result.contents}
-
- export default async (childDatas, childRenderFns) => {
- // Kind of hacky, can clean up if this works
- const renderHmx = {setup, head, body};
- const merge = (await import('deepmerge')).default;
- const content = childDatas && childDatas[0].content;
- const _data = await renderHmx.setup({content});
- if (_data.layout) {
- const renderLayout = (await import('/_hmx/layouts/' + _data.layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js'))).default;
- return renderLayout(
- [...(childDatas || []), _data],
- [...(childRenderFns || []), renderHmx]
- );
- }
- const data = merge.all([_data, ...(childDatas || [])]);
- let headResult;
- let bodyResult;
- for (const renderFn of (childRenderFns || [])) {
- let headAndBody = await Promise.all([
- renderFn.head(data, headResult),
- renderFn.body(data, bodyResult)
- ]);
- headResult = headAndBody[0];
- bodyResult = headAndBody[1];
- }
- return h(Fragment, null, [
- renderHmx.head(data, headResult, true),
- renderHmx.body(data, bodyResult, true),
- ]);
- };
- `;
- } catch (err) {
- console.error(err);
- }
-
return result.contents;
},
};
diff --git a/src/@types/astro.ts b/src/@types/astro.ts
index f7170cb61..d2d82f3aa 100644
--- a/src/@types/astro.ts
+++ b/src/@types/astro.ts
@@ -17,9 +17,12 @@ export interface JsxItem {
export interface TransformResult {
script: string;
+ head: JsxItem | undefined;
+ body: JsxItem | undefined;
items: JsxItem[];
}
export interface CompileResult {
+ result: TransformResult;
contents: string;
}
diff --git a/src/codegen/index.ts b/src/codegen/index.ts
index 662d63858..0b94fdfd3 100644
--- a/src/codegen/index.ts
+++ b/src/codegen/index.ts
@@ -53,6 +53,10 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
continue;
}
const val: TemplateNode = attr.value[0];
+ if (!val) {
+ result[attr.name] = '(' + val + ')';
+ continue;
+ }
switch (val.type) {
case 'MustacheTag':
result[attr.name] = '(' + val.expression + ')';
@@ -143,33 +147,37 @@ function getComponentWrapper(_name: string, { type, url }: { type: string; url:
}
function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
+ let compiledCode = compileExpressionSafe(raw, loader);
// esbuild treeshakes unused imports. In our case these are components, so let's keep them.
const imports = eslexer
- .parse(raw)[0]
- .filter(({ d }) => d === -1)
- .map((i: any) => raw.substring(i.ss, i.se));
+ .parse(raw)[0]
+ .filter(({ d }) => d === -1)
+ .map((i) => raw.substring(i.ss, i.se));
+ for (let importStatement of imports) {
+ if (!compiledCode.includes(importStatement)) {
+ compiledCode = importStatement + '\n' + compiledCode;
+ }
+ }
+ return compiledCode;
+}
+
+function compileExpressionSafe(raw: string, loader: 'jsx' | 'tsx'): string {
let { code } = transformSync(raw, {
loader,
jsxFactory: 'h',
jsxFragment: 'Fragment',
charset: 'utf8',
});
-
- for (let importStatement of imports) {
- if (!code.includes(importStatement)) {
- code = importStatement + '\n' + code;
- }
- }
-
return code;
+
}
export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> {
await eslexer.init;
// Compile scripts as TypeScript, always
- const script = compileScriptSafe(ast.instance ? ast.instance.content : '', 'tsx');
+ const script = compileScriptSafe(ast.module ? ast.module.content : '', 'tsx');
// Todo: Validate that `h` and `Fragment` aren't defined in the script
const [scriptImports] = eslexer.parse(script, 'optional-sourcename');
@@ -182,6 +190,8 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
);
const additionalImports = new Set<string>();
+ let headItem: JsxItem | undefined;
+ let bodyItem: JsxItem | undefined;
let items: JsxItem[] = [];
let mode: 'JSX' | 'SCRIPT' | 'SLOT' = 'JSX';
let collectionItem: JsxItem | undefined;
@@ -192,7 +202,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
enter(node: TemplateNode) {
switch (node.type) {
case 'MustacheTag':
- let code = compileScriptSafe(node.expression, 'jsx');
+ let code = compileExpressionSafe(node.expression, 'jsx');
let matches: RegExpExecArray[] = [];
let match: RegExpExecArray | null | undefined;
@@ -230,8 +240,12 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return;
}
break;
+
+ case 'Head':
+ case 'Body':
case 'InlineComponent':
- case 'Element':
+ case 'Title':
+ case 'Element': {
const name: string = node.name;
if (!name) {
throw new Error('AHHHH');
@@ -241,6 +255,16 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
currentItemName = name;
if (!collectionItem) {
collectionItem = { name, jsx: '' };
+ if (node.type === 'Head') {
+ collectionItem.jsx += `h(Fragment, null`;
+ headItem = collectionItem;
+ return;
+ }
+ if (node.type === 'Body') {
+ collectionItem.jsx += `h(Fragment, null`;
+ bodyItem = collectionItem;
+ return;
+ }
items.push(collectionItem);
}
collectionItem.jsx += collectionItem.jsx === '' ? '' : ',';
@@ -249,10 +273,6 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
collectionItem.jsx += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
return;
}
- if (name === 'Component') {
- collectionItem.jsx += `h(Fragment, null`;
- return;
- }
const [componentName, componentKind] = name.split(':');
const componentImportData = components[componentName];
if (!componentImportData) {
@@ -265,6 +285,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
collectionItem.jsx += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`;
return;
+ }
case 'Attribute': {
this.skip();
return;
@@ -293,7 +314,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return;
}
default:
- throw new Error('Unexpected node type: ' + node.type);
+ throw new Error('Unexpected (enter) node type: ' + node.type);
}
},
leave(node, parent, prop, index) {
@@ -314,6 +335,9 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
if (!collectionItem) {
return;
}
+ case 'Head':
+ case 'Body':
+ case 'Title':
case 'Element':
case 'InlineComponent':
if (!collectionItem) {
@@ -329,13 +353,15 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return;
}
default:
- throw new Error('Unexpected node type: ' + node.type);
+ throw new Error('Unexpected (leave) node type: ' + node.type);
}
},
});
return {
script: script + '\n' + Array.from(additionalImports).join('\n'),
+ head: headItem,
+ body: bodyItem,
items,
};
}
diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts
index bedb29cda..b77357d23 100644
--- a/src/compiler/interfaces.ts
+++ b/src/compiler/interfaces.ts
@@ -58,7 +58,7 @@ export interface Parser {
export interface Script extends BaseNode {
type: 'Script';
- context: string;
+ context: 'runtime' | 'setup';
content: string;
}
@@ -75,8 +75,8 @@ export interface Style extends BaseNode {
export interface Ast {
html: TemplateNode;
css: Style;
- instance: Script;
module: Script;
+ // instance: Script;
}
export interface Warning {
@@ -94,38 +94,6 @@ export type ModuleFormat = 'esm' | 'cjs';
export type CssHashGetter = (args: { name: string; filename: string | undefined; css: string; hash: (input: string) => string }) => string;
-export interface CompileOptions {
- format?: ModuleFormat;
- name?: string;
- filename?: string;
- generate?: 'dom' | 'ssr' | false;
-
- sourcemap?: object | string;
- outputFilename?: string;
- cssOutputFilename?: string;
- sveltePath?: string;
-
- dev?: boolean;
- accessors?: boolean;
- immutable?: boolean;
- hydratable?: boolean;
- legacy?: boolean;
- customElement?: boolean;
- tag?: string;
- css?: boolean;
- loopGuardTimeout?: number;
- namespace?: string;
- cssHash?: CssHashGetter;
-
- preserveComments?: boolean;
- preserveWhitespace?: boolean;
-}
-
-export interface ParserOptions {
- filename?: string;
- customElement?: boolean;
-}
-
export interface Visitor {
enter: (node: Node) => void;
leave?: (node: Node) => void;
diff --git a/src/compiler/parse/index.ts b/src/compiler/parse/index.ts
index eab2c42c5..f98119d73 100644
--- a/src/compiler/parse/index.ts
+++ b/src/compiler/parse/index.ts
@@ -232,33 +232,34 @@ export default function parse(template: string, options: ParserOptions = {}): As
);
}
- const instance_scripts = parser.js.filter((script) => script.context === 'default');
- const module_scripts = parser.js.filter((script) => script.context === 'module');
+ // const instance_scripts = parser.js.filter((script) => script.context === 'default');
+ // const module_scripts = parser.js.filter((script) => script.context === 'module');
+ const hmx_scripts = parser.js.filter((script) => script.context === 'setup');
- if (instance_scripts.length > 1) {
+ if (hmx_scripts.length > 1) {
parser.error(
{
code: 'invalid-script',
- message: 'A component can only have one instance-level <script> element',
+ message: 'A component can only have one <script astro> element',
},
- instance_scripts[1].start
+ hmx_scripts[1].start
);
}
- if (module_scripts.length > 1) {
- parser.error(
- {
- code: 'invalid-script',
- message: 'A component can only have one <script context="module"> element',
- },
- module_scripts[1].start
- );
- }
+ // if (module_scripts.length > 1) {
+ // parser.error(
+ // {
+ // code: 'invalid-script',
+ // message: 'A component can only have one <script context="module"> element',
+ // },
+ // module_scripts[1].start
+ // );
+ // }
return {
html: parser.html,
css: parser.css[0],
- instance: instance_scripts[0],
- module: module_scripts[0],
+ // instance: instance_scripts[0],
+ module: hmx_scripts[0],
};
}
diff --git a/src/compiler/parse/read/script.ts b/src/compiler/parse/read/script.ts
index eb7a8c5b3..7afbfb08f 100644
--- a/src/compiler/parse/read/script.ts
+++ b/src/compiler/parse/read/script.ts
@@ -7,15 +7,16 @@ import { Node, Program } from 'estree';
const script_closing_tag = '</script>';
-function get_context(parser: Parser, attributes: any[], start: number): string {
- const context = attributes.find((attribute) => attribute.name === 'context');
- if (!context) return 'default';
+function get_context(parser: Parser, attributes: any[], start: number): 'runtime' | 'setup' {
+ const context = attributes.find((attribute) => attribute.name === 'astro');
+ if (!context) return 'runtime';
+ if (context.value === true) return 'setup';
if (context.value.length !== 1 || context.value[0].type !== 'Text') {
parser.error(
{
code: 'invalid-script',
- message: 'context attribute must be static',
+ message: 'astro attribute must be static',
},
start
);
@@ -23,11 +24,11 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
const value = context.value[0].data;
- if (value !== 'module') {
+ if (value !== 'setup') {
parser.error(
{
code: 'invalid-script',
- message: 'If the context attribute is supplied, its value must be "module"',
+ message: 'If the "astro" attribute has a value, its value must be "setup"',
},
context.start
);
diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts
index fa5ccb6e3..e1dbcab42 100644
--- a/src/compiler/parse/state/tag.ts
+++ b/src/compiler/parse/state/tag.ts
@@ -14,13 +14,14 @@ import list from '../../utils/list.js';
const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const meta_tags = new Map([
- ['svelte:head', 'Head'],
- ['svelte:options', 'Options'],
- ['svelte:window', 'Window'],
- ['svelte:body', 'Body'],
+ ['slot:head', 'Head'],
+ ['slot:body', 'Body'],
+ // ['astro:options', 'Options'],
+ // ['astro:window', 'Window'],
+ // ['astro:body', 'Body'],
]);
-const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment');
+const valid_meta_tags = Array.from(meta_tags.keys()); //.concat('astro:self', 'astro:component', 'astro:fragment');
const specials = new Map([
[
@@ -39,9 +40,10 @@ const specials = new Map([
],
]);
-const SELF = /^svelte:self(?=[\s/>])/;
-const COMPONENT = /^svelte:component(?=[\s/>])/;
-const SLOT = /^svelte:fragment(?=[\s/>])/;
+const SELF = /^astro:self(?=[\s/>])/;
+const COMPONENT = /^astro:component(?=[\s/>])/;
+const SLOT = /^astro:fragment(?=[\s/>])/;
+const HEAD = /^head(?=[\s/>])/;
function parent_is_head(stack) {
let i = stack.length;
@@ -79,7 +81,7 @@ export default function tag(parser: Parser) {
if (meta_tags.has(name)) {
const slug = meta_tags.get(name).toLowerCase();
if (is_closing_tag) {
- if ((name === 'svelte:window' || name === 'svelte:body') && parser.current().children.length) {
+ if ((name === 'astro:window' || name === 'astro:body') && parser.current().children.length) {
parser.error(
{
code: `invalid-${slug}-content`,
@@ -115,9 +117,9 @@ export default function tag(parser: Parser) {
const type = meta_tags.has(name)
? meta_tags.get(name)
- : /[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component'
+ : /[A-Z]/.test(name[0]) || name === 'astro:self' || name === 'astro:component'
? 'InlineComponent'
- : name === 'svelte:fragment'
+ : name === 'astro:fragment'
? 'SlotTemplate'
: name === 'title' && parent_is_head(parser.stack)
? 'Title'
@@ -197,13 +199,13 @@ export default function tag(parser: Parser) {
parser.allow_whitespace();
}
- if (name === 'svelte:component') {
+ if (name === 'astro:component') {
const index = element.attributes.findIndex((attr) => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) {
parser.error(
{
code: 'missing-component-definition',
- message: "<svelte:component> must have a 'this' attribute",
+ message: "<astro:component> must have a 'this' attribute",
},
start
);
@@ -281,27 +283,29 @@ function read_tag_name(parser: Parser) {
parser.error(
{
code: 'invalid-self-placement',
- message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
+ message: '<astro:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
},
start
);
}
- return 'svelte:self';
+ return 'astro:self';
}
- if (parser.read(COMPONENT)) return 'svelte:component';
+ if (parser.read(COMPONENT)) return 'astro:component';
- if (parser.read(SLOT)) return 'svelte:fragment';
+ if (parser.read(SLOT)) return 'astro:fragment';
+
+ if (parser.read(HEAD)) return 'head';
const name = parser.read_until(/(\s|\/|>)/);
if (meta_tags.has(name)) return name;
- if (name.startsWith('svelte:')) {
+ if (name.startsWith('astro:')) {
const match = fuzzymatch(name.slice(7), valid_meta_tags);
- let message = `Valid <svelte:...> tag names are ${list(valid_meta_tags)}`;
+ let message = `Valid <astro:...> tag names are ${list(valid_meta_tags)}`;
if (match) message += ` (did you mean '${match}'?)`;
parser.error(
diff --git a/src/generate.ts b/src/generate.ts
index ad2e9ded9..225bf4fde 100644
--- a/src/generate.ts
+++ b/src/generate.ts
@@ -52,6 +52,7 @@ export default async function (astroConfig: AstroConfig) {
await writeFile(outPath, html, 'utf-8');
} catch (err) {
console.error('Unable to generate page', rel);
+ console.error(err);
}
}
diff --git a/src/markdown-encode.ts b/src/markdown-encode.ts
deleted file mode 100644
index 173c63fde..000000000
--- a/src/markdown-encode.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import type { HtmlExtension, Token } from 'micromark/dist/shared-types';
-
-const characterReferences = {
- '"': 'quot',
- '&': 'amp',
- '<': 'lt',
- '>': 'gt',
- '{': 'lbrace',
- '}': 'rbrace',
-};
-
-type EncodedChars = '"' | '&' | '<' | '>' | '{' | '}';
-
-function encode(value: string): string {
- return value.replace(/["&<>{}]/g, (raw: string) => {
- return '&' + characterReferences[raw as EncodedChars] + ';';
- });
-}
-
-const plugin: HtmlExtension = {
- exit: {
- codeFlowValue() {
- const token: Token = arguments[0];
- const serialize = (this.sliceSerialize as unknown) as (t: Token) => string;
- const raw = (this.raw as unknown) as (s: string) => void;
- const value = serialize(token);
- raw(encode(value));
- },
- },
-};
-
-export { plugin as default };
diff --git a/src/micromark-collect-headers.ts b/src/micromark-collect-headers.ts
new file mode 100644
index 000000000..d614cc5b4
--- /dev/null
+++ b/src/micromark-collect-headers.ts
@@ -0,0 +1,35 @@
+import slugger from 'github-slugger';
+
+// NOTE: micromark has terrible TS types. Instead of fighting with the
+// limited/broken TS types that they ship, we just reach for our good friend, "any".
+export function createMarkdownHeadersCollector() {
+ const headers: any[] = [];
+ let currentHeader: any;
+ return {
+ headers,
+ headersExtension: {
+ enter: {
+ atxHeading(node: any) {
+ currentHeader = {};
+ headers.push(currentHeader);
+ },
+ atxHeadingSequence(node: any) {
+ currentHeader.depth = this.sliceSerialize(node).length;
+ },
+ atxHeadingText(node: any) {
+ currentHeader.text = this.sliceSerialize(node);
+ },
+ } as any,
+ exit: {
+ atxHeading(node: any) {
+ currentHeader.slug = slugger.slug(currentHeader.text);
+ this.tag(`<h${currentHeader.depth} id="${currentHeader.slug}">`);
+ this.raw(currentHeader.text);
+ this.tag(`</h${currentHeader.depth}>`);
+
+ // console.log(this.sliceSerialize(node));
+ },
+ } as any,
+ } as any,
+ };
+}
diff --git a/src/runtime.ts b/src/runtime.ts
index a17b552e8..91ee9c5d2 100644
--- a/src/runtime.ts
+++ b/src/runtime.ts
@@ -58,7 +58,14 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
try {
const mod = await snowpackRuntime.importModule(selectedPageUrl);
- const html = (await mod.exports.default()) as string;
+ const html = (await mod.exports.__renderPage({
+ request: {
+ host: fullurl.hostname,
+ path: fullurl.pathname,
+ href: fullurl.toString(),
+ },
+ children: [],
+ })) as string;
return {
statusCode: 200,
diff --git a/src/transform2.ts b/src/transform2.ts
index 0ccdc6b55..4cca58510 100644
--- a/src/transform2.ts
+++ b/src/transform2.ts
@@ -7,7 +7,7 @@ import matter from 'gray-matter';
import gfmHtml from 'micromark-extension-gfm/html.js';
import { CompileResult, TransformResult } from './@types/astro';
import { parse } from './compiler/index.js';
-import markdownEncode from './markdown-encode.js';
+import { createMarkdownHeadersCollector } from './micromark-collect-headers.js';
import { defaultLogOptions } from './logger.js';
import { optimize } from './optimize/index.js';
import { codegen } from './codegen/index.js';
@@ -51,33 +51,35 @@ async function convertMdToJsx(
contents: string,
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
): Promise<TransformResult> {
- // This doesn't work.
const { data: _frontmatterData, content } = matter(contents);
+ const {headers, headersExtension} = createMarkdownHeadersCollector();
const mdHtml = micromark(content, {
extensions: [gfmSyntax()],
- htmlExtensions: [gfmHtml, markdownEncode],
+ htmlExtensions: [gfmHtml, headersExtension],
});
- const setupData = {
- title: _frontmatterData.title,
- description: _frontmatterData.description,
- layout: _frontmatterData.layout,
+ console.log("headers", headers);
+ const setupContext = {
+ ..._frontmatterData,
content: {
frontmatter: _frontmatterData,
-
- // This is an awful hack due to Svelte parser disliking script tags badly.
- source: content.replace(/<\/?script/g, '<SCRIPT'),
+ headers,
+ source: content,
html: mdHtml,
},
- props: {
- ..._frontmatterData,
- },
};
+ // </script> can't be anywhere inside of a JS string, otherwise the HTML parser fails.
+ // Break it up here so that the HTML parser won't detect it.
+ const stringifiedSetupContext = JSON.stringify(setupContext).replace(/\<\/script\>/g, `</scrip" + "t>`);
+
return convertHmxToJsx(
- `<script hmx="setup">export function setup() {
- return ${JSON.stringify(setupData)};
- }</script><head></head><body>${mdHtml}</body>`,
+ `<script astro>
+ ${_frontmatterData.layout ? `export const layout = ${JSON.stringify(_frontmatterData.layout)};` : ''}
+ export function setup({context}) {
+ return {context: ${stringifiedSetupContext} };
+ }
+ </script><slot:head></slot:head><slot:body><section>{${JSON.stringify(mdHtml)}}</section></slot:body>`,
{ compileOptions, filename, fileID }
);
}
@@ -97,49 +99,85 @@ async function transformFromSource(
}
}
-export async function compilePage(
+export async function compileComponent(
source: string,
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
): Promise<CompileResult> {
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
+ const headItem = sourceJsx.head;
+ const bodyItem = sourceJsx.body;
+ const headItemJsx = !headItem ? 'null' : headItem.jsx;
+ const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx;
- const headItem = sourceJsx.items.find((item) => item.name === 'head');
- const bodyItem = sourceJsx.items.find((item) => item.name === 'body');
- const headItemJsx = !headItem ? 'null' : headItem.jsx.replace('"head"', 'isRoot ? "head" : Fragment');
- const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx.replace('"head"', 'isRoot ? "body" : Fragment');
+ // sort <style> tags first
+ // TODO: remove these and inject in <head>
+ sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0));
- const modJsx = `
+ // return template
+ let modJsx = `
+// <script astro></script>
${sourceJsx.script}
+// \`__render()\`: Render the contents of the HMX module. "<slot:*>" elements are not
+// included (see below).
import { h, Fragment } from '${internalImport('h.js')}';
-export function head({title, description, props}, child, isRoot) { return (${headItemJsx}); }
-export function body({title, description, props}, child, isRoot) { return (${bodyItemJsx}); }
-`.trim();
-
- return {
- contents: modJsx,
+export default function __render(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); }
+
+// <slot:*> render functions
+export function __slothead(context, child) { return h(Fragment, null, ${headItemJsx}); }
+export function __slotbody(context, child) { return h(Fragment, null, ${bodyItemJsx}); }
+`;
+
+ if (headItemJsx || bodyItemJsx) {
+ modJsx += `
+// \`__renderPage()\`: Render the contents of the HMX module as a page. This is a special flow,
+// triggered by loading a component directly by URL.
+// If the page exports a defined "layout", then load + render those first. "context", "slot:head",
+// and "slot:body" should all inherit from parent layouts, merging together in the correct order.
+export async function __renderPage({request, children}) {
+ const currentChild = {
+ __slothead,
+ __slotbody,
+ setup: typeof setup === 'undefined' ? (passthrough) => passthrough : setup,
+ layout: typeof layout === 'undefined' ? undefined : layout,
};
-}
-
-export async function compileComponent(
- source: string,
- { compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
-): Promise<CompileResult> {
- const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
-
- // throw error if <Component /> missing
- if (!sourceJsx.items.find(({ name }) => name === 'Component')) throw new Error(`${filename} <Component> expected!`);
- // sort <style> tags first
- // TODO: remove these and inject in <head>
- sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0));
+ // find all layouts, going up the layout chain.
+ if (currentChild.layout) {
+ const layoutComponent = (await import('/_hmx/layouts/' + layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js')));
+ return layoutComponent.__renderPage({
+ request,
+ children: [currentChild, ...children],
+ });
+ }
+
+ const isRoot = true;
+ const merge = (await import('deepmerge')).default;
+
+ // call all children setup scripts, in order, and return.
+ let mergedContext = {};
+ for (const child of [currentChild, ...children]) {
+ const childSetupResult = await child.setup({request, context: mergedContext});
+ mergedContext = childSetupResult.context ? merge(mergedContext, childSetupResult.context) : mergedContext;
+ }
+
+ Object.freeze(mergedContext);
+
+ let headResult;
+ let bodyResult;
+ for (const child of children.reverse()) {
+ headResult = await child.__slothead(mergedContext, headResult);
+ bodyResult = await child.__slotbody(mergedContext, bodyResult);
+ }
+ return h(Fragment, null, [
+ h("head", null, currentChild.__slothead(mergedContext, headResult)),
+ h("body", null, currentChild.__slotbody(mergedContext, bodyResult)),
+ ]);
+};\n`;
+ }
- // return template
- const modJsx = `
- import { h, Fragment } from '${internalImport('h.js')}';
- export default function(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); }
- `.trim();
return {
+ result: sourceJsx,
contents: modJsx,
};
}
diff --git a/test/fixtures/hmx-basic/astro/pages/index.hmx b/test/fixtures/hmx-basic/astro/pages/index.hmx
index a8ea2678a..035760ddb 100644
--- a/test/fixtures/hmx-basic/astro/pages/index.hmx
+++ b/test/fixtures/hmx-basic/astro/pages/index.hmx
@@ -1,4 +1,4 @@
-<script hmx="setup">
+<script astro>
export function setup() {
return {
props: {}
@@ -6,10 +6,10 @@
}
</script>
-<head>
+<slot:head>
<!-- Head Stuff -->
-</head>
+</slot:head>
-<body>
+<slot:body>
<h1>Hello world!</h1>
-</body> \ No newline at end of file
+</slot:body> \ No newline at end of file