Remove legacy.astroFlavoredMarkdown (#5771)

* Remove legacy.astroFlavoredMarkdown

* update vue mdx test

* Add a changeset
This commit is contained in:
Matthew Phillips 2023-01-05 16:20:40 -05:00 committed by GitHub
parent 9ef0c50427
commit 259a539d7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
109 changed files with 15 additions and 1870 deletions

View file

@ -0,0 +1,9 @@
---
'astro': major
---
Removes support for astroFlavoredMarkdown
In 1.0 Astro moved the old Astro Flavored Markdown (also sometimes called Components in Markdown) to a legacy feature. This change removes the `legacy.astroFlavoredMarkdown` option completely.
In 2.0 this feature will not be available in Astro at all. We recommend migration to MDX for those were still using this feature in 1.x.

View file

@ -3,8 +3,5 @@ import preact from '@astrojs/preact';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [preact({ compat: true })], integrations: [preact({ compat: true })],
}); });

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.jsx';
import PreactComponent from '../components/JSXComponent.jsx';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<PreactComponent id="client-only" client:only="preact" />

View file

@ -4,8 +4,5 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [preact(), mdx()], integrations: [preact(), mdx()],
}); });

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.jsx';
import PreactComponent from '../components/JSXComponent.jsx';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<PreactComponent id="client-only" client:only="preact" />

View file

@ -4,8 +4,5 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [react(), mdx()], integrations: [react(), mdx()],
}); });

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.jsx';
import ReactComponent from '../components/JSXComponent.jsx';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<ReactComponent id="client-only" client:only="react" />

View file

@ -4,8 +4,5 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [solid(), mdx()], integrations: [solid(), mdx()],
}); });

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.jsx';
import SolidComponent from '../components/SolidComponent.jsx';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<SolidComponent id="client-only" client:only="solid" />

View file

@ -4,8 +4,5 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [svelte(), mdx()], integrations: [svelte(), mdx()],
}); });

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.svelte';
import SvelteComponent from '../components/SvelteComponent.svelte';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<SvelteComponent id="client-only" client:only="svelte" />

View file

