Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
token: ${{ secrets.ACTIONS_BRANCH_PROTECTION_BYPASS }}
fetch-depth: 0

- name: Install pnpm with version specified in 'packageManager'
uses: pnpm/action-setup@v4

- name: Install Node.js 20
uses: actions/setup-node@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ jobs:
with:
token: ${{ secrets.ACTIONS_BRANCH_PROTECTION_BYPASS }}

- name: Install pnpm with version specified in 'packageManager'
uses: pnpm/action-setup@v4

- name: Install Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
Expand Down
301 changes: 233 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,259 @@
# TypeScript Library Template
# remark-github-markdown-alerts

An opinionated production-ready TypeScript library template with automated builds, testing, and releases.
Transform GitHub-style markdown alerts into HTML using the [unified][unified] ecosystem

## Tech Stack

- **TypeScript** - Strict configuration for type safety
- **Rollup** - Builds both CommonJS and ESM formats
- **Biome** - Fast linting and formatting
- **Vitest** - Testing with coverage reports
- **Husky** - Pre-commit hooks for code quality
- **Semantic Release** - Automated versioning and releases
- **pnpm** - Fast package management with Corepack
- **GitHub Actions** - CI/CD pipeline
> **Why this package over [jaywcjlove/remark-github-blockquote-alert][alternative]?**
> First of all, the mentioned project is a great one and has been there for a while, however it's design indicates slightly different usage - it's rather for out of the box implementation of 1:1 GitHub Alerts visuals than for custom implementations.
>
> On the other hand, the [neg4n/remark-github-markdown-alerts](https://github.com/neg4n/remark-github-markdown-alerts) offers maximum extensibility with granular configuration for class names, HTML elements, and custom icons. It's both ESM and CJS compatible, completely unstyled by default (no opinionated GitHub CSS), adaptable to any design system

## Features

- 📦 **Dual Package Support** - Outputs CommonJS and ESM builds
- 🛡️ **Type Safety** - Extremely strict TypeScript configuration
- ✅ **Build Validation** - Uses `@arethetypeswrong/cli` to check package exports
- 🧪 **Automated Testing** - Vitest with coverage reporting
- 🎨 **Code Quality** - Biome linting and formatting with pre-commit hooks
- 🚀 **Automated Releases** - Semantic versioning with changelog generation
- ⚙️ **CI/CD Pipeline** - GitHub Actions for testing and publishing
- 🔧 **One-Click Setup** - Automated repository configuration with `init.sh`
- 🎯 **GitHub compatibility** - Renders `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, and `[!CAUTION]` alerts
- 🛡️ **100% test coverage** - Comprehensive test suite
- 🔧 **Maximum extensibility** - Configure HTML elements, class names, and custom icons per alert type
- 🎨 **Unstyled by default** - No opinionated CSS, works with any design system
- 📦 **TypeScript support** - Batteries included with typed HTML tags and more
- 🔧 **[Unified][unified] ecosystem** - Works with remark, rehype and can be easily used with [react-markdown][react-markdown]

## Installation

```sh
npm i remark-github-markdown-alerts
# or
yarn add remark-github-markdown-alerts
# or
pnpm add remark-github-markdown-alerts
# or
bun add remark-github-markdown-alerts
```

## Usage

### With remark

```ts
import { remark } from 'remark'
import remarkHtml from 'remark-html'
import { remarkGitHubAlerts } from 'remark-github-markdown-alerts'

const processor = remark()
.use(remarkGitHubAlerts)
.use(remarkHtml)

const markdown = `
> [!NOTE]
> This is a note alert with some important information.

> [!WARNING] Custom title
> This is a warning with a custom title.
`

const result = await processor.process(markdown)
console.log(result.toString())
```


### With React Server Components and custom icons

Using [`react-markdown`][react-markdown] and [`common-tags`][common-tags]'s `html` helper, example code in Next.js application:

```tsx
import { MarkdownAsync } from 'react-markdown'
import { html } from 'common-tags'
import { remarkGitHubAlerts } from 'remark-github-markdown-alerts'

// ⚠️ Use only in server environment (RSC)
const customIcon = html`<svg viewBox="0 0 16 16" width="16" height="16">
<path fill="currentColor" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zM8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>`

async function ServerMarkdown() {
const markdown = `
> [!NOTE]
> Server-rendered alert with custom SVG icon
`

return (
<MarkdownAsync
remarkPlugins={[
[remarkGitHubAlerts, {
alerts: {
note: {
iconElementHtml: customIcon
}
}
}]
]}
>
{markdown}
</MarkdownAsync>
)
}
```

### With [unified][unified] pipeline

## Setup
```ts
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
import { remarkGitHubAlerts } from 'remark-github-markdown-alerts'

### 1. Quick Start
const processor = unified()
.use(remarkParse)
.use(remarkGitHubAlerts)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeStringify, { allowDangerousHtml: true })

Run the initialization script to automatically configure your repository:
const result = await processor.process('> [!IMPORTANT]\\n> Critical information here!')
```

## Alert Types

```markdown
> [!NOTE]
> Information that users should know.

> [!TIP]
> Helpful advice for better results.

> [!IMPORTANT]
> Key information for success.

> [!WARNING]
> Urgent information to avoid problems.

> [!CAUTION]
> Risks or negative outcomes.
```

### Custom Titles

```markdown
> [!NOTE] Custom title
> Content with custom title.

```bash
# One-command setup
./init.sh
> [!WARNING] Breaking Changes
> This version has breaking changes.
```

