Skip to content

Commit

Permalink
🪆 Improve block nesting transform
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 committed Oct 13, 2023
1 parent cd531c3 commit 2a6179c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/five-cats-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-transforms': patch
---

Block nesting updates
35 changes: 34 additions & 1 deletion packages/myst-transforms/src/blocks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import { describe, expect, test } from 'vitest';
import { u } from 'unist-builder';
import { VFile } from 'vfile';
import { blockMetadataTransform } from './blocks';
import { blockMetadataTransform, blockNestingTransform } from './blocks';

describe('Test blockMetadataTransform', () => {
test.each([
[
['a', 'block', 'b'],
['block>a', 'block', 'block>b'],
],
[
['block', 'b'],
['block', 'block>b'],
],
[['a', 'b'], ['block>a,b']],
[
['block', 'block'],
['block', 'block'],
],
[
['a', 'block', 'b', 'c'],
['block>a', 'block', 'block>b,c'],
],
])('nestBlock(%s, %s)}', (a, b) => {
const mdast = u(
'root',
a.map((type) => ({ type })),
) as any;
blockNestingTransform(mdast);
expect(
mdast.children.map(
({ type, children }) =>
`${type}${
children && children.length > 0 ? '>' + children.map(({ type: t }) => t).join(',') : ''
}`,
),
).toEqual(b);
});
test('metadata is parsed and becomes data', async () => {
const mdast = u('root', [
u('block', { meta: '{"key": "value"}' }, [
Expand Down
35 changes: 21 additions & 14 deletions packages/myst-transforms/src/blocks.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import type { VFile } from 'vfile';
import type { Plugin } from 'unified';
import type { Node, Parent } from 'myst-spec';
import { select, selectAll } from 'unist-util-select';
import type { Node } from 'myst-spec';
import { selectAll } from 'unist-util-select';
import type { GenericNode, GenericParent } from 'myst-common';
import { RuleId, fileError, normalizeLabel } from 'myst-common';
import type { Code } from 'myst-spec-ext';

export function blockNestingTransform(mdast: GenericParent) {
if (!select('block', mdast)) {
const blockNode = { type: 'block', children: mdast.children as Node[] };
(mdast as Parent).children = [blockNode];
function nestBlock(tree: GenericParent): void {
const start = tree.children.findIndex((child) => (child.type as any) !== 'block');
if (start === -1) return;
const end = tree.children.findIndex((child, i) => (child.type as any) === 'block' && i > start);
if (end === -1) {
tree.children = [
...tree.children.slice(0, start),
{ type: 'block', children: tree.children.slice(start) as Node[] },
];
return;
}
if ((mdast.children[0].type as any) !== 'block') {
// There are some blocks, but the first one is not!
// Lift the content until the first block into a block
const index = mdast.children.findIndex((child) => (child.type as any) === 'block');
const firstBlock = { type: 'block', children: mdast.children.slice(0, index) as Node[] };
const otherBlocks = mdast.children.slice(index) as Parent[];
(mdast as Parent).children = [firstBlock, ...otherBlocks];
}
tree.children = [
...tree.children.slice(0, start),
{ type: 'block', children: tree.children.slice(start, end) as Node[] },
...tree.children.slice(end),
];
nestBlock(tree);
}

export function blockNestingTransform(tree: GenericParent) {
nestBlock(tree);
}

export const blockNestingPlugin: Plugin<[], GenericParent, GenericParent> = () => (tree) => {
Expand Down

0 comments on commit 2a6179c

Please sign in to comment.