@ -4,9 +4,6 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [ integrations: [
mdx(), mdx(),
vue({ vue({

View file

@ -1,32 +0,0 @@
---
layout: ../components/Layout.astro
setup: |
import Counter from '../components/Counter.vue';
import VueComponent from '../components/VueComponent.vue';
const someProps = {
count: 0,
};
---
<Counter id="server-only" {...someProps}>
# Hello, server!
</Counter>
<Counter id="client-idle" {...someProps} client:idle>
# Hello, client:idle!
</Counter>
<Counter id="client-load" {...someProps} client:load>
# Hello, client:load!
</Counter>
<Counter id="client-visible" {...someProps} client:visible>
# Hello, client:visible!
</Counter>
<Counter id="client-media" {...someProps} client:media="(max-width: 50em)">
# Hello, client:media!
</Counter>
<VueComponent id="client-only" client:only="vue" />

View file

@ -14,11 +14,3 @@ test.describe('preact/compat components in Astro files', () => {
pageSourceFilePath: './src/pages/index.astro', pageSourceFilePath: './src/pages/index.astro',
}); });
}); });
test.describe('preact/compat components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});

View file

@ -15,14 +15,6 @@ test.describe('Preact components in Astro files', () => {
}); });
}); });
test.describe('Preact components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});
test.describe('Preact components in MDX files', () => { test.describe('Preact components in MDX files', () => {
createTests({ createTests({
...config, ...config,

View file

@ -16,14 +16,6 @@ test.describe('React components in Astro files', () => {
}); });
}); });
test.describe('React components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});
test.describe('React components in MDX files', () => { test.describe('React components in MDX files', () => {
createTests({ createTests({
...config, ...config,

View file

@ -15,14 +15,6 @@ test.describe('Solid components in Astro files', () => {
}); });
}); });
test.describe('Solid components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});
test.describe('Solid components in MDX files', () => { test.describe('Solid components in MDX files', () => {
createTests({ createTests({
...config, ...config,

View file

@ -16,14 +16,6 @@ test.describe('Svelte components in Astro files', () => {
}); });
}); });
test.describe('Svelte components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});
test.describe('Svelte components in MDX files', () => { test.describe('Svelte components in MDX files', () => {
createTests({ createTests({
...config, ...config,

View file

@ -16,14 +16,6 @@ test.describe('Vue components in Astro files', () => {
}); });
}); });
test.describe('Vue components in Markdown files', () => {
createTests({
...config,
pageUrl: '/markdown/',
pageSourceFilePath: './src/pages/markdown.md',
});
});
test.describe('Vue components in MDX files', () => { test.describe('Vue components in MDX files', () => {
createTests({ createTests({
...config, ...config,

View file

@ -870,30 +870,7 @@ export interface AstroUserConfig {
* These flags allow you to opt in to some deprecated or otherwise outdated behavior of Astro * These flags allow you to opt in to some deprecated or otherwise outdated behavior of Astro
* in the latest version, so that you can continue to upgrade and take advantage of new Astro releases. * in the latest version, so that you can continue to upgrade and take advantage of new Astro releases.
*/ */
legacy?: { legacy?: object;
/**
* @docs
* @name legacy.astroFlavoredMarkdown
* @type {boolean}
* @default `false`
* @version 1.0.0-rc.1
* @description
* Enable Astro's pre-v1.0 support for components and JSX expressions in `.md` (and alternative extensions for markdown files like ".markdown") Markdown files.
* In Astro `1.0.0-rc`, this original behavior was removed as the default, in favor of our new [MDX integration](https://docs.astro.build/en/guides/integrations-guide/mdx/).
*
* To enable this behavior, set `legacy.astroFlavoredMarkdown` to `true` in your [`astro.config.mjs` configuration file](https://docs.astro.build/en/guides/configuring-astro/#the-astro-config-file).
*
* ```js
* {
* legacy: {
* // Example: Add support for legacy Markdown features
* astroFlavoredMarkdown: true,
* },
* }
* ```
*/
astroFlavoredMarkdown?: boolean;
};
/** /**
* @docs * @docs

View file

@ -349,7 +349,6 @@ async function generatePath(
logging, logging,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections, isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },

View file

@ -210,7 +210,6 @@ function buildManifest(
base: settings.config.base, base: settings.config.base,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections, isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },

View file

@ -36,9 +36,7 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
...markdownConfigDefaults, ...markdownConfigDefaults,
}, },
vite: {}, vite: {},
legacy: { legacy: {},
astroFlavoredMarkdown: false,
},
experimental: { experimental: {
contentCollections: false, contentCollections: false,
}, },
@ -180,12 +178,7 @@ export const AstroConfigSchema = z.object({
.optional() .optional()
.default({}), .default({}),
legacy: z legacy: z
.object({ .object({})
astroFlavoredMarkdown: z
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.legacy.astroFlavoredMarkdown),
})
.optional() .optional()
.default({}), .default({}),
}); });

View file

@ -20,7 +20,6 @@ import htmlVitePlugin from '../vite-plugin-html/index.js';
import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js'; import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js';
import jsxVitePlugin from '../vite-plugin-jsx/index.js'; import jsxVitePlugin from '../vite-plugin-jsx/index.js';
import astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js'; import astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js';
import legacyMarkdownVitePlugin from '../vite-plugin-markdown-legacy/index.js';
import markdownVitePlugin from '../vite-plugin-markdown/index.js'; import markdownVitePlugin from '../vite-plugin-markdown/index.js';
import astroScannerPlugin from '../vite-plugin-scanner/index.js'; import astroScannerPlugin from '../vite-plugin-scanner/index.js';
import astroScriptsPlugin from '../vite-plugin-scripts/index.js'; import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
@ -110,9 +109,7 @@ export async function createVite(
// the build to run very slow as the filewatcher is triggered often. // the build to run very slow as the filewatcher is triggered often.
mode !== 'build' && vitePluginAstroServer({ settings, logging, fs }), mode !== 'build' && vitePluginAstroServer({ settings, logging, fs }),
envVitePlugin({ settings }), envVitePlugin({ settings }),
settings.config.legacy.astroFlavoredMarkdown markdownVitePlugin({ settings, logging }),
? legacyMarkdownVitePlugin({ settings, logging })
: markdownVitePlugin({ settings, logging }),
htmlVitePlugin(), htmlVitePlugin(),
jsxVitePlugin({ settings, logging }), jsxVitePlugin({ settings, logging }),
astroPostprocessVitePlugin({ settings }), astroPostprocessVitePlugin({ settings }),

View file

@ -24,7 +24,6 @@ export function createDevelopmentEnvironment(
logging, logging,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isAstroFlavoredMd: settings.config.legacy.astroFlavoredMarkdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections, isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },

View file

@ -1,3 +0,0 @@
# vite-plugin-markdown-legacy
Adds Markdown support to Vite, both at the top level as well as within `.astro` files.

View file

@ -1,265 +0,0 @@
import { renderMarkdown } from '@astrojs/markdown-remark';
import fs from 'fs';
import matter from 'gray-matter';
import { fileURLToPath } from 'url';
import { Plugin, ResolvedConfig, transformWithEsbuild } from 'vite';
import type { AstroSettings } from '../@types/astro';
import { getContentPaths } from '../content/index.js';
import { pagesVirtualModuleId } from '../core/app/index.js';
import { cachedCompilation, CompileProps } from '../core/compile/index.js';
import { AstroErrorData, MarkdownError } from '../core/errors/index.js';
import type { LogOptions } from '../core/logger/core.js';
import { isMarkdownFile } from '../core/util.js';
import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types';
import { getFileInfo, normalizeFilename } from '../vite-plugin-utils/index.js';
interface AstroPluginOptions {
settings: AstroSettings;
logging: LogOptions;
}
const MARKDOWN_IMPORT_FLAG = '?mdImport';
const MARKDOWN_CONTENT_FLAG = '?content';
function safeMatter(source: string, id: string) {
try {
return matter(source);
} catch (err: any) {
const markdownError = new MarkdownError({
code: AstroErrorData.UnknownMarkdownError.code,
message: err.message,
stack: err.stack,
location: {
file: id,
},
});
if (err.name === 'YAMLException') {
markdownError.setErrorCode(AstroErrorData.MarkdownFrontmatterParseError.code);
markdownError.setLocation({
file: id,
line: err.mark.line,
column: err.mark.column,
});
markdownError.setMessage(err.reason);
}
throw markdownError;
}
}
// Both end up connecting a `load()` hook to the Astro compiler, and share some copy-paste
// logic in how that is done.
export default function markdown({ settings }: AstroPluginOptions): Plugin {
const { config } = settings;
// Weird Vite behavior: Vite seems to use a fake "index.html" importer when you
// have `enforce: pre`. This can probably be removed once the vite issue is fixed.
// see: https://github.com/vitejs/vite/issues/5981
const fakeRootImporter = fileURLToPath(new URL('index.html', config.root));
function isRootImport(importer: string | undefined) {
if (!importer) {
return true;
}
if (importer === fakeRootImporter) {
return true;
}
if (importer === '\0' + pagesVirtualModuleId) {
return true;
}
return false;
}
let resolvedConfig: ResolvedConfig;
return {
name: 'astro:markdown',
enforce: 'pre',
async resolveId(id, importer, options) {
// Resolve any .md (or alternative extensions of markdown files like .markdown) files with the `?content` cache buster. This should only come from
// an already-resolved JS module wrapper. Needed to prevent infinite loops in Vite.
// Unclear if this is expected or if cache busting is just working around a Vite bug.
if (isMarkdownFile(id, { suffix: MARKDOWN_CONTENT_FLAG })) {
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
return resolvedId?.id.replace(MARKDOWN_CONTENT_FLAG, '');
}
// If the markdown file is imported from another file via ESM, resolve a JS representation
// that defers the markdown -> HTML rendering until it is needed. This is especially useful
// when fetching and then filtering many markdown files, like with import.meta.glob() or Astro.glob().
// Otherwise, resolve directly to the actual component.
if (isMarkdownFile(id) && !isRootImport(importer)) {
const resolvedId = await this.resolve(id, importer, { skipSelf: true, ...options });
if (resolvedId) {
return resolvedId.id + MARKDOWN_IMPORT_FLAG;
}
}
// In all other cases, we do nothing and rely on normal Vite resolution.
return undefined;
},
async load(id, opts) {
// A markdown file has been imported via ESM!
// Return the file's JS representation, including all Markdown
// frontmatter and a deferred `import() of the compiled markdown content.
if (isMarkdownFile(id, { suffix: MARKDOWN_IMPORT_FLAG })) {
const { fileId, fileUrl } = getFileInfo(id, config);
const source = await fs.promises.readFile(fileId, 'utf8');
const { data: frontmatter, content: rawContent } = safeMatter(source, fileId);
return {
code: `
// Static
export const frontmatter = ${escapeViteEnvReferences(JSON.stringify(frontmatter))};
export const file = ${JSON.stringify(fileId)};
export const url = ${JSON.stringify(fileUrl)};
export function rawContent() {
return ${escapeViteEnvReferences(JSON.stringify(rawContent))};
}
export async function compiledContent() {
return load().then((m) => m.compiledContent());
}
// Deferred
export default async function load() {
return (await import(${JSON.stringify(fileId + MARKDOWN_CONTENT_FLAG)}));
}
export function Content(...args) {
return load().then((m) => m.default(...args));
}
Content.isAstroComponentFactory = true;
export function getHeadings() {
return load().then((m) => m.metadata.headings);
}
export function getHeaders() {
console.warn('getHeaders() have been deprecated. Use getHeadings() function instead.');
return load().then((m) => m.metadata.headings);
};`,
map: null,
};
}
// A markdown file is being rendered! This markdown file was either imported
// directly as a page in Vite, or it was a deferred render from a JS module.
// This returns the compiled markdown -> astro component that renders to HTML.
if (isMarkdownFile(id)) {
const filename = normalizeFilename(id, config);
const source = await fs.promises.readFile(filename, 'utf8');
const renderOpts = config.markdown;
const fileUrl = new URL(`file://${filename}`);
// Extract special frontmatter keys
let { data: frontmatter, content: markdownContent } = safeMatter(source, filename);
// Turn HTML comments into JS comments while preventing nested `*/` sequences
// from ending the JS comment by injecting a zero-width space
// Inside code blocks, this is removed during renderMarkdown by the remark-escape plugin.
markdownContent = markdownContent.replace(
/<\s*!--([^-->]*)(.*?)-->/gs,
(whole) => `{/*${whole.replace(/\*\//g, '*\u200b/')}*/}`
);
let renderResult = await renderMarkdown(markdownContent, {
...renderOpts,
fileURL: fileUrl,
isAstroFlavoredMd: true,
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir,
} as any);
let { code: astroResult, metadata } = renderResult;
const { layout = '', components = '', setup = '', ...content } = frontmatter;
content.astro = metadata;
content.url = getFileInfo(id, config).fileUrl;
content.file = filename;
const prelude = `---
import Slugger from 'github-slugger';
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
${components ? `import * from ${JSON.stringify(components)};` : ''}
${setup}
const slugger = new Slugger();
function $$slug(value) {
return slugger.slug(value);
}
const $$content = ${JSON.stringify(content)};
Object.defineProperty($$content.astro, 'headers', {
get() {
console.warn('[${JSON.stringify(id)}] content.astro.headers is now content.astro.headings.');
return this.headings;
}
});
---`;
const imports = `${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
${setup}`.trim();
// If the user imported "Layout", wrap the content in a Layout
if (/\bLayout\b/.test(imports)) {
astroResult = `${prelude}\n<Layout content={$$content}>\n\n${astroResult}\n\n</Layout>`;
} else {
// Note: without a Layout, we need to inject `head` manually so `maybeRenderHead` runs
astroResult = `${prelude}\n<head></head>${astroResult}`;
}
// Transform from `.astro` to valid `.ts`
const compileProps: CompileProps = {
astroConfig: config,
viteConfig: resolvedConfig,
filename,
source: astroResult,
id,
};
let transformResult = await cachedCompilation(compileProps);
let { code: tsResult } = transformResult;
tsResult = `\nexport const metadata = ${JSON.stringify(metadata)};
export const frontmatter = ${JSON.stringify(content)};
export function rawContent() {
return ${JSON.stringify(markdownContent)};
}
export function compiledContent() {
return ${JSON.stringify(renderResult.metadata.html)};
}
${tsResult}`;
// Compile from `.ts` to `.js`
const { code } = await transformWithEsbuild(tsResult, id, {
loader: 'ts',
sourcemap: false,
});
const astroMetadata: AstroPluginMetadata['astro'] = {
clientOnlyComponents: transformResult.clientOnlyComponents,
hydratedComponents: transformResult.hydratedComponents,
scripts: transformResult.scripts,
propagation: 'none',
pageOptions: {},
};
return {
code: escapeViteEnvReferences(code),
map: null,
meta: {
astro: astroMetadata,
vite: {
lang: 'ts',
},
},
};
}
return null;
},
};
}
// Converts the first dot in `import.meta.env` to its Unicode escape sequence,
// which prevents Vite from replacing strings like `import.meta.env.SITE`
// in our JS representation of loaded Markdown files
function escapeViteEnvReferences(code: string) {
return code.replace(/import\.meta\.env/g, 'import\\u002Emeta.env');
}

View file

@ -91,7 +91,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
warn( warn(
logging, logging,
'markdown', 'markdown',
`[${id}] Astro now supports MDX! Support for components in ".md" (or alternative extensions like ".markdown") files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX or add the "legacy.astroFlavoredMarkdown" config flag to re-enable support.` `[${id}] Astro now supports MDX! Support for components in ".md" (or alternative extensions like ".markdown") files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX.`
); );
} }

View file

@ -1,59 +0,0 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
let fixture;
const IMPORTED_ASTRO_COMPONENT_ID = 'imported-astro-component';
describe('Imported markdown CSS', function () {
before(async () => {
fixture = await loadFixture({ root: './fixtures/astro-markdown-css/' });
});
describe('build', () => {
let $;
let bundledCSS;
before(async () => {
this.timeout(45000); // test needs a little more time in CI
await fixture.build();
// get bundled CSS (will be hashed, hence DOM query)
const html = await fixture.readFile('/index.html');
$ = cheerio.load(html);
const bundledCSSHREF = $('link[rel=stylesheet][href^=/assets/]').attr('href');
bundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/'));
});
it('Compiles styles for Astro components within imported markdown', () => {
const importedAstroComponent = $(`#${IMPORTED_ASTRO_COMPONENT_ID}`)?.[0];
expect(importedAstroComponent?.name).to.equal('h2');
const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0];
expect(bundledCSS).to.include(`h2:where(.${cssClass}){color:#00f}`);
});
});
describe('dev', () => {
let devServer;
let html;
let $;
before(async () => {
devServer = await fixture.startDevServer();
html = await fixture.fetch('/').then((res) => res.text());
$ = cheerio.load(html);
});
after(async () => {
await devServer.stop();
});
it('Compiles styles for Astro components within imported markdown', async () => {
const importedAstroComponent = $(`#${IMPORTED_ASTRO_COMPONENT_ID}`)?.[0];
expect(importedAstroComponent?.name).to.equal('h2');
const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0];
const allInjectedStyles = $('style').text().replace(/\s*/g, '');
expect(allInjectedStyles).to.include(`h2:where(.${cssClass}){color:#00f}`);
});
});
});

View file

@ -14,19 +14,6 @@ describe('Astro Markdown', () => {
await fixture.build(); await fixture.build();
}); });
it('Leaves JSX expressions unprocessed', async () => {
const html = await fixture.readFile('/jsx-expressions/index.html');
const $ = cheerio.load(html);
expect($('h2').html()).to.equal('{frontmatter.title}');
});
it('Leaves JSX components un-transformed', async () => {
const html = await fixture.readFile('/components/index.html');
expect(html).to.include('<counter client:load="" count="{0}">');
});
it('Exposes raw markdown content', async () => { it('Exposes raw markdown content', async () => {
const { raw } = JSON.parse(await fixture.readFile('/raw-content.json')); const { raw } = JSON.parse(await fixture.readFile('/raw-content.json'));

View file

@ -1,9 +0,0 @@
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: []
});

View file

@ -1,12 +0,0 @@
{
"name": "@test/astro-markdown-css",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "astro build",
"dev": "astro dev"
},
"dependencies": {
"astro": "workspace:*"
}
}

View file

@ -1,7 +0,0 @@
<h2 id="imported-astro-component">I'm a visual!</h2>
<style>
h2 {
color: #00f;
}
</style>

View file

@ -1,9 +0,0 @@
---
setup: import Visual from '../components/Visual.astro'
---
# Example markdown document, with a Visual
<Visual />
<Visual />
<Visual />

View file

@ -1,9 +0,0 @@
---
setup: import Visual from '../components/Visual.astro'
---
# Example markdown document, with a more Visuals
<Visual />
<Visual />
<Visual />

View file

@ -1,15 +0,0 @@
---
const markdownDocs = await Astro.glob('../markdown/*.md')
const article2 = await import('../markdown/article2.md')
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Astro</title>
</head>
<body>
{markdownDocs.map(markdownDoc => <><h2>{markdownDoc.url}</h2><markdownDoc.Content /></>)}
<article2.Content />
</body>
</html>

View file

@ -1,5 +0,0 @@
---
setup: import Counter from '../components/Counter.svelte'
---
<Counter client:load count={0}></Counter>

View file

@ -1,13 +0,0 @@
---
title: Blog Post with JSX expressions
paragraph: JSX at the start of the line!
list: ['test-1', 'test-2', 'test-3']
---
## {frontmatter.title}
{frontmatter.paragraph}
<ul>
{frontmatter.list.map(item => <li id={item}>{item}</li>)}
</ul>

View file

@ -2,8 +2,5 @@ import { defineConfig } from 'astro/config';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [] integrations: []
}); });

View file

@ -1,8 +0,0 @@
---
setup: |
import foo from '../foo.js'
---
# Testing
## { foo() }

View file

@ -1,12 +0,0 @@
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
import svelte from "@astrojs/svelte";
// https://astro.build/config
export default defineConfig({
integrations: [preact(), svelte()],
site: 'https://astro.build/',
legacy: {
astroFlavoredMarkdown: true,
}
});

View file

@ -1,12 +0,0 @@
{
"name": "@test/astro-markdown",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/preact": "workspace:*",
"@astrojs/svelte": "workspace:*",
"astro": "workspace:*",
"preact": "^10.11.0",
"svelte": "^3.48.0"
}
}

View file

@ -1,7 +0,0 @@
import { h } from 'preact';
import { useState } from 'preact/hooks';
export default function () {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

View file

@ -1,5 +0,0 @@
import { h } from 'preact';
export default function () {
return <div id="test">Testing</div>;
}

View file

@ -1,5 +0,0 @@
import { h } from 'preact';
export default function ({ name }) {
return <div id="test">Hello {name}</div>;
}

View file

@ -1,13 +0,0 @@
<article>
<section class="fragmentSlot">
<slot name="fragmentSlot">❌ Missing content for slot "fragmentSlot"</slot>
</section>
<section class="pSlot">
<slot name="pSlot">❌ Missing content for slot "pSlot"</slot>
</section>
<section class="defaultSlot">
<slot>❌ Missing content for default slot</slot>
</section>
</article>

View file

@ -1,11 +0,0 @@
<script>
let cool = false
</script>
<button on:click={() => cool = true}>This is cool right? {cool}</button>
<style>
button {
background: green;
}
</style>

View file

@ -1,20 +0,0 @@
import { h } from 'preact';
const TextBlock = ({
title,
children,
noPadding = false,
}) => {
return (
<div
className={`${
noPadding ? "" : "md:px-2 lg:px-4"
} flex-1 prose prose-headings:font-grotesk`}
>
<h3>{title}</h3>
<p>{children}</p>
</div>
);
};
export default TextBlock;

View file

@ -1,5 +0,0 @@
import Counter from './Counter';
export default {
Counter
}

View file

@ -1,3 +0,0 @@
This should have `nospace` around it.
This should have <code class="custom-class">nospace</code> around it.

View file

@ -1,6 +0,0 @@
---
---
## Plain jane
I am plain markdown!

View file

@ -1,17 +0,0 @@
---
setup: |
import Counter from '../components/Counter.jsx'
import Hello from '../components/Hello.jsx'
import SvelteButton from '../components/SvelteButton.svelte'
---
## With components
### Non-hydrated
<Hello name="Astro Naut" />
### Hydrated
<Counter client:load />
<SvelteButton client:load />

View file

@ -1,10 +0,0 @@
<html>
<head>
<!-- Head Stuff -->
</head>
<body>
<div class="container">
<slot></slot>
</div>
</body>
</html>

View file

@ -1,17 +0,0 @@
---
interface Props {
url: string;
file: string;
title: string;
}
const { title, url, file } = Astro.props.content as Props;
---
<html>
<body>
<div id="title">{title}</div>
<div id="url">{url}</div>
<div id="file">{file}</div>
</body>
</html>

View file

@ -1,12 +0,0 @@
---
setup: import TextBlock from '../components/TextBlock'
---
{/* https://github.com/withastro/astro/issues/3319 */}
<TextBlock title="Hello world!" noPadding>
<ul class="not-prose">
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
</TextBlock>

View file

@ -1,7 +0,0 @@
---
const content = await Astro.glob('../content/*.md');
---
<div>
{content.map(({ Content }) => <Content />)}
</div>

View file

@ -1,16 +0,0 @@
# Inline code blocks
`<script>` tags in **Astro** components are now built,
bundled and optimized by default.
> Markdown formatting still works between tags in inline code blocks.
We can also use closing `</script>` tags without any problems.
# Fenced code blocks
```html
<body>
<div>This should also work without any problems.</div>
</body>
```

View file

@ -1,23 +0,0 @@
<!--
HTML comments with */ inside!
-->
<!--
```js
/**
* It even works inside nested fenced code blocks!
*/
function test() {
/* Yay */
return 'Nice!';
}
```
-->
```
<!-- HTML comments in code fence -->
```
`<!-- HTML comments in code -->`
# It still works!

View file

@ -1,2 +0,0 @@
<!-- HTML comments! -->
# It works!

View file

@ -1,14 +0,0 @@
---
title: My Blog Post
layout: ../layouts/content.astro
---
## Title
Hello world
With this in the body ---
## Another
more content

View file

@ -1,20 +0,0 @@
---
title: My Blog Post
layout: ../layouts/content.astro
---
## Title
Hello world
With this in the body ---
## Another
more content
```
```
<pre></pre>

View file

@ -1,9 +0,0 @@
---
import Layout from '../../layouts/content.astro'
const posts = await Astro.glob('../../imported-md/*.md')
---
<Layout>
{posts.map(({ Content }) => <Content />)}
</Layout>

View file

@ -1,13 +0,0 @@
---
title: Blog Post with JSX expressions
paragraph: JSX at the start of the line!
list: ['test-1', 'test-2', 'test-3']
---
## {frontmatter.title}
{frontmatter.paragraph}
<ul>
{frontmatter.list.map(item => <li id={item}>{item}</li>)}
</ul>

View file

@ -1,4 +0,0 @@
---
title: 'Hello world!'
layout: '../layouts/layout-props.astro'
---

View file

@ -1,7 +0,0 @@
---
setup: import ns from '../components/index.js';
---
# Hello Namespace!
<ns.Counter>Click me!</ns.Counter>

View file

@ -1,10 +0,0 @@
import { rawContent, compiledContent } from '../imported-md/with-components.md';
export async function get() {
return {
body: JSON.stringify({
raw: rawContent(),
compiled: await compiledContent(),
}),
}
}

View file

@ -1,7 +0,0 @@
# Test
## Let's try a script...
This should work!
<script src="/src/scripts/test.js" />

View file

@ -1,38 +0,0 @@
---
layout: ../layouts/content.astro
setup: import SlotComponent from '../components/SlotComponent.astro';
---
# Component with slot contents in children
<SlotComponent>
<div>4: Div in default slot</div>
<Fragment slot="fragmentSlot">
<div>1: Div in fragmentSlot</div>
<p>2: Paragraph in fragmentSlot</p>
</Fragment>
<Fragment><p>5: Paragraph in fragment in default slot</p></Fragment>
6: Regular text in default slot
<p slot="pSlot" title="hello">3: p with title as pSlot</p>
</SlotComponent>
# Component with nested component in children
<SlotComponent>
<p slot="pSlot">2: pSlot</p>
<SlotComponent>
<p slot="pSlot">4: nested pSlot</p>
5: nested text in default slot
<Fragment slot="fragmentSlot">3: nested fragmentSlot</Fragment>
</SlotComponent>
<Fragment slot="fragmentSlot">1: fragmentSlot</Fragment>
</SlotComponent>
# Missing content due to empty children
<SlotComponent>
</SlotComponent>
# Missing content due to self-closing tag
<SlotComponent/>

View file

@ -1,7 +0,0 @@
---
title: My Blog Post
---
# {frontmatter.title}
Hello world

View file

@ -1,35 +0,0 @@
---
title: Referencing Vite Env Vars like import.meta.env.SITE, import.meta.env.TITLE and import.meta.env
layout: ../layouts/content.astro
---
## Referencing the full name of Vite env vars
You can get the configured site URL with `import.meta.env.SITE`.
The variable `import.meta.env.TITLE` is not configured.
You can reference all env vars through `import.meta.env`.
This should also work outside of code blocks:
- import.meta.env.SITE
- import.meta.env.TITLE
- import.meta.env
## Usage in fenced code blocks with syntax highlighting
```js
// src/pages/rss.xml.js
import rss from '@astrojs/rss';
export const get = () => rss({
// Use Vite env vars with import.meta.env
site: import.meta.env.SITE,
title: import.meta.env.TITLE,
items: import.meta.glob('./**/*.md'),
});
```
## Usage in frontmatter
> frontmatter.title: {frontmatter.title}

View file

@ -1 +0,0 @@
console.log("Hello world");

View file

@ -1,7 +0,0 @@
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
// https://astro.build/config
export default defineConfig({
integrations: [vue()],
});

View file

@ -1,10 +0,0 @@
{
"name": "@test/legacy-build",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/vue": "workspace:*",
"astro": "workspace:*",
"preact": "~10.6.6"
}
}

View file

@ -1,24 +0,0 @@
<template>
<div id="vue" class="counter">
<button @click="subtract()">-</button>
<pre>{{ count }}</pre>
<button @click="add()">+</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const add = () => (count.value = count.value + 1);
const subtract = () => (count.value = count.value - 1);
return {
count,
add,
subtract,
};
},
};
</script>

View file

@ -1,20 +0,0 @@
<script>
export default {
data() {
return {
greeting: 'Hello World!',
};
},
};
</script>
<template>
<p class="greeting">{{ greeting }}</p>
</template>
<style>
.greeting {
color: red;
font-weight: bold;
}
</style>

View file

@ -1,13 +0,0 @@
<script type="module" hoist>
import { h, render } from 'preact';
const mount = document.querySelector('#inline-hoist');
function App() {
return h('strong', null, 'Hello again');
}
render(h(App), mount);
</script>
<div id="inline-hoist"></div>

View file

@ -1,18 +0,0 @@
---
import Greeting from '../components/Greeting.vue';
export async function getStaticPaths() {
const allPokemon = [{name: 'Charmander'}, {name: 'Charmander'}, {name: 'Charizard'}];
return allPokemon.map(pokemon => ({params: {pokemon: pokemon.name}, props: {pokemon}}));
}
---
<html lang="en">
<head>
<title>Hello</title>
</head>
<body>
<h1>{Astro.props.pokemon.name}</h1>
<Greeting client:load />
</body>
</html>

View file

@ -1,60 +0,0 @@
---
import Greeting from '../components/Greeting.vue';
import Counter from '../components/Counter.vue';
import InlineHoisted from '../components/InlineHoisted.astro';
---
<html>
<head>
<title>Demo app</title>
<style>
h1 {
color: salmon;
}
</style>
<style lang="scss">
@import "../styles/_global.scss";
h2 {
color: $color;
}
</style>
<style define:vars={{ color: 'blue' }}>
.define-vars h1 {
color: var(--color);
}
</style>
</head>
<body>
<section>
<h1>Component CSS</h1>
<Greeting />
</section>
<section>
<h1>ImageTools</h1>
</section>
<section>
<h1>Astro components</h1>
</section>
<section>
<h1>Hydrated component</h1>
<Counter client:idle />
</section>
<section>
<h1>Hoisted scripts</h1>
<InlineHoisted />
</section>
<section class="define-vars">
<h1>define:vars</h1>
<h2></h2>
<script define:vars={{ color: 'blue' }}>
document.querySelector('.define-vars h2').textContent = `Color: ${color}`;
</script>
</section>
</body>
</html>

View file

@ -1,2 +0,0 @@
const el = document.querySelector('#external-hoist');
el.textContent = `This was loaded externally`;

View file

@ -1 +0,0 @@
$color: tan;

View file

@ -1,3 +0,0 @@
body {
background: lightcoral;
}

View file

@ -4,8 +4,5 @@ import preact from '@astrojs/preact';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [preact(), mdx()], integrations: [preact(), mdx()],
}); });

View file

@ -1,9 +0,0 @@
---
setup: import Counter from '../components/Counter.jsx'
---
# Slots: Preact
<Counter case="content" client:visible><h1 id="slotted">Hello world!</h1></Counter>
<Counter case="named" client:visible><h1 slot="named"> / Named</h1></Counter>
<Counter case="dash-case" client:visible><h1 slot="dash-case"> / Dash Case</h1></Counter>

View file

@ -4,8 +4,5 @@ import react from '@astrojs/react';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [react(), mdx()], integrations: [react(), mdx()],
}); });

