snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-16 04:01:20 +05:00
commit 702cc698a7
9990 changed files with 1073618 additions and 0 deletions

View File

@@ -0,0 +1,334 @@
import { ParagraphBlockSchema } from '@blocksuite/affine-model';
import {
BlockMarkdownAdapterExtension,
type BlockMarkdownAdapterMatcher,
IN_PARAGRAPH_NODE_CONTEXT_KEY,
isCalloutNode,
type MarkdownAST,
type MarkdownDeltaConverter,
} from '@blocksuite/affine-shared/adapters';
import type { BlockSnapshot, DeltaInsert } from '@blocksuite/store';
import { nanoid } from '@blocksuite/store';
import type { Blockquote, Heading, List, ListItem } from 'mdast';
/**
* Extend the HeadingData type to include the collapsed property
*/
declare module 'mdast' {
interface HeadingData {
collapsed?: boolean;
}
}
const PARAGRAPH_MDAST_TYPE = new Set(['paragraph', 'heading', 'blockquote']);
const isParagraphMDASTType = (node: MarkdownAST) =>
PARAGRAPH_MDAST_TYPE.has(node.type);
const joinDeltaLines = (
lines: DeltaInsert[][],
prefix?: string
): DeltaInsert[] => {
const deltas: DeltaInsert[] = [];
lines.forEach(line => {
if (deltas.length) deltas.push({ insert: '\n' });
if (prefix) deltas.push({ insert: prefix });
deltas.push(...line);
});
return deltas;
};
const flattenListItemToDelta = (
node: ListItem,
deltaConverter: MarkdownDeltaConverter,
prefix: string,
depth: number
): DeltaInsert[] => {
const firstParagraph = node.children[0];
const lines: DeltaInsert[][] = [];
if (firstParagraph?.type === 'paragraph') {
lines.push([
{ insert: prefix },
...deltaConverter.astToDelta(firstParagraph),
]);
} else {
lines.push([{ insert: prefix.trimEnd() }]);
}
node.children
.slice(firstParagraph?.type === 'paragraph' ? 1 : 0)
.forEach(child => {
const delta = flattenMarkdownBlockToDelta(
child as MarkdownAST,
deltaConverter,
depth + 1
);
if (delta.length) {
lines.push(delta);
}
});
return joinDeltaLines(lines);
};
const flattenMarkdownBlockToDelta = (
node: MarkdownAST,
deltaConverter: MarkdownDeltaConverter,
depth = 0
): DeltaInsert[] => {
switch (node.type) {
case 'paragraph':
case 'heading':
return deltaConverter.astToDelta(node);
case 'list': {
const list = node as List;
return joinDeltaLines(
list.children.map((item, index) => {
const order = (list.start ?? 1) + index;
const prefix =
' '.repeat(depth) + (list.ordered ? `${order}. ` : '- ');
return flattenListItemToDelta(item, deltaConverter, prefix, depth);
})
);
}
case 'blockquote':
return flattenBlockquoteToDelta(node as Blockquote, deltaConverter);
default:
return 'children' in node
? joinDeltaLines(
(node.children as MarkdownAST[]).map(child =>
flattenMarkdownBlockToDelta(child, deltaConverter, depth)
)
)
: [];
}
};
const flattenBlockquoteToDelta = (
node: Blockquote,
deltaConverter: MarkdownDeltaConverter
) =>
joinDeltaLines(
node.children.map(child =>
flattenMarkdownBlockToDelta(child as MarkdownAST, deltaConverter)
)
);
const getSnapshotTextDelta = (node: BlockSnapshot): DeltaInsert[] => {
const text = (node.props.text ?? { delta: [] }) as {
delta: DeltaInsert[];
};
return text.delta;
};
const flattenSnapshotBlockToDelta = (
node: BlockSnapshot,
depth = 0
): DeltaInsert[] => {
if (node.flavour === 'affine:list') {
const type = node.props.type;
const order = (node.props.order as number | undefined) ?? 1;
const prefix =
' '.repeat(depth) + (type === 'numbered' ? `${order}. ` : '- ');
return joinDeltaLines([
[{ insert: prefix }, ...getSnapshotTextDelta(node)],
...node.children.map(child =>
flattenSnapshotBlockToDelta(child, depth + 1)
),
]);
}
return joinDeltaLines([
getSnapshotTextDelta(node),
...node.children.map(child => flattenSnapshotBlockToDelta(child, depth)),
]);
};
const flattenQuoteSnapshotToDelta = (
text: DeltaInsert[],
children: BlockSnapshot[]
) =>
joinDeltaLines([
text,
...children.map(child => flattenSnapshotBlockToDelta(child)),
]);
export const paragraphBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
{
flavour: ParagraphBlockSchema.model.flavour,
toMatch: o => isParagraphMDASTType(o.node) && !isCalloutNode(o.node),
fromMatch: o => o.node.flavour === ParagraphBlockSchema.model.flavour,
toBlockSnapshot: {
enter: (o, context) => {
const { walkerContext, deltaConverter } = context;
switch (o.node.type) {
case 'paragraph': {
walkerContext.setGlobalContext(IN_PARAGRAPH_NODE_CONTEXT_KEY, true);
walkerContext
.openNode(
{
type: 'block',
id: nanoid(),
flavour: 'affine:paragraph',
props: {
type: 'text',
text: {
'$blocksuite:internal:text$': true,
delta: deltaConverter.astToDelta(o.node),
},
},
children: [],
},
'children'
)
.closeNode();
break;
}
case 'heading': {
const isCollapsed = !!o.node.data?.collapsed;
walkerContext
.openNode(
{
type: 'block',
id: nanoid(),
flavour: 'affine:paragraph',
props: {
type: `h${o.node.depth}`,
collapsed: isCollapsed,
text: {
'$blocksuite:internal:text$': true,
delta: deltaConverter.astToDelta(o.node),
},
},
children: [],
},
'children'
)
.closeNode();
break;
}
case 'blockquote': {
if (isCalloutNode(o.node)) {
return;
}
walkerContext
.openNode(
{
type: 'block',
id: nanoid(),
flavour: 'affine:paragraph',
props: {
type: 'quote',
text: {
'$blocksuite:internal:text$': true,
delta: flattenBlockquoteToDelta(
o.node as Blockquote,
deltaConverter
),
},
},
children: [],
},
'children'
)
.closeNode();
walkerContext.skipAllChildren();
break;
}
}
},
leave: (o, context) => {
if (o.node.type === 'paragraph') {
const { walkerContext } = context;
walkerContext.setGlobalContext(IN_PARAGRAPH_NODE_CONTEXT_KEY, false);
}
},
},
fromBlockSnapshot: {
enter: (o, context) => {
const { walkerContext, deltaConverter } = context;
const paragraphDepth = (walkerContext.getGlobalContext(
'affine:paragraph:depth'
) ?? 0) as number;
const text = (o.node.props.text ?? { delta: [] }) as {
delta: DeltaInsert[];
};
switch (o.node.props.type) {
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6': {
walkerContext
.openNode(
{
type: 'heading',
depth: parseInt(o.node.props.type[1]) as Heading['depth'],
children: deltaConverter.deltaToAST(
text.delta,
paragraphDepth
),
},
'children'
)
.closeNode();
break;
}
case 'text': {
walkerContext
.openNode(
{
type: 'paragraph',
children: deltaConverter.deltaToAST(
text.delta,
paragraphDepth
),
},
'children'
)
.closeNode();
break;
}
case 'quote': {
const quoteDelta = flattenQuoteSnapshotToDelta(
text.delta,
o.node.children
);
walkerContext
.openNode(
{
type: 'blockquote',
children: [],
},
'children'
)
.openNode(
{
type: 'paragraph',
children: deltaConverter.deltaToAST(quoteDelta),
},
'children'
)
.closeNode()
.closeNode();
walkerContext.skipAllChildren();
break;
}
}
walkerContext.setGlobalContext(
'affine:paragraph:depth',
paragraphDepth + 1
);
},
leave: (_, context) => {
const { walkerContext } = context;
walkerContext.setGlobalContext(
'affine:paragraph:depth',
(walkerContext.getGlobalContext('affine:paragraph:depth') as number) -
1
);
},
},
};
export const ParagraphBlockMarkdownAdapterExtension =
BlockMarkdownAdapterExtension(paragraphBlockMarkdownAdapterMatcher);