Files
AFFiNE-Mirror/blocksuite/affine/blocks/image/src/adapters/markdown.ts
T
donteatfriedrice 26ece014f1 fix(editor): support relative image reference path when importing zip with images (#12264)
Closes: [BS-3385](https://linear.app/affine-design/issue/BS-3385/markdown类型的导入,支持media文件和md文件不在同目录的情况)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added utility functions to resolve and normalize image file paths in markdown and HTML imports.
  - Introduced middleware to provide full file path context during file import and transformation.
  - Added new types for improved asset and file management in zip imports.

- **Refactor**
  - Centralized and simplified image processing logic across HTML, Markdown, and Notion HTML adapters for improved maintainability.
  - Enhanced type safety and clarity in file and asset handling during zip imports.

- **Tests**
  - Added comprehensive tests for image file path resolution utility.

- **Documentation**
  - Improved inline code comments explaining file path resolution logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-14 02:30:30 +00:00

67 lines
1.9 KiB
TypeScript

import { ImageBlockSchema } from '@blocksuite/affine-model';
import {
BlockMarkdownAdapterExtension,
type BlockMarkdownAdapterMatcher,
type MarkdownAST,
} from '@blocksuite/affine-shared/adapters';
import { getAssetName } from '@blocksuite/store';
import { processImageNodeToBlock } from './utils';
const isImageNode = (node: MarkdownAST) => node.type === 'image';
export const imageBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
flavour: ImageBlockSchema.model.flavour,
toMatch: o => isImageNode(o.node),
fromMatch: o => o.node.flavour === ImageBlockSchema.model.flavour,
toBlockSnapshot: {
enter: async (o, context) => {
const { configs, walkerContext, assets } = context;
const imageURL = 'url' in o.node ? o.node.url : '';
if (!assets || !imageURL) {
return;
}
await processImageNodeToBlock(imageURL, walkerContext, assets, configs);
},
},
fromBlockSnapshot: {
enter: async (o, context) => {
const { assets, walkerContext, updateAssetIds } = context;
const blobId = (o.node.props.sourceId ?? '') as string;
if (!assets) {
return;
}
await assets.readFromBlob(blobId);
const blob = assets.getAssets().get(blobId);
if (!blob) {
return;
}
const blobName = getAssetName(assets.getAssets(), blobId);
updateAssetIds?.(blobId);
walkerContext
.openNode(
{
type: 'paragraph',
children: [],
},
'children'
)
.openNode(
{
type: 'image',
url: `assets/${blobName}`,
title: (o.node.props.caption as string | undefined) ?? null,
alt: (blob as File).name ?? null,
},
'children'
)
.closeNode()
.closeNode();
},
},
};
export const ImageBlockMarkdownAdapterExtension = BlockMarkdownAdapterExtension(
imageBlockMarkdownAdapterMatcher
);