Convert Markdown and GitHub Flavoured Markdown into Slack Block Kit objects.
This is the maintained @berrydev-ai/mack fork of tryfabric/mack. The original MIT license and attribution are retained.
Requires Node.js 22.13 or newer. Node 24 LTS is recommended for development. CommonJS and ES module consumers are supported; markdownToBlocks returns a Promise in both.
The fork is being prepared for its first release under the new package name. To use the local checkout before publication, build a tarball:
pnpm install --frozen-lockfile
pnpm packInstall the resulting .tgz in your application with pnpm add /absolute/path/to/the/package.tgz. Published tarballs include JavaScript and TypeScript declarations and require no build tools at installation time.
After an npm release is available:
pnpm add @berrydev-ai/mackimport {markdownToBlocks} from '@berrydev-ai/mack';
const blocks = await markdownToBlocks(`
# Hello world
* bulleted item 1
* bulleted item 2
abc _123_

`);CommonJS:
const {markdownToBlocks} = require('@berrydev-ai/mack');
async function example() {
const blocks = await markdownToBlocks('# Hello world');
console.log(blocks);
}
example();The result can be supplied as the blocks field of a Slack message. Mack does not send messages or require Slack credentials.
import type {KnownBlock} from '@slack/types';
function markdownToBlocks(
text: string,
options?: ParsingOptions
): Promise<KnownBlock[]>;
interface ParsingOptions {
lists?: ListOptions;
}
interface ListOptions {
// Defaults to 'β’ ' for both checked and unchecked items.
checkboxPrefix?: (checked: boolean) => string;
}ParsingOptions and ListOptions are exported from @berrydev-ai/mack.
const blocks = await markdownToBlocks('- [x] Done\n- [ ] Pending', {
lists: {checkboxPrefix: checked => (checked ? 'β ' : 'β ')},
});- Emphasis, bold, strikethrough, inline code, links, and line breaks
- Headers, code blocks, and dividers
- Simple ordered, unordered, and checkbox lists
- Markdown images and standalone HTML
<img>tags - Paragraph block quotes and tables rendered as text
Section text is truncated to 3,000 characters, headers to 150, and image titles and alternative text to 2,000. Truncation can cut formatting or links short. The caller must handle Slack's per-message block-count limit.
Nested lists, multiple paragraphs within a list item, and lists/headings/images inside block quotes are not fully supported. Table alignment is not preserved. General HTML is ignored; invalid HTML images without a usable src are omitted. Mack does not validate or fetch image URLs.
Use the pnpm version pinned in package.json (12.3.4). See pnpm installation for setup. .nvmrc selects Node 24.
pnpm install --frozen-lockfile
pnpm run check
pnpm run test:package
pnpm auditcheck runs the tests, ESLint, Prettier, and the library build. test:package packs and installs the library with production dependencies in a temporary consumer project, then verifies CommonJS, ES modules, and declarations. It needs registry access and removes its temporary files afterward. Use pnpm run fix to apply lint and formatting fixes.
Commit pnpm-lock.yaml whenever dependencies change. CI checks Node 22.13, the latest Node 22, Node 24, and Node 26. Weekly dependency and GitHub Actions updates are configured through Dependabot.
The first fork version is staged as 2.0.0-0 to signal the package rename and Node support change. No npm release is implied by this checkout. See the modernization notes for migration details.
Before publishing, provision the @berrydev-ai npm scope and an NPM_TOKEN secret with publish access. GitHub Packages uses the workflow's GITHUB_TOKEN with package write permission. The release workflow publishes to both registries after validation; it requires a v-prefixed tag matching package.json and publishes prereleases to next.
Update the version, run the development checks, and publish a GitHub release for the matching version tag when ready. The manual Release workflow accepts an existing matching tag. Each registry is a separate matrix job, so retry only the failed job after a partial publication.