View file

@ -1,9 +0,0 @@
---
setup: import Counter from '../components/Counter.jsx'
---
# Slots: React
<Counter case="content" client:visible><h1 id="slotted">Hello world!</h1></Counter>
<Counter case="named" client:visible><h1 slot="named"> / Named</h1></Counter>
<Counter case="dash-case" client:visible><h1 slot="dash-case"> / Dash Case</h1></Counter>

View file

@ -4,8 +4,5 @@ import solid from '@astrojs/solid-js';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [solid(), mdx()], integrations: [solid(), mdx()],
}); });

View file

@ -1,9 +0,0 @@
---
setup: import Counter from '../components/Counter.jsx'
---
# Slots: Solid
<Counter case="content" client:visible><h1 id="slotted">Hello world!</h1></Counter>
<Counter case="named" client:visible><h1 slot="named"> / Named</h1></Counter>
<Counter case="dash-case" client:visible><h1 slot="dash-case"> / Dash Case</h1></Counter>

View file

@ -4,8 +4,5 @@ import svelte from '@astrojs/svelte';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [svelte(), mdx()], integrations: [svelte(), mdx()],
}); });

View file

@ -1,9 +0,0 @@
---
setup: import Counter from '../components/Counter.svelte'
---
# Slots: Svelte
<Counter id="content" client:visible><h1 id="slotted">Hello world!</h1></Counter>
<Counter id="named" client:visible><h1 slot="named"> / Named</h1></Counter>
<Counter id="dash-case" client:visible><h1 slot="dash-case"> / Dash Case</h1></Counter>

