summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown.md8
-rw-r--r--examples/remote-markdown/src/components/Yell.jsx7
-rw-r--r--packages/astro-parser/src/parse/state/codefence.ts2
-rw-r--r--packages/astro-parser/src/parse/state/codespan.ts5
-rw-r--r--packages/astro/src/compiler/codegen/index.ts62
-rw-r--r--packages/astro/src/compiler/index.ts12
-rw-r--r--packages/astro/src/compiler/markdown/micromark.d.ts6
-rw-r--r--packages/astro/src/compiler/markdown/rehype-collect-headers.ts10
-rw-r--r--packages/astro/src/compiler/markdown/remark-mdx-lite.ts16
-rw-r--r--packages/astro/src/compiler/markdown/remark-scoped-styles.ts4
-rw-r--r--packages/astro/src/compiler/transform/styles.ts2
-rw-r--r--packages/astro/src/compiler/utils.ts11
-rw-r--r--packages/astro/src/frontend/markdown.ts22
-rw-r--r--packages/astro/src/frontend/render/renderer.ts10
-rw-r--r--packages/astro/src/frontend/render/utils.ts2
-rw-r--r--packages/astro/src/runtime.ts6
-rw-r--r--packages/astro/src/search.ts2
-rw-r--r--packages/astro/test/astro-markdown.test.js1
-rw-r--r--packages/astro/test/plain-markdown.test.js1
-rw-r--r--tools/astro-vscode/languages/astro-markdown-language-configuration.json12
20 files changed, 102 insertions, 99 deletions
diff --git a/docs/markdown.md b/docs/markdown.md
index ceeb0b515..116f807a6 100644
--- a/docs/markdown.md
+++ b/docs/markdown.md
@@ -17,6 +17,7 @@ Astro treats any `.md` files inside of the `/src/pages` directory as pages. Thes
The only special Frontmatter key is `layout`, which defines the relative path to a `.astro` component which should wrap your Markdown content.
`src/pages/index.md`
+
```md
---
layout: ../layouts/main.astro
@@ -30,6 +31,7 @@ Layout files are normal `.astro` components. Any Frontmatter defined in your `.m
The rendered Markdown content is placed into the default `<slot />` element.
`src/layouts/main.astro`
+
```jsx
---
export let content;
@@ -52,7 +54,7 @@ Similar to tools like [MDX](https://mdxjs.com/) or [MDsveX](https://github.com/p
Astro exposes a special `Markdown` component for `.astro` files which enables markdown syntax for its children **recursively**. Within the `Markdown` component you may also use plain HTML or any other type of component that is supported by Astro.
-```jsx
+````jsx
---
// For now, this import _must_ be named "Markdown" and _must not_ be wrapped with a custom component
// We're working on easing these restrictions!
@@ -91,7 +93,7 @@ const expressions = 'Lorem ipsum';
</MyFancyCodePreview:visible>
</Markdown>
</Layout>
-```
+````
### Remote Markdown
@@ -111,7 +113,7 @@ const content = await fetch('https://raw.githubusercontent.com/snowpackjs/snowpa
### Security FAQs
-**Aren't there security concerns to rendering remote markdown directly to HTML?**
+**Aren't there security concerns to rendering remote markdown directly to HTML?**
Yes! Just like with regular HTML, improper use the `<Markdown>` component can open you up to a [cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) attack. If you are rendering untrusted content, be sure to _santize your content **before** rendering it_.
diff --git a/examples/remote-markdown/src/components/Yell.jsx b/examples/remote-markdown/src/components/Yell.jsx
index ae7d0d959..366d88a95 100644
--- a/examples/remote-markdown/src/components/Yell.jsx
+++ b/examples/remote-markdown/src/components/Yell.jsx
@@ -1,5 +1,10 @@
import { h, Fragment } from 'preact';
export default function Yell({ children }) {
- return children.filter(v => typeof v === 'string').join('').toUpperCase() + '!'
+ return (
+ children
+ .filter((v) => typeof v === 'string')
+ .join('')
+ .toUpperCase() + '!'
+ );
}
diff --git a/packages/astro-parser/src/parse/state/codefence.ts b/packages/astro-parser/src/parse/state/codefence.ts
index d5b498a0f..72867867c 100644
--- a/packages/astro-parser/src/parse/state/codefence.ts
+++ b/packages/astro-parser/src/parse/state/codefence.ts
@@ -23,7 +23,7 @@ export default function codefence(parser: Parser) {
type: 'CodeFence',
raw: `${raw}` + trailingWhitespace,
metadata,
- data
+ data,
};
parser.current().children.push(node);
diff --git a/packages/astro-parser/src/parse/state/codespan.ts b/packages/astro-parser/src/parse/state/codespan.ts
index b685800a7..7f4b3354a 100644
--- a/packages/astro-parser/src/parse/state/codespan.ts
+++ b/packages/astro-parser/src/parse/state/codespan.ts
@@ -18,7 +18,10 @@ export default function codespan(parser: Parser) {
end: parser.index,
type: 'CodeSpan',
raw,
- data: raw?.slice(open?.length, open?.length * -1).replace(/^ /, '').replace(/ $/, '')
+ data: raw
+ ?.slice(open?.length, open?.length * -1)
+ .replace(/^ /, '')
+ .replace(/ $/, ''),
};
parser.current().children.push(node);
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index ab66ee47d..64d7c1822 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -306,7 +306,7 @@ interface CodegenState {
components: Components;
css: string[];
markers: {
- insideMarkdown: boolean|string;
+ insideMarkdown: boolean | string;
};
importExportStatements: Set<string>;
dynamicImports: DynamicImportMap;
@@ -583,41 +583,41 @@ function compileHtml(enterNode: TemplateNode, state: CodegenState, compileOption
try {
const attributes = getAttributes(node.attributes);
- outSource += outSource === '' ? '' : ',';
- if (node.type === 'Slot') {
- outSource += `(children`;
- return;
- }
- const COMPONENT_NAME_SCANNER = /^[A-Z]/;
- if (!COMPONENT_NAME_SCANNER.test(name)) {
- outSource += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
- if (state.markers.insideMarkdown) {
- outSource += `,h(__astroMarkdownRender, null`
+ outSource += outSource === '' ? '' : ',';
+ if (node.type === 'Slot') {
+ outSource += `(children`;
+ return;
}
- return;
- }
- const [componentName, componentKind] = name.split(':');
- const componentImportData = components[componentName];
- if (!componentImportData) {
- throw new Error(`Unknown Component: ${componentName}`);
- }
- if (componentImportData.type === '.astro') {
- if (componentName === 'Markdown') {
- const attributeStr = attributes ? generateAttributes(attributes) : 'null';
- state.markers.insideMarkdown = attributeStr;
- outSource += `h(__astroMarkdownRender, ${attributeStr}`
+ const COMPONENT_NAME_SCANNER = /^[A-Z]/;
+ if (!COMPONENT_NAME_SCANNER.test(name)) {
+ outSource += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
+ if (state.markers.insideMarkdown) {
+ outSource += `,h(__astroMarkdownRender, null`;
+ }
return;
}
- }
- const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], { astroConfig, dynamicImports, filename });
- if (wrapperImport) {
- importExportStatements.add(wrapperImport);
- }
+ const [componentName, componentKind] = name.split(':');
+ const componentImportData = components[componentName];
+ if (!componentImportData) {
+ throw new Error(`Unknown Component: ${componentName}`);
+ }
+ if (componentImportData.type === '.astro') {
+ if (componentName === 'Markdown') {
+ const attributeStr = attributes ? generateAttributes(attributes) : 'null';
+ state.markers.insideMarkdown = attributeStr;
+ outSource += `h(__astroMarkdownRender, ${attributeStr}`;
+ return;
+ }
+ }
+ const { wrapper, wrapperImport } = getComponentWrapper(name, components[componentName], { astroConfig, dynamicImports, filename });
+ if (wrapperImport) {
+ importExportStatements.add(wrapperImport);
+ }
outSource += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`;
if (state.markers.insideMarkdown) {
const attributeStr = state.markers.insideMarkdown;
- outSource += `,h(__astroMarkdownRender, ${attributeStr}`
+ outSource += `,h(__astroMarkdownRender, ${attributeStr}`;
}
} catch (err) {
// handle errors in scope with filename
@@ -710,10 +710,10 @@ export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOpt
components: {},
css: [],
markers: {
- insideMarkdown: false
+ insideMarkdown: false,
},
importExportStatements: new Set(),
- dynamicImports: new Map()
+ dynamicImports: new Map(),
};
const { script, componentPlugins, createCollection } = compileModule(ast.module, state, compileOptions);
diff --git a/packages/astro/src/compiler/index.ts b/packages/astro/src/compiler/index.ts
index afdaac986..0eef6b5cd 100644
--- a/packages/astro/src/compiler/index.ts
+++ b/packages/astro/src/compiler/index.ts
@@ -48,13 +48,17 @@ async function convertAstroToJsx(template: string, opts: ConvertAstroOptions): P
* .md -> .astro source
*/
export async function convertMdToAstroSource(contents: string, { filename }: { filename: string }): Promise<string> {
- const { content, frontmatter: { layout, ...frontmatter }, ...data } = await renderMarkdownWithFrontmatter(contents);
+ const {
+ content,
+ frontmatter: { layout, ...frontmatter },
+ ...data
+ } = await renderMarkdownWithFrontmatter(contents);
if (frontmatter['astro'] !== undefined) {
throw new Error(`"astro" is a reserved word but was used as a frontmatter value!\n\tat ${filename}`);
}
const contentData: any = {
...frontmatter,
- ...data
+ ...data,
};
// </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.
@@ -75,7 +79,7 @@ async function convertMdToJsx(
contents: string,
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
): Promise<TransformResult> {
-const raw = await convertMdToAstroSource(contents, { filename });
+ const raw = await convertMdToAstroSource(contents, { filename });
const convertOptions = { compileOptions, filename, fileID };
return await convertAstroToJsx(raw, convertOptions);
}
@@ -105,7 +109,7 @@ export async function compileComponent(
): Promise<CompileResult> {
const result = await transformFromSource(source, { compileOptions, filename, projectRoot });
const site = compileOptions.astroConfig.buildOptions.site || `http://localhost:${compileOptions.astroConfig.devOptions.port}`;
- const usesMarkdown = !!result.imports.find(spec => spec.indexOf('Markdown') > -1);
+ const usesMarkdown = !!result.imports.find((spec) => spec.indexOf('Markdown') > -1);
// return template
let modJsx = `
diff --git a/packages/astro/src/compiler/markdown/micromark.d.ts b/packages/astro/src/compiler/markdown/micromark.d.ts
index 9c084f437..245b91fc1 100644
--- a/packages/astro/src/compiler/markdown/micromark.d.ts
+++ b/packages/astro/src/compiler/markdown/micromark.d.ts
@@ -1,11 +1,11 @@
-declare module '@silvenon/remark-smartypants' {
+declare module '@silvenon/remark-smartypants' {
export default function (): any;
}
-declare module 'mdast-util-mdx/from-markdown.js' {
+declare module 'mdast-util-mdx/from-markdown.js' {
export default function (): any;
}
-declare module 'mdast-util-mdx/to-markdown.js' {
+declare module 'mdast-util-mdx/to-markdown.js' {
export default function (): any;
}
diff --git a/packages/astro/src/compiler/markdown/rehype-collect-headers.ts b/packages/astro/src/compiler/markdown/rehype-collect-headers.ts
index 3ebf3257d..edfcd29bc 100644
--- a/packages/astro/src/compiler/markdown/rehype-collect-headers.ts
+++ b/packages/astro/src/compiler/markdown/rehype-collect-headers.ts
@@ -7,16 +7,16 @@ export default function createCollectHeaders() {
const visitor = (node: any) => {
if (node.type !== 'element') return;
- const { tagName, children } = node
+ const { tagName, children } = node;
if (tagName[0] !== 'h') return;
let [_, depth] = tagName.match(/h([0-6])/) ?? [];
if (!depth) return;
depth = Number.parseInt(depth);
-
+
let text = '';
visit(node, 'text', (child) => {
text += child.value;
- })
+ });
let slug = slugger.slug(text);
node.properties = node.properties || {};
@@ -24,7 +24,7 @@ export default function createCollectHeaders() {
headers.push({ depth, slug, text });
return node;
- }
+ };
- return { headers, rehypeCollectHeaders: () => (tree: any) => visit(tree, visitor) }
+ return { headers, rehypeCollectHeaders: () => (tree: any) => visit(tree, visitor) };
}
diff --git a/packages/astro/src/compiler/markdown/remark-mdx-lite.ts b/packages/astro/src/compiler/markdown/remark-mdx-lite.ts
index 27eed917e..9ab8d764f 100644
--- a/packages/astro/src/compiler/markdown/remark-mdx-lite.ts
+++ b/packages/astro/src/compiler/markdown/remark-mdx-lite.ts
@@ -2,24 +2,24 @@ import fromMarkdown from 'mdast-util-mdx/from-markdown.js';
import toMarkdown from 'mdast-util-mdx/to-markdown.js';
/** See https://github.com/micromark/micromark-extension-mdx-md */
-const syntax = { disable: {null: ['autolink', 'codeIndented']} };
+const syntax = { disable: { null: ['autolink', 'codeIndented'] } };
-/**
+/**
* Lite version of https://github.com/mdx-js/mdx/tree/main/packages/remark-mdx
* We don't need all the features MDX does because all components are precompiled
* to HTML. We just want to disable a few MD features that cause issues.
*/
-function mdxLite (this: any) {
- let data = this.data()
+function mdxLite(this: any) {
+ let data = this.data();
add('micromarkExtensions', syntax);
- add('fromMarkdownExtensions', fromMarkdown)
- add('toMarkdownExtensions', toMarkdown)
+ add('fromMarkdownExtensions', fromMarkdown);
+ add('toMarkdownExtensions', toMarkdown);
/** Adds remark plugin */
function add(field: string, value: any) {
- if (data[field]) data[field].push(value)
- else data[field] = [value]
+ if (data[field]) data[field].push(value);
+ else data[field] = [value];
}
}
diff --git a/packages/astro/src/compiler/markdown/remark-scoped-styles.ts b/packages/astro/src/compiler/markdown/remark-scoped-styles.ts
index 9e2c8c290..7d19ae0ee 100644
--- a/packages/astro/src/compiler/markdown/remark-scoped-styles.ts
+++ b/packages/astro/src/compiler/markdown/remark-scoped-styles.ts
@@ -6,13 +6,13 @@ export default function scopedStyles(className: string) {
const visitor = (node: any) => {
if (noVisit.has(node.type)) return;
- const {data} = node
+ const { data } = node;
const currentClassName = data?.hProperties?.class ?? '';
node.data = node.data || {};
node.data.hProperties = node.data.hProperties || {};
node.data.hProperties.className = `${className} ${currentClassName}`.trim();
return node;
- }
+ };
return () => (tree: any) => visit(tree, visitor);
}
diff --git a/packages/astro/src/compiler/transform/styles.ts b/packages/astro/src/compiler/transform/styles.ts
index 10d9158a0..ab1d75ce2 100644
--- a/packages/astro/src/compiler/transform/styles.ts
+++ b/packages/astro/src/compiler/transform/styles.ts
@@ -214,7 +214,7 @@ export default function transformStyles({ compileOptions, filename, fileID }: Tr
enter(node) {
if (node.name !== 'Markdown') return;
injectScopedClassAttribute(node, scopedClass, '$scope');
- }
+ },
},
Element: {
enter(node) {
diff --git a/packages/astro/src/compiler/utils.ts b/packages/astro/src/compiler/utils.ts
index 701dc2adf..0fbc070f1 100644
--- a/packages/astro/src/compiler/utils.ts
+++ b/packages/astro/src/compiler/utils.ts
@@ -18,13 +18,10 @@ export interface MarkdownRenderingOptions {
}
/** Internal utility for rendering a full markdown file and extracting Frontmatter data */
-export async function renderMarkdownWithFrontmatter(contents: string, opts?: MarkdownRenderingOptions|null) {
+export async function renderMarkdownWithFrontmatter(contents: string, opts?: MarkdownRenderingOptions | null) {
// Dynamic import to ensure that "gray-matter" isn't built by Snowpack
const { default: matter } = await import('gray-matter');
- const {
- data: frontmatter,
- content,
- } = matter(contents);
+ const { data: frontmatter, content } = matter(contents);
const value = await renderMarkdown(content, opts);
return { ...value, frontmatter };
}
@@ -41,12 +38,12 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp
}
if (useGfm) {
- const {default:gfm} = await import('remark-gfm');
+ const { default: gfm } = await import('remark-gfm');
parser = parser.use(gfm);
}
if (useFootnotes) {
- const {default:footnotes} = await import('remark-footnotes');
+ const { default: footnotes } = await import('remark-footnotes');
parser = parser.use(footnotes);
}
diff --git a/packages/astro/src/frontend/markdown.ts b/packages/astro/src/frontend/markdown.ts
index 8fb013d76..2cae2a65b 100644
--- a/packages/astro/src/frontend/markdown.ts
+++ b/packages/astro/src/frontend/markdown.ts
@@ -1,14 +1,14 @@
import { renderMarkdown } from '../compiler/utils.js';
-/**
- * Functional component which uses Astro's built-in Markdown rendering
- * to render out its children.
- *
- * Note: the children have already been properly escaped/rendered
- * by the parser and Astro, so at this point we're just rendering
- * out plain markdown, no need for JSX support
- */
-export default async function Markdown(props: { $scope: string|null }, ...children: string[]): Promise<string> {
+/**
+ * Functional component which uses Astro's built-in Markdown rendering
+ * to render out its children.
+ *
+ * Note: the children have already been properly escaped/rendered
+ * by the parser and Astro, so at this point we're just rendering
+ * out plain markdown, no need for JSX support
+ */
+export default async function Markdown(props: { $scope: string | null }, ...children: string[]): Promise<string> {
const { $scope = null } = props ?? {};
const text = dedent(children.join('').trimEnd());
let { content } = await renderMarkdown(text, { $: { scopedClassName: $scope } });
@@ -21,6 +21,6 @@ export default async function Markdown(props: { $scope: string|null }, ...childr
/** Remove leading indentation based on first line */
function dedent(str: string) {
let arr = str.match(/^[ \t]*(?=\S)/gm);
- let first = !!arr && arr.find(x => x.length > 0)?.length;
- return (!arr || !first) ? str : str.replace(new RegExp(`^[ \\t]{0,${first}}`, 'gm'), '');
+ let first = !!arr && arr.find((x) => x.length > 0)?.length;
+ return !arr || !first ? str : str.replace(new RegExp(`^[ \\t]{0,${first}}`, 'gm'), '');
}
diff --git a/packages/astro/src/frontend/render/renderer.ts b/packages/astro/src/frontend/render/renderer.ts
index 86d74fa84..a7f6d165d 100644
--- a/packages/astro/src/frontend/render/renderer.ts
+++ b/packages/astro/src/frontend/render/renderer.ts
@@ -39,11 +39,11 @@ export function createRenderer(renderer: SupportedComponentRenderer) {
const script = `${typeof wrapperStart === 'function' ? wrapperStart(innerContext) : wrapperStart}
${_imports(renderContext)}
${renderer.render({
- ...innerContext,
- props: serializeProps(props),
- children: `[${childrenToH(renderer, children) ?? ''}]`,
- childrenAsString: `\`${children}\``,
- })}
+ ...innerContext,
+ props: serializeProps(props),
+ children: `[${childrenToH(renderer, children) ?? ''}]`,
+ childrenAsString: `\`${children}\``,
+})}
${typeof wrapperEnd === 'function' ? wrapperEnd(innerContext) : wrapperEnd}`;
return [value, `<script type="module">${script.trim()}</script>`].join('\n');
diff --git a/packages/astro/src/frontend/render/utils.ts b/packages/astro/src/frontend/render/utils.ts
index 29eaf64b5..64a712561 100644
--- a/packages/astro/src/frontend/render/utils.ts
+++ b/packages/astro/src/frontend/render/utils.ts
@@ -42,7 +42,7 @@ export const childrenToH = moize.deep(function childrenToH(renderer: ComponentRe
const simpleTypes = new Set(['number', 'boolean']);
const serializeChild = (child: unknown) => {
- if (typeof child === 'string') return JSON.stringify(child).replace(/<\/script>/gmi, '</script" + ">');
+ if (typeof child === 'string') return JSON.stringify(child).replace(/<\/script>/gim, '</script" + ">');
if (simpleTypes.has(typeof child)) return JSON.stringify(child);
if (child === null) return `null`;
if ((child as any).__SERIALIZED) return (child as any).__SERIALIZED;
diff --git a/packages/astro/src/runtime.ts b/packages/astro/src/runtime.ts
index 1eabbd364..965ea641a 100644
--- a/packages/astro/src/runtime.ts
+++ b/packages/astro/src/runtime.ts
@@ -314,11 +314,7 @@ async function createSnowpack(astroConfig: AstroConfig, options: CreateSnowpackO
},
packageOptions: {
knownEntrypoints: ['preact-render-to-string'],
- external: [
- '@vue/server-renderer',
- 'node-fetch',
- 'prismjs/components/index.js'
- ],
+ external: ['@vue/server-renderer', 'node-fetch', 'prismjs/components/index.js'],
},
});
diff --git a/packages/astro/src/search.ts b/packages/astro/src/search.ts
index 84a2ee634..20f600d31 100644
--- a/packages/astro/src/search.ts
+++ b/packages/astro/src/search.ts
@@ -45,7 +45,7 @@ export function searchForPage(url: URL, astroRoot: URL): SearchResult {
// Try to find index.astro/md paths
if (reqPath.endsWith('/')) {
- const candidates = [`${base}index.astro`, `${base}index.md`,];
+ const candidates = [`${base}index.astro`, `${base}index.md`];
const location = findAnyPage(candidates, astroRoot);
if (location) {
return {
diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js
index f531ad2e5..edc18c576 100644
--- a/packages/astro/test/astro-markdown.test.js
+++ b/packages/astro/test/astro-markdown.test.js
@@ -8,7 +8,6 @@ const Markdown = suite('Astro Markdown tests');
setup(Markdown, './fixtures/astro-markdown');
setupBuild(Markdown, './fixtures/astro-markdown');
-
Markdown('Can load markdown pages with Astro', async ({ runtime }) => {
const result = await runtime.load('/post');
if (result.error) throw new Error(result.error);
diff --git a/packages/astro/test/plain-markdown.test.js b/packages/astro/test/plain-markdown.test.js
index 8e2f1a2ec..3adc904f5 100644
--- a/packages/astro/test/plain-markdown.test.js
+++ b/packages/astro/test/plain-markdown.test.js
@@ -34,5 +34,4 @@ Markdown('Builds markdown pages for prod', async (context) => {
await context.build();
});
-
Markdown.run();
diff --git a/tools/astro-vscode/languages/astro-markdown-language-configuration.json b/tools/astro-vscode/languages/astro-markdown-language-configuration.json
index 1ee3bf7e2..c3242cb3b 100644
--- a/tools/astro-vscode/languages/astro-markdown-language-configuration.json
+++ b/tools/astro-vscode/languages/astro-markdown-language-configuration.json
@@ -16,13 +16,11 @@
{ "open": "'", "close": "'" },
{ "open": "\"", "close": "\"" },
{
- "open": "<",
- "close": ">",
- "notIn": [
- "string"
- ]
- },
- { "open": "<!--", "close": "-->", "notIn": ["comment", "string"] },
+ "open": "<",
+ "close": ">",
+ "notIn": ["string"]
+ },
+ { "open": "<!--", "close": "-->", "notIn": ["comment", "string"] }
],
"autoCloseBefore": ";:.,=}])>` \n\t",
"surroundingPairs": [