This script will:
- 🔒 **Create repository rulesets** for branch protection (linear history, PR reviews)
- 🚫 **Disable unnecessary features** (wikis, projects, squash/merge commits)
- ⚙️ **Configure merge settings** (rebase-only workflow)
- ✅ **Verify GitHub Actions** are enabled
- 🔑 **Check required secrets** and provide setup instructions
## Configuration

### 2. Required Secrets
The plugin accepts an options object with two main sections:

The script will guide you to set up these secrets if missing:
### 🎛️ Global Configuration (`defaultConfig`)

**NPM_TOKEN** (for publishing):
```bash
# Generate NPM token with OTP for enhanced security
pnpm token create --otp=<YOUR_OTP> --registry=https://registry.npmjs.org/
Applied to all alert types unless overridden:

# Set the token as repository secret
gh secret set NPM_TOKEN --body "your-npm-token-here"
```ts
import { remarkGitHubAlerts } from 'remark-github-markdown-alerts'

const options = {
defaultConfig: {
// 🎨 CSS Class Names
classNames: {
container: 'alert', // Main wrapper class
icon: 'alert-icon', // Icon container class
title: 'alert-title', // Title/header class
content: 'alert-content' // Content body class
},

// 🏗️ HTML Elements
tags: {
container: 'section', // Wrapper element
icon: 'i', // Icon element
title: 'h3', // Title element
content: 'div' // Content element
},

// 🔧 Custom Icon
iconElementHtml: '🔔' // Default icon HTML
}
}
```

**ACTIONS_BRANCH_PROTECTION_BYPASS** (for automated releases):
```bash
# Create Personal Access Token with 'repo' permissions
# Visit: https://github.com/settings/personal-access-tokens/new
### 🎯 Alert-Specific Configuration (`alerts`)

Override settings for individual alert types:

```ts
const options = {
// ... defaultConfig above
alerts: {
note: {
iconElementHtml: '<svg viewBox="0 0 16 16">...</svg>',
classNames: {
container: 'note-container',
icon: 'note-icon'
}
},
warning: {
tags: {
container: 'aside',
title: 'h4'
}
}
}
}

# Set the PAT as repository secret
gh secret set ACTIONS_BRANCH_PROTECTION_BYPASS --body "your-pat-token-here"
const processor = remark().use(remarkGitHubAlerts, options)
```

#### Why Linear History?
### 📋 Configuration Reference

#### Default Configuration Options

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| **CSS Classes** | | | |
| `classNames.container` | `string` | `'markdown-alert'` | Main alert container class |
| `classNames.icon` | `string` | `'markdown-alert-icon'` | Icon element class |
| `classNames.title` | `string` | `'markdown-alert-title'` | Title/header class |
| `classNames.content` | `string` | `'markdown-alert-content'` | Content body class |
| **HTML Elements** | | | |
| `tags.container` | `HtmlElement` | `'div'` | Alert wrapper element |
| `tags.icon` | `HtmlElement` | `'span'` | Icon container element |
| `tags.title` | `HtmlElement` | `'div'` | Title/header element |
| `tags.content` | `HtmlElement` | `'div'` | Content body element |
| **Customization** | | | |
| `iconElementHtml` | `string` | `''` | Custom icon HTML/emoji |

Linear history provides several benefits for library releases:
#### Alert-Specific Overrides

- **Clean commit history** - Easy to track changes and debug issues
- **Simplified releases** - Semantic release works better with linear commits
- **Clear changelog** - Each commit represents a complete change
- **Better debugging** - `git bisect` works more effectively
- **Consistent workflow** - Forces proper PR review process
| Property | Type | Description |
|----------|------|-------------|
| `alerts.note` | `PartialDeep<AlertConfig>` | Override config for `[!NOTE]` alerts |
| `alerts.tip` | `PartialDeep<AlertConfig>` | Override config for `[!TIP]` alerts |
| `alerts.important` | `PartialDeep<AlertConfig>` | Override config for `[!IMPORTANT]` alerts |
| `alerts.warning` | `PartialDeep<AlertConfig>` | Override config for `[!WARNING]` alerts |
| `alerts.caution` | `PartialDeep<AlertConfig>` | Override config for `[!CAUTION]` alerts |

## Scripts

| Command | Description |
|---------|-------------|
| `pnpm dev` | Watch mode build |
| `pnpm build` | Production build |
| `pnpm build:check` | Build + package validation |
| `pnpm test` | Run tests |
| `pnpm test:watch` | Watch mode testing |
| `pnpm test:coverage` | Generate coverage report |
| `pnpm lint` | Check linting and formatting |
| `pnpm lint:fix` | Fix linting and formatting issues |
| `pnpm typecheck` | TypeScript type checking |
| `pnpm release` | Create release (CI only) |

## Contributing
> [!TIP]
> Alert-specific configurations merge with the default config, so you only need to specify the properties you want to override.

## Example output

```html
<div class="markdown-alert markdown-alert-note">
<div class="markdown-alert-title">
<span class="markdown-alert-icon"></span>
Note
</div>
<div class="markdown-alert-content">
<p>Your content here</p>
</div>
</div>
```

# License

The MIT License

See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, commit conventions, and contribution guidelines.
[unified]: https://github.com/unifiedjs/unified
[react-markdown]: https://github.com/remarkjs/react-markdown
[common-tags]: https://www.npmjs.com/package/common-tags
[alternative]: https://github.com/jaywcjlove/remark-github-blockquote-alert
Loading