View file

@ -4,8 +4,5 @@ import vue from '@astrojs/vue';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [vue(), mdx()], integrations: [vue(), mdx()],
}); });

View file

@ -1,9 +0,0 @@
---
setup: import Counter from '../components/Counter.vue'
---
# Slots: Vue
<Counter case="content" client:visible><h1 id="slotted">Hello world!</h1></Counter>
<Counter case="named" client:visible><h1 slot="named"> / Named</h1></Counter>
<Counter case="dash-case" client:visible><h1 slot="dash-case"> / Dash Case</h1></Counter>

View file

@ -4,9 +4,6 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
legacy: {
astroFlavoredMarkdown: true,
},
integrations: [tailwind(), mdx()], integrations: [tailwind(), mdx()],
vite: { vite: {
build: { build: {

View file

@ -16,10 +16,4 @@ describe('Using .js extension on .ts file', () => {
const $ = cheerio.load(html); const $ = cheerio.load(html);
expect($('h1').text()).to.equal('bar'); expect($('h1').text()).to.equal('bar');
}); });
it('works in .md files', async () => {
const html = await fixture.readFile('/post/index.html');
const $ = cheerio.load(html);
expect($('h2').text()).to.equal('bar');
});
}); });

View file

@ -1,200 +0,0 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture, fixLineEndings } from './test-utils.js';
describe('Legacy Astro-flavored Markdown', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/legacy-astro-flavored-markdown/',
});
await fixture.build();
});
it('Can parse JSX expressions in markdown pages', async () => {
const html = await fixture.readFile('/jsx-expressions/index.html');
const $ = cheerio.load(html);
expect($('h2').html()).to.equal('Blog Post with JSX expressions');
expect(html).to.contain('JSX at the start of the line!');
for (let listItem of ['test-1', 'test-2', 'test-3']) {
expect($(`#${listItem}`).html()).to.equal(`${listItem}`);
}
});
it('Can handle slugs with JSX expressions in markdown pages', async () => {
const html = await fixture.readFile('/slug/index.html');
const $ = cheerio.load(html);
expect($('h1').attr('id')).to.equal('my-blog-post');
});
it('Can handle code elements without extra spacing', async () => {
const html = await fixture.readFile('/code-element/index.html');
const $ = cheerio.load(html);
$('code').each((_, el) => {
expect($(el).html()).to.equal($(el).html().trim());
});
});
it('Can handle namespaced components in markdown', async () => {
const html = await fixture.readFile('/namespace/index.html');
const $ = cheerio.load(html);
expect($('h1').text()).to.equal('Hello Namespace!');
expect($('button').length).to.equal(1);
});
it('Correctly handles component children in markdown pages (#3319)', async () => {
const html = await fixture.readFile('/children/index.html');
expect(html).not.to.contain('<p></p>');
});
it('Can handle HTML comments in markdown pages', async () => {
const html = await fixture.readFile('/comment/index.html');
const $ = cheerio.load(html);
expect($('h1').text()).to.equal('It works!');
});
it('Prevents `*/` sequences from breaking HTML comments (#3476)', async () => {
const html = await fixture.readFile('/comment-with-js/index.html');
const $ = cheerio.load(html);
expect($('h1').text()).to.equal('It still works!');
});
it('Can handle HTML comments in inline code', async () => {
const html = await fixture.readFile('/comment-with-js/index.html');
const $ = cheerio.load(html);
expect($('p code').text()).to.equal('<!-- HTML comments in code -->');
});
it('Can handle HTML comments in code fences', async () => {
const html = await fixture.readFile('/comment-with-js/index.html');
const $ = cheerio.load(html);
expect($('pre > code').text()).to.equal('<!-- HTML comments in code fence -->');
});
// https://github.com/withastro/astro/issues/3254
it('Can handle scripts in markdown pages', async () => {
const html = await fixture.readFile('/script/index.html');
expect(html).not.to.match(new RegExp('/src/scripts/test.js'));
});
it('Empty code blocks do not fail', async () => {
const html = await fixture.readFile('/empty-code/index.html');
const $ = cheerio.load(html);
// test 1: There is not a `<code>` in the codeblock
expect($('pre')[0].children).to.have.lengthOf(1);
// test 2: The empty `<pre>` failed to render
expect($('pre')[1].children).to.have.lengthOf(0);
});
it('Can render markdown with --- for horizontal rule', async () => {
const html = await fixture.readFile('/dash/index.html');
expect(!!html).to.equal(true);
});
it('Exposes raw markdown content', async () => {
const { raw } = JSON.parse(await fixture.readFile('/raw-content.json'));
expect(fixLineEndings(raw)).to.equal(
`\n## With components\n\n### Non-hydrated\n\n<Hello name="Astro Naut" />\n\n### Hydrated\n\n<Counter client:load />\n<SvelteButton client:load />\n`
);
});
it('Exposes compiled HTML content', async () => {
const { compiled } = JSON.parse(await fixture.readFile('/raw-content.json'));
expect(fixLineEndings(compiled)).to.equal(
`<h2 id="with-components">With components</h2>\n<h3 id="non-hydrated">Non-hydrated</h3>\n<Hello name="Astro Naut" />\n<h3 id="hydrated">Hydrated</h3>\n<Counter client:load />\n<SvelteButton client:load />`
);
});
it('Allows referencing Vite env var names in markdown (#3412)', async () => {
const html = await fixture.readFile('/vite-env-vars/index.html');
const $ = cheerio.load(html);
// test 1: referencing an existing var name
expect($('code').eq(0).text()).to.equal('import.meta.env.SITE');
expect($('li').eq(0).text()).to.equal('import.meta.env.SITE');
expect($('code').eq(3).text()).to.contain('site: import.meta.env.SITE');
expect($('blockquote').text()).to.contain('import.meta.env.SITE');
// test 2: referencing a non-existing var name
expect($('code').eq(1).text()).to.equal('import.meta.env.TITLE');
expect($('li').eq(1).text()).to.equal('import.meta.env.TITLE');
expect($('code').eq(3).text()).to.contain('title: import.meta.env.TITLE');
expect($('blockquote').text()).to.contain('import.meta.env.TITLE');
// test 3: referencing `import.meta.env` itself (without any var name)
expect($('code').eq(2).text()).to.equal('import.meta.env');
expect($('li').eq(2).text()).to.equal('import.meta.env');
expect($('code').eq(3).text()).to.contain('// Use Vite env vars with import.meta.env');
expect($('blockquote').text()).to.match(/import\.meta\.env\s*$/);
});
it('Escapes HTML tags in code blocks', async () => {
const html = await fixture.readFile('/code-in-md/index.html');
const $ = cheerio.load(html);
expect($('code').eq(0).html()).to.equal('&lt;script&gt;');
expect($('blockquote').length).to.equal(1);
expect($('code').eq(1).html()).to.equal('&lt;/script&gt;');
expect($('pre').html()).to.contain('&gt;This should also work without any problems.&lt;');
});
it('Allows defining slot contents in component children', async () => {
const html = await fixture.readFile('/slots/index.html');
const $ = cheerio.load(html);
const slots = $('article').eq(0);
expect(slots.find('> .fragmentSlot > div').text()).to.contain('1:');
expect(slots.find('> .fragmentSlot > div + p').text()).to.contain('2:');
expect(slots.find('> .pSlot > p[title="hello"]').text()).to.contain('3:');
expect(slots.find('> .defaultSlot').html()).to.match(
new RegExp(
`<div>4: Div in default slot</div>` +
// Optional extra paragraph due to the line breaks between components
`(<p></p>)?` +
`<p>5: Paragraph in fragment in default slot</p>` +
// Optional whitespace due to the line breaks between components
`[\s\n]*` +
`6: Regular text in default slot`
)
);
const nestedSlots = $('article').eq(1);
expect(nestedSlots.find('> .fragmentSlot').html()).to.contain('1:');
expect(nestedSlots.find('> .pSlot > p').text()).to.contain('2:');
expect(nestedSlots.find('> .defaultSlot > article').text().replace(/\s+/g, ' ')).to.equal(
`
3: nested fragmentSlot
4: nested pSlot
5: nested text in default slot
`.replace(/\s+/g, ' ')
);
expect($('article').eq(3).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
expect($('article').eq(4).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
});
it('Generate the right props for the layout', async () => {
const html = await fixture.readFile('/layout-props/index.html');
const $ = cheerio.load(html);
expect($('#title').text()).to.equal('Hello world!');
expect($('#url').text()).to.equal('/layout-props');
expect($('#file').text()).to.match(/.*\/layout-props.md$/);
});
});

