summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/nodejs.yml4
-rw-r--r--examples/snowpack/snowpack.config.js6
-rw-r--r--src/dev.ts7
-rw-r--r--src/micromark-encode.ts35
-rw-r--r--src/transform2.ts29
-rw-r--r--test/fixtures/hmx-markdown/astro.config.mjs9
-rw-r--r--test/fixtures/hmx-markdown/astro/components/Example.jsx5
-rw-r--r--test/fixtures/hmx-markdown/astro/layouts/content.hmx3
-rw-r--r--test/fixtures/hmx-markdown/astro/pages/index.hmx13
-rw-r--r--test/fixtures/hmx-markdown/astro/pages/post.md13
-rw-r--r--test/fixtures/hmx-markdown/snowpack.config.js5
-rw-r--r--test/hmx-markdown.test.js45
-rw-r--r--test/react-component.test.js8
-rw-r--r--test/snowpack-integration.test.js8
14 files changed, 171 insertions, 19 deletions
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index b89978663..1890b86fe 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -19,6 +19,10 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: npm install, build, and test
run: |
+ cd examples/snowpack
+ npm ci
+ cd ../..
+
npm ci
npm run build
npm test
diff --git a/examples/snowpack/snowpack.config.js b/examples/snowpack/snowpack.config.js
index e85a9d7b2..821552181 100644
--- a/examples/snowpack/snowpack.config.js
+++ b/examples/snowpack/snowpack.config.js
@@ -10,11 +10,7 @@ module.exports = {
'@snowpack/plugin-svelte',
'@snowpack/plugin-vue',
],
- packageOptions: {
- external: [
- 'node-fetch'
- ]
- },
+ packageOptions: {},
buildOptions: {
out: '_site',
},
diff --git a/src/dev.ts b/src/dev.ts
index 93a890057..c6ad9ff7c 100644
--- a/src/dev.ts
+++ b/src/dev.ts
@@ -57,6 +57,8 @@ export default async function (astroConfig: AstroConfig) {
break;
}
}
+ res.statusCode = 500;
+ res.end(formatErrorForBrowser(result.error));
break;
}
}
@@ -66,3 +68,8 @@ export default async function (astroConfig: AstroConfig) {
console.log(`Server running at http://${hostname}:${port}/`);
});
}
+
+function formatErrorForBrowser(error: Error) {
+ // TODO make this pretty.
+ return error.toString();
+} \ No newline at end of file
diff --git a/src/micromark-encode.ts b/src/micromark-encode.ts
new file mode 100644
index 000000000..d205d13e3
--- /dev/null
+++ b/src/micromark-encode.ts
@@ -0,0 +1,35 @@
+import type { HtmlExtension, Token, Tokenize } 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] + ';';
+ });
+}
+
+function encodeToken(this: Record<string, () => void>) {
+ 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));
+}
+
+const plugin: HtmlExtension = {
+ exit: {
+ codeTextData: encodeToken,
+ codeFlowValue: encodeToken,
+ },
+};
+
+export { plugin as encodeMarkdown }; \ No newline at end of file
diff --git a/src/transform2.ts b/src/transform2.ts
index 2f1e651cf..42a151b3c 100644
--- a/src/transform2.ts
+++ b/src/transform2.ts
@@ -8,6 +8,7 @@ import gfmHtml from 'micromark-extension-gfm/html.js';
import { CompileResult, TransformResult } from './@types/astro';
import { parse } from './compiler/index.js';
import { createMarkdownHeadersCollector } from './micromark-collect-headers.js';
+import { encodeMarkdown } from './micromark-encode.js';
import { defaultLogOptions } from './logger.js';
import { optimize } from './optimize/index.js';
import { codegen } from './codegen/index.js';
@@ -54,8 +55,9 @@ async function convertMdToJsx(
const { data: _frontmatterData, content } = matter(contents);
const { headers, headersExtension } = createMarkdownHeadersCollector();
const mdHtml = micromark(content, {
+ allowDangerousHtml: true,
extensions: [gfmSyntax()],
- htmlExtensions: [gfmHtml, headersExtension],
+ htmlExtensions: [gfmHtml, encodeMarkdown, headersExtension],
});
const setupContext = {
@@ -68,19 +70,26 @@ async function convertMdToJsx(
},
};
+ let imports = '';
+ for(let [ComponentName, specifier] of Object.entries(_frontmatterData.import || {})) {
+ imports += `import ${ComponentName} from '${specifier}';\n`;
+ }
+
// </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 astro>
- ${_frontmatterData.layout ? `export const layout = ${JSON.stringify(_frontmatterData.layout)};` : ''}
- export function setup({context}) {
- return {context: ${stringifiedSetupContext} };
- }
- </script><section>{${JSON.stringify(mdHtml)}}</section>`,
- { compileOptions, filename, fileID }
- );
+ const raw = `<script astro>
+ ${imports}
+ ${_frontmatterData.layout ? `export const layout = ${JSON.stringify(_frontmatterData.layout)};` : ''}
+ export function setup({context}) {
+ return {context: ${stringifiedSetupContext} };
+ }
+</script><section>${mdHtml}</section>`;
+
+ const convertOptions = { compileOptions, filename, fileID };
+
+ return convertHmxToJsx(raw, convertOptions);
}
async function transformFromSource(
diff --git a/test/fixtures/hmx-markdown/astro.config.mjs b/test/fixtures/hmx-markdown/astro.config.mjs
new file mode 100644
index 000000000..0f0be4b94
--- /dev/null
+++ b/test/fixtures/hmx-markdown/astro.config.mjs
@@ -0,0 +1,9 @@
+
+export default {
+ projectRoot: '.',
+ hmxRoot: './astro',
+ dist: './_site',
+ extensions: {
+ '.jsx': 'preact'
+ }
+} \ No newline at end of file
diff --git a/test/fixtures/hmx-markdown/astro/components/Example.jsx b/test/fixtures/hmx-markdown/astro/components/Example.jsx
new file mode 100644
index 000000000..57bde3a95
--- /dev/null
+++ b/test/fixtures/hmx-markdown/astro/components/Example.jsx
@@ -0,0 +1,5 @@
+import { h } from 'preact';
+
+export default function() {
+ return <div id="test">Testing</div>
+} \ No newline at end of file
diff --git a/test/fixtures/hmx-markdown/astro/layouts/content.hmx b/test/fixtures/hmx-markdown/astro/layouts/content.hmx
new file mode 100644
index 000000000..52f79400c
--- /dev/null
+++ b/test/fixtures/hmx-markdown/astro/layouts/content.hmx
@@ -0,0 +1,3 @@
+<div class="container">
+ <slot></slot>
+</div> \ No newline at end of file
diff --git a/test/fixtures/hmx-markdown/astro/pages/index.hmx b/test/fixtures/hmx-markdown/astro/pages/index.hmx
new file mode 100644
index 000000000..19f888e04
--- /dev/null
+++ b/test/fixtures/hmx-markdown/astro/pages/index.hmx
@@ -0,0 +1,13 @@
+<script astro>
+ export function setup() {
+ return {
+ props: {}
+ }
+ }
+</script>
+
+<astro:head>
+ <!-- Head Stuff -->
+</astro:head>
+
+<h1>Hello world!</h1> \ No newline at end of file
diff --git a/test/fixtures/hmx-markdown/astro/pages/post.md b/test/fixtures/hmx-markdown/astro/pages/post.md
new file mode 100644
index 000000000..057b1febb
--- /dev/null
+++ b/test/fixtures/hmx-markdown/astro/pages/post.md
@@ -0,0 +1,13 @@
+---
+layout: layouts/content.hmx
+title: My Blog Post
+description: This is a post about some stuff.
+import:
+ Example: '../components/Example.jsx'
+---
+
+## Interesting Topic
+
+<div id="first">Some content</div>
+
+<Example /> \ No newline at end of file
diff --git a/test/fixtures/hmx-markdown/snowpack.config.js b/test/fixtures/hmx-markdown/snowpack.config.js
new file mode 100644
index 000000000..2cbf0ef07
--- /dev/null
+++ b/test/fixtures/hmx-markdown/snowpack.config.js
@@ -0,0 +1,5 @@
+export default {
+ mount: {
+
+ }
+};
diff --git a/test/hmx-markdown.test.js b/test/hmx-markdown.test.js
new file mode 100644
index 000000000..1a3a2e11c
--- /dev/null
+++ b/test/hmx-markdown.test.js
@@ -0,0 +1,45 @@
+import { suite } from 'uvu';
+import * as assert from 'uvu/assert';
+import { createRuntime } from '../lib/runtime.js';
+import { loadConfig } from '../lib/config.js';
+import { doc } from './test-utils.js';
+
+const HMXMD = suite('HMX Markdown');
+
+let runtime, setupError;
+
+HMXMD.before(async () => {
+ const astroConfig = await loadConfig(new URL('./fixtures/hmx-markdown', import.meta.url).pathname);
+
+ const logging = {
+ level: 'error',
+ dest: process.stderr
+ };
+
+ try {
+ runtime = await createRuntime(astroConfig, logging);
+ } catch(err) {
+ console.error(err);
+ setupError = err;
+ }
+});
+
+HMXMD.after(async () => {
+ runtime && runtime.shutdown();
+});
+
+HMXMD('No errors creating a runtime', () => {
+ assert.equal(setupError, undefined);
+});
+
+HMXMD('Can load markdown pages with hmx', async () => {
+ const result = await runtime.load('/post');
+
+ assert.equal(result.statusCode, 200);
+
+ const $ = doc(result.contents);
+ assert.ok($('#first').length, 'There is a div added in markdown');
+ assert.ok($('#test').length, 'There is a div added via a component from markdown');
+});
+
+HMXMD.run(); \ No newline at end of file
diff --git a/test/react-component.test.js b/test/react-component.test.js
index 0b6273922..d901c62b0 100644
--- a/test/react-component.test.js
+++ b/test/react-component.test.js
@@ -6,7 +6,7 @@ import { doc } from './test-utils.js';
const React = suite('React Components');
-let runtime;
+let runtime, setupError;
React.before(async () => {
const astroConfig = await loadConfig(new URL('./fixtures/react-component', import.meta.url).pathname);
@@ -20,7 +20,7 @@ React.before(async () => {
runtime = await createRuntime(astroConfig, logging);
} catch(err) {
console.error(err);
- throw err;
+ setupError = err;
}
});
@@ -28,6 +28,10 @@ React.after(async () => {
await runtime.shutdown();
});
+React('No error creating the runtime', () => {
+ assert.equal(setupError, undefined);
+});
+
React('Can load hmx page', async () => {
const result = await runtime.load('/');
diff --git a/test/snowpack-integration.test.js b/test/snowpack-integration.test.js
index 8547ee7cd..033f5587d 100644
--- a/test/snowpack-integration.test.js
+++ b/test/snowpack-integration.test.js
@@ -10,7 +10,7 @@ const { readdir, stat } = fsPromises;
const SnowpackDev = suite('snowpack.dev');
-let runtime, cwd;
+let runtime, cwd, setupError;
SnowpackDev.before(async () => {
// Bug: Snowpack config is still loaded relative to the current working directory.
@@ -28,7 +28,7 @@ SnowpackDev.before(async () => {
runtime = await createRuntime(astroConfig, logging);
} catch(err) {
console.error(err);
- throw err;
+ setupError = err;
}
});
@@ -58,6 +58,10 @@ async function* allPages(root) {
}
}
+SnowpackDev('No error creating the runtime', () => {
+ assert.equal(setupError, undefined);
+});
+
SnowpackDev('Can load every page', async () => {
const failed = [];