mirror of https://github.com/buster-so/buster.git
569 lines
17 KiB
TypeScript
569 lines
17 KiB
TypeScript
import type { ReportElements } from '@buster/database';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { markdownToPlatejs, platejsToMarkdown } from './platejs-conversions';
|
|
|
|
describe('markdownToPlatejs', () => {
|
|
it('should convert elaborate markdown to platejs', async () => {
|
|
const markdown = `# Welcome to the Plate Playground!
|
|
|
|
Experience a modern rich-text editor built with [Slate](https://slatejs.org) and [React](https://reactjs.org). This playground showcases just a part of Plate's capabilities. [Explore the documentation](/docs) to discover more.
|
|
|
|
## Collaborative Editing
|
|
|
|
Review and refine content seamlessly. Use [](/docs/suggestion) or to . Discuss changes using [comments](/docs/comment) on many text segments. You can even have annotations!
|
|
|
|
## AI-Powered Editing
|
|
|
|
Boost your productivity with integrated [AI SDK](/docs/ai). Press <kbd>⌘+J</kbd> or <kbd>Space</kbd> in an empty line to:
|
|
|
|
* Generate content (continue writing, summarize, explain)
|
|
* Edit existing text (improve, fix grammar, change tone)
|
|
|
|
## Rich Content Editing
|
|
|
|
Structure your content with [headings](/docs/heading), [lists](/docs/list), and [quotes](/docs/blockquote). Apply [marks](/docs/basic-marks) like **bold**, _italic_, <u>underline</u>, ~~strikethrough~~, and \`code\`. Use [autoformatting](/docs/autoformat) for [Markdown](/docs/markdown)-like shortcuts (e.g., <kbd>\\*</kbd> for lists, <kbd>#</kbd> for H1).
|
|
|
|
> Blockquotes are great for highlighting important information.
|
|
|
|
\`\`\`javascript
|
|
function hello() {
|
|
console.info('Code blocks are supported!');
|
|
}
|
|
\`\`\`
|
|
|
|
Create [links](/docs/link), [@mention](/docs/mention) users like [Alice](mention:Alice), or insert [emojis](/docs/emoji) ✨. Use the [slash command](/docs/slash-command) (/) for quick access to elements.
|
|
|
|
### How Plate Compares
|
|
|
|
Plate offers many features out-of-the-box as free, open-source plugins.
|
|
|
|
| **Feature** | **Plate (Free & OSS)** | **Tiptap** |
|
|
| ------------------- | ---------------------- | --------------------- |
|
|
| AI | ✅ | Paid Extension |
|
|
| Comments | ✅ | Paid Extension |
|
|
| Suggestions | ✅ | Paid (Comments Pro) |
|
|
| Emoji Picker | ✅ | Paid Extension |
|
|
| Table of Contents | ✅ | Paid Extension |
|
|
| Drag Handle | ✅ | Paid Extension |
|
|
| Collaboration (Yjs) | ✅ | Hocuspocus (OSS/Paid) |
|
|
|
|
### Images and Media
|
|
|
|
Embed rich media like images directly in your content. Supports [Media uploads](/docs/media) and [drag & drop](/docs/dnd) for a smooth experience.
|
|
|
|

|
|
|
|
<file isUpload="true" name="sample.pdf" src="https://s26.q4cdn.com/900411403/files/doc_downloads/test.pdf" />
|
|
|
|
<audio src="https://samplelib.com/lib/preview/mp3/sample-3s.mp3" />
|
|
|
|
### Table of Contents
|
|
|
|
<toc />
|
|
|
|
Here's an unordered list:
|
|
|
|
* First item with \`code snippet\`
|
|
* Second item with **bold text**
|
|
* Third item with _italic text_
|
|
* Nested item 1
|
|
* Nested item 2`;
|
|
const platejs = await markdownToPlatejs(markdown);
|
|
expect(platejs).toBeDefined();
|
|
});
|
|
|
|
it('real world markdown', async () => {
|
|
const markdown = `Our most popular mountain bike over the last 12 months is Mountain-200 Black, 38 with 825 units sold.
|
|
## Key Findings
|
|
- The top-selling mountain bike model is **Mountain-200 Black, 38**.
|
|
- It sold **825 units** in the last 12 months.
|
|
## Metric
|
|
<metric metricId="d3bf75d2-28f7-408e-93ec-ae06b509ad27" />
|
|
## Context
|
|
- I focused specifically on complete bicycle products in the **Mountain Bikes** subcategory within the broader **Bikes** category to avoid counting components or frames.
|
|
- I measured popularity by **units sold**, which reflects the number of bikes customers purchased.
|
|
- Timeframe defaults to the **last 12 months** to show a current view.
|
|
## Methodology
|
|
- Data sources: Sales order lines and headers, and product catalog tables in the operational analytics database.
|
|
- Filters:
|
|
- Product Category = "Bikes"
|
|
- Product Subcategory = "Mountain Bikes"
|
|
- Order Date between CURRENT_DATE - 12 months and CURRENT_DATE
|
|
- Calculation:
|
|
- For each mountain bike product, sum of sales order quantities from sales order details.
|
|
- Select the product with the highest total units sold.
|
|
- Notes on definitions:
|
|
- "Most popular" defined as highest **units sold**; alternative definitions could use revenue or number of distinct orders, but units sold most directly represents product popularity by volume.
|
|
- Product names are used as the display label to identify the specific model.
|
|
- Alternatives considered:
|
|
- Using revenue-based popularity could favor higher-priced bikes; I chose units to avoid price bias.
|
|
- Using the riding discipline filter (e.g., Mountain) was considered, but I used the explicit Mountain Bikes subcategory to exclude components.
|
|
`;
|
|
const platejs = await markdownToPlatejs(markdown);
|
|
expect(platejs).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('platejsToMarkdown', () => {
|
|
it('should convert platejs to markdown', async () => {
|
|
const markdown = `This is a simple paragraph.\n`;
|
|
const elements: ReportElements = [
|
|
{
|
|
type: 'p',
|
|
children: [
|
|
{
|
|
text: 'This is a simple paragraph.',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const markdown2 = await platejsToMarkdown(elements);
|
|
expect(markdown2).toBe(markdown);
|
|
});
|
|
|
|
it('should convert callout platejs element to markdown', async () => {
|
|
const elements: ReportElements = [
|
|
{
|
|
type: 'h1',
|
|
children: [
|
|
{
|
|
text: 'Main Title',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'p',
|
|
children: [
|
|
{
|
|
text: 'This paragraph has ',
|
|
},
|
|
{
|
|
text: 'bold text',
|
|
bold: true,
|
|
},
|
|
{
|
|
text: ' in it.',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const markdown2 = await platejsToMarkdown(elements);
|
|
const markdown = `# Main Title\n\nThis paragraph has **bold text** in it.\n`;
|
|
expect(markdown2).toBe(markdown);
|
|
});
|
|
|
|
it('should convert callout platejs element to markdown', async () => {
|
|
const elements: ReportElements = [
|
|
{
|
|
type: 'callout',
|
|
icon: '⚠️',
|
|
variant: 'warning',
|
|
children: [
|
|
{
|
|
type: 'p' as const,
|
|
children: [
|
|
{
|
|
text: 'This is a simple paragraph.',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const markdownFromPlatejs = await platejsToMarkdown(elements);
|
|
|
|
const expectedMarkdown = `<callout icon="⚠️">This is a simple paragraph.\n</callout>\n`;
|
|
expect(markdownFromPlatejs).toBe(expectedMarkdown);
|
|
});
|
|
|
|
it('should convert callout platejs element to markdown', async () => {
|
|
const elements: ReportElements = [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Our most popular mountain bike over the last 12 months is Mountain-200 Black, 38 with 825 units sold.',
|
|
},
|
|
],
|
|
type: 'p',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Key Findings',
|
|
},
|
|
],
|
|
type: 'h2',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'The top-selling mountain bike model is ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'Mountain-200 Black, 38',
|
|
},
|
|
{
|
|
text: '.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'It sold ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: '825 units',
|
|
},
|
|
{
|
|
text: ' in the last 12 months.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Metric',
|
|
},
|
|
],
|
|
type: 'h2',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
text: '<metric>\n',
|
|
},
|
|
{
|
|
text: '',
|
|
},
|
|
{
|
|
text: '\n</metric>',
|
|
},
|
|
],
|
|
type: 'p',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Context',
|
|
},
|
|
],
|
|
type: 'h2',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'I focused specifically on complete bicycle products in the ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'Mountain Bikes',
|
|
},
|
|
{
|
|
text: ' subcategory within the broader ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'Bikes',
|
|
},
|
|
{
|
|
text: ' category to avoid counting components or frames.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'I measured popularity by ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'units sold',
|
|
},
|
|
{
|
|
text: ', which reflects the number of bikes customers purchased.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Timeframe defaults to the ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'last 12 months',
|
|
},
|
|
{
|
|
text: ' to show a current view.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Methodology',
|
|
},
|
|
],
|
|
type: 'h2',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Data sources: Sales order lines and headers, and product catalog tables in the operational analytics database.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Filters:',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Product Category = "Bikes"',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Product Subcategory = "Mountain Bikes"',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Order Date between CURRENT_DATE - 12 months and CURRENT_DATE',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Calculation:',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'For each mountain bike product, sum of sales order quantities from sales order details.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Select the product with the highest total units sold.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Notes on definitions:',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: '"Most popular" defined as highest ',
|
|
},
|
|
{
|
|
bold: true,
|
|
text: 'units sold',
|
|
},
|
|
{
|
|
text: '; alternative definitions could use revenue or number of distinct orders, but units sold most directly represents product popularity by volume.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Product names are used as the display label to identify the specific model.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Alternatives considered:',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Using revenue-based popularity could favor higher-priced bikes; I chose units to avoid price bias.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
text: 'Using the riding discipline filter (e.g., Mountain) was considered, but I used the explicit Mountain Bikes subcategory to exclude components.',
|
|
},
|
|
],
|
|
type: 'lic',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
],
|
|
type: 'li',
|
|
},
|
|
],
|
|
type: 'ul',
|
|
},
|
|
];
|
|
});
|
|
});
|