View file

@ -34,26 +34,6 @@ describe('Slots: Preact', () => {
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });
describe('For Markdown Pages', () => {
it('Renders default slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#content').text().trim()).to.equal('Hello world!');
});
it('Renders named slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#named').text().trim()).to.equal('Fallback / Named');
});
it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
});
});
describe('For MDX Pages', () => { describe('For MDX Pages', () => {
it('Renders default slot', async () => { it('Renders default slot', async () => {
const html = await fixture.readFile('/mdx/index.html'); const html = await fixture.readFile('/mdx/index.html');

View file

@ -34,26 +34,6 @@ describe('Slots: React', () => {
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });
describe('For Markdown Pages', () => {
it('Renders default slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#content').text().trim()).to.equal('Hello world!');
});
it('Renders named slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#named').text().trim()).to.equal('Fallback / Named');
});
it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
});
});
describe('For MDX Pages', () => { describe('For MDX Pages', () => {
it('Renders default slot', async () => { it('Renders default slot', async () => {
const html = await fixture.readFile('/mdx/index.html'); const html = await fixture.readFile('/mdx/index.html');

View file

@ -34,26 +34,6 @@ describe('Slots: Solid', () => {
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });
describe('For Markdown Pages', () => {
it('Renders default slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#content').text().trim()).to.equal('Hello world!');
});
it('Renders named slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#named').text().trim()).to.equal('Fallback / Named');
});
it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
});
});
describe('For MDX Pages', () => { describe('For MDX Pages', () => {
it('Renders default slot', async () => { it('Renders default slot', async () => {
const html = await fixture.readFile('/mdx/index.html'); const html = await fixture.readFile('/mdx/index.html');

View file

@ -34,26 +34,6 @@ describe('Slots: Svelte', () => {
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });
describe('For Markdown Pages', () => {
it('Renders default slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#content').text().trim()).to.equal('Hello world!');
});
it('Renders named slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#named').text().trim()).to.equal('Fallback / Named');
});
it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
});
});
describe('For MDX Pages', () => { describe('For MDX Pages', () => {
it('Renders default slot', async () => { it('Renders default slot', async () => {
const html = await fixture.readFile('/mdx/index.html'); const html = await fixture.readFile('/mdx/index.html');

View file

@ -34,26 +34,6 @@ describe('Slots: Vue', () => {
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });
describe('For Markdown Pages', () => {
it('Renders default slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#content').text().trim()).to.equal('Hello world!');
});
it('Renders named slot', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#named').text().trim()).to.equal('Fallback / Named');
});
it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html');
const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
});
});
describe('For MDX Pages', () => { describe('For MDX Pages', () => {
it('Renders default slot', async () => { it('Renders default slot', async () => {
const html = await fixture.readFile('/mdx/index.html'); const html = await fixture.readFile('/mdx/index.html');
@ -68,7 +48,7 @@ describe('Slots: Vue', () => {
}); });
it('Converts dash-case slot to camelCase', async () => { it('Converts dash-case slot to camelCase', async () => {
const html = await fixture.readFile('/markdown/index.html'); const html = await fixture.readFile('/mdx/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);
expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case'); expect($('#dash-case').text().trim()).to.equal('Fallback / Dash Case');
}); });

View file

@ -25,25 +25,6 @@ describe('Astro Markdown', () => {
expect($('#test').length).to.be.ok; expect($('#test').length).to.be.ok;
}); });
it('Can parse JSX expressions in markdown pages', async () => {
const html = await fixture.readFile('/jsx-expressions/index.html');
const $ = cheerio.load(html);
expect($('h2').html()).to.equal('Blog Post with JSX expressions');
expect(html).to.contain('JSX at the start of the line!');
for (let listItem of ['test-1', 'test-2', 'test-3']) {
expect($(`#${listItem}`).html()).to.equal(`${listItem}`);
}
});
it('Can handle slugs with JSX expressions in markdown pages', async () => {
const html = await fixture.readFile('/slug/index.html');
const $ = cheerio.load(html);
expect($('h1').attr('id')).to.equal('my-blog-post');
});
it('Can handle code elements without extra spacing', async () => { it('Can handle code elements without extra spacing', async () => {
const html = await fixture.readFile('/code-element/index.html'); const html = await fixture.readFile('/code-element/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);
@ -53,14 +34,6 @@ describe('Astro Markdown', () => {
}); });
}); });
it('Can handle namespaced components in markdown', async () => {
const html = await fixture.readFile('/namespace/index.html');
const $ = cheerio.load(html);
expect($('h1').text()).to.equal('Hello Namespace!');
expect($('button').length).to.equal(1);
});
it('Correctly handles component children in markdown pages (#3319)', async () => { it('Correctly handles component children in markdown pages (#3319)', async () => {
const html = await fixture.readFile('/children/index.html'); const html = await fixture.readFile('/children/index.html');
@ -95,12 +68,6 @@ describe('Astro Markdown', () => {
expect($('pre > code').text()).to.equal('<!-- HTML comments in code fence -->'); expect($('pre > code').text()).to.equal('<!-- HTML comments in code fence -->');
}); });
// https://github.com/withastro/astro/issues/3254
it('Can handle scripts in markdown pages', async () => {
const html = await fixture.readFile('/script/index.html');
expect(html).not.to.match(new RegExp('/src/scripts/test.js'));
});
it('Can load more complex jsxy stuff', async () => { it('Can load more complex jsxy stuff', async () => {
const html = await fixture.readFile('/complex/index.html'); const html = await fixture.readFile('/complex/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);
@ -256,45 +223,6 @@ describe('Astro Markdown', () => {
expect($('#target > ol > li > ol > li').text()).to.equal('nested hello'); expect($('#target > ol > li > ol > li').text()).to.equal('nested hello');
}); });
it('Exposes raw markdown content', async () => {
const { raw } = JSON.parse(await fixture.readFile('/raw-content.json'));
expect(fixLineEndings(raw)).to.equal(
`\n## With components\n\n### Non-hydrated\n\n<Hello name="Astro Naut" />\n\n### Hydrated\n\n<Counter client:load />\n<SvelteButton client:load />\n`
);
});
it('Exposes HTML parser for raw markdown content', async () => {
const { compiled } = JSON.parse(await fixture.readFile('/raw-content.json'));
expect(fixLineEndings(compiled)).to.equal(
`<h2 id="with-components">With components</h2>\n<h3 id="non-hydrated">Non-hydrated</h3>\n<Hello name="Astro Naut" />\n<h3 id="hydrated">Hydrated</h3>\n<Counter client:load />\n<SvelteButton client:load />`
);
});
it('Allows referencing Vite env var names in markdown (#3412)', async () => {
const html = await fixture.readFile('/vite-env-vars/index.html');
const $ = cheerio.load(html);
// test 1: referencing an existing var name
expect($('code').eq(0).text()).to.equal('import.meta.env.SITE');
expect($('li').eq(0).text()).to.equal('import.meta.env.SITE');
expect($('code').eq(3).text()).to.contain('site: import.meta.env.SITE');
expect($('blockquote').text()).to.contain('import.meta.env.SITE');
// test 2: referencing a non-existing var name
expect($('code').eq(1).text()).to.equal('import.meta.env.TITLE');
expect($('li').eq(1).text()).to.equal('import.meta.env.TITLE');
expect($('code').eq(3).text()).to.contain('title: import.meta.env.TITLE');
expect($('blockquote').text()).to.contain('import.meta.env.TITLE');
// test 3: referencing `import.meta.env` itself (without any var name)
expect($('code').eq(2).text()).to.equal('import.meta.env');
expect($('li').eq(2).text()).to.equal('import.meta.env');
expect($('code').eq(3).text()).to.contain('// Use Vite env vars with import.meta.env');
expect($('blockquote').text()).to.match(/import\.meta\.env\s*$/);
});
it('Escapes HTML tags in code blocks', async () => { it('Escapes HTML tags in code blocks', async () => {
const html = await fixture.readFile('/code-in-md/index.html'); const html = await fixture.readFile('/code-in-md/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);
@ -305,42 +233,6 @@ describe('Astro Markdown', () => {
expect($('pre').html()).to.contain('&gt;This should also work without any problems.&lt;'); expect($('pre').html()).to.contain('&gt;This should also work without any problems.&lt;');
}); });
it('Allows defining slot contents in component children', async () => {
const html = await fixture.readFile('/slots/index.html');
const $ = cheerio.load(html);
const slots = $('article').eq(0);
expect(slots.find('> .fragmentSlot > div').text()).to.contain('1:');
expect(slots.find('> .fragmentSlot > div + p').text()).to.contain('2:');
expect(slots.find('> .pSlot > p[title="hello"]').text()).to.contain('3:');
expect(slots.find('> .defaultSlot').html()).to.match(
new RegExp(
`<div>4: Div in default slot</div>` +
// Optional extra paragraph due to the line breaks between components
`(<p></p>)?` +
`<p>5: Paragraph in fragment in default slot</p>` +
// Optional whitespace due to the line breaks between components
`[\s\n]*` +
`6: Regular text in default slot`
)
);
const nestedSlots = $('article').eq(1);
expect(nestedSlots.find('> .fragmentSlot').html()).to.contain('1:');
expect(nestedSlots.find('> .pSlot > p').text()).to.contain('2:');
expect(nestedSlots.find('> .defaultSlot > article').text().replace(/\s+/g, ' ')).to.equal(
`
3: nested fragmentSlot
4: nested pSlot
5: nested text in default slot
`.replace(/\s+/g, ' ')
);
expect($('article').eq(3).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
expect($('article').eq(4).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
});
it('Generate the right props for the layout', async () => { it('Generate the right props for the layout', async () => {
const html = await fixture.readFile('/layout-props/index.html'); const html = await fixture.readFile('/layout-props/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);

Some files were not shown because too many files have changed in this diff Show more