summaryrefslogtreecommitdiff
path: root/packages/markdown/remark/src
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-12-22 10:38:03 -0500
committerGravatar GitHub <noreply@github.com> 2022-12-22 10:38:03 -0500
commit853081d1c857d8ad8a9634c37ed8fd123d32d241 (patch)
tree39bbad51f665c2f771fc0d9900656e7d09640b76 /packages/markdown/remark/src
parentb64081deed88271a4aa55d66468a10fea235e0a9 (diff)
downloadastro-853081d1c857d8ad8a9634c37ed8fd123d32d241.tar.gz
astro-853081d1c857d8ad8a9634c37ed8fd123d32d241.tar.zst
astro-853081d1c857d8ad8a9634c37ed8fd123d32d241.zip
[Content] Throw on relative image usage (#5648)
* chore: add rel image error plugin * deps: mdast, mdast types * chore: add rel image throw to mdx * refactor: doc rel image path plugin * fix: respect experimental flag in md remark * chore: changeset * deps: remove mdast package * fix: resolve contentDir from config * fix: apply MDX plugin after user plugins * fix: stub out contentDir
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r--packages/markdown/remark/src/index.ts8
-rw-r--r--packages/markdown/remark/src/remark-content-rel-image-error.ts52
-rw-r--r--packages/markdown/remark/src/types.ts4
3 files changed, 64 insertions, 0 deletions
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts
index 6d69bcd20..07df39ee8 100644
--- a/packages/markdown/remark/src/index.ts
+++ b/packages/markdown/remark/src/index.ts
@@ -14,6 +14,7 @@ import remarkPrism from './remark-prism.js';
import scopedStyles from './remark-scoped-styles.js';
import remarkShiki from './remark-shiki.js';
import remarkUnwrap from './remark-unwrap.js';
+import toRemarkContentRelImageError from './remark-content-rel-image-error.js';
import rehypeRaw from 'rehype-raw';
import rehypeStringify from 'rehype-stringify';
@@ -42,6 +43,8 @@ export async function renderMarkdown(
remarkRehype = {},
extendDefaultPlugins = false,
isAstroFlavoredMd = false,
+ isExperimentalContentCollections = false,
+ contentDir,
} = opts;
const input = new VFile({ value: content, path: fileURL });
const scopedClassName = opts.$?.scopedClassName;
@@ -73,6 +76,11 @@ export async function renderMarkdown(
parser.use([remarkPrism(scopedClassName)]);
}
+ // Apply later in case user plugins resolve relative image paths
+ if (isExperimentalContentCollections) {
+ parser.use([toRemarkContentRelImageError({ contentDir })]);
+ }
+
parser.use([
[
markdownToHtml as any,
diff --git a/packages/markdown/remark/src/remark-content-rel-image-error.ts b/packages/markdown/remark/src/remark-content-rel-image-error.ts
new file mode 100644
index 000000000..0704ebdd1
--- /dev/null
+++ b/packages/markdown/remark/src/remark-content-rel-image-error.ts
@@ -0,0 +1,52 @@
+import type { Image } from 'mdast';
+import { visit } from 'unist-util-visit';
+import { pathToFileURL } from 'url';
+import type { VFile } from 'vfile';
+
+/**
+ * `src/content/` does not support relative image paths.
+ * This plugin throws an error if any are found
+ */
+export default function toRemarkContentRelImageError({ contentDir }: { contentDir: URL }) {
+ return function remarkContentRelImageError() {
+ return (tree: any, vfile: VFile) => {
+ const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href);
+ if (!isContentFile) return;
+
+ const relImagePaths = new Set<string>();
+ visit(tree, 'image', function raiseError(node: Image) {
+ console.log(node.url);
+ if (isRelativePath(node.url)) {
+ relImagePaths.add(node.url);
+ }
+ });
+ if (relImagePaths.size === 0) return;
+
+ const errorMessage =
+ `Relative image paths are not supported in the content/ directory. Place local images in the public/ directory and use absolute paths (see https://docs.astro.build/en/guides/images/#in-markdown-files)\n` +
+ [...relImagePaths].map((path) => JSON.stringify(path)).join(',\n');
+
+ // Throw raw string to use `astro:markdown` default formatting
+ throw errorMessage;
+ };
+ };
+}
+
+// Following utils taken from `packages/astro/src/core/path.ts`:
+
+function isRelativePath(path: string) {
+ return startsWithDotDotSlash(path) || startsWithDotSlash(path);
+}
+
+function startsWithDotDotSlash(path: string) {
+ const c1 = path[0];
+ const c2 = path[1];
+ const c3 = path[2];
+ return c1 === '.' && c2 === '.' && c3 === '/';
+}
+
+function startsWithDotSlash(path: string) {
+ const c1 = path[0];
+ const c2 = path[1];
+ return c1 === '.' && c2 === '/';
+}
diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts
index 76dfe9b73..15465d950 100644
--- a/packages/markdown/remark/src/types.ts
+++ b/packages/markdown/remark/src/types.ts
@@ -54,6 +54,10 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
scopedClassName: string | null;
};
isAstroFlavoredMd?: boolean;
+ /** Used to prevent relative image imports from `src/content/` */
+ isExperimentalContentCollections?: boolean;
+ /** Used to prevent relative image imports from `src/content/` */
+ contentDir: URL;
}
export interface MarkdownHeading {