@onozaty/pukiwiki-to-md
v1.10.0
Published
A converter from PukiWiki to Markdown
Readme
pukiwiki-to-md
English | 日本語
A command-line tool to convert PukiWiki pages and attachments to Markdown format.
Features
- 📝 Convert PukiWiki Syntax - Transform PukiWiki markup to Markdown
- 📁 Preserve Directory Structure - Maintain hierarchical page organization
- 📎 Process Attachments - Automatically handle attached files
- 🌍 Encoding Support - Works with UTF-8 and EUC-JP encoded files
- 🗑️ Auto-Exclude System Pages - Filters out
:config,:RenameLog, etc. - 🧹 Comment Unsupported Block Plugins - Converts system directives and other unsupported block plugins to HTML comments (use
--strip-commentsto drop them entirely)
Installation
Using npx (Recommended)
No installation required. Run directly with npx:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./outputGlobal Installation
Install globally for repeated use:
npm install -g @onozaty/pukiwiki-to-md
pukiwiki-to-md -w ./wiki -a ./attach -o ./outputUsage
Basic Command
npx @onozaty/pukiwiki-to-md -w <wiki-folder> -a <attach-folder> -o <output-folder>Options
| Option | Alias | Default | Description |
|--------|-------|---------|-------------|
| --wiki <path> | -w | (required) | Path to PukiWiki wiki folder |
| --attach <path> | -a | (required) | Path to PukiWiki attach folder |
| --output <path> | -o | (required) | Output directory path |
| --encoding <encoding> | -e | utf-8 | Input file encoding (utf-8 or euc-jp) |
| --exclude-plugins <list> | -x | (empty) | Comma-separated custom block plugins to exclude |
| --strip-comments | -s | false | Remove all HTML comments from output |
| --convert-ls-to-lsx | | false | Convert PukiWiki #ls/#ls2 plugins to GROWI $lsx format |
| --preserve-modtime | -p | false | Preserve modification time from source wiki and attachment files |
| --help | -h | | Display help information |
| --version | -v | | Display version number |
Examples
Convert UTF-8 encoded PukiWiki:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./outputConvert EUC-JP encoded PukiWiki:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output -e euc-jpExclude custom plugins:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output -x "myplugin,customplugin"Remove HTML comments from output:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output -sConvert #ls/#ls2 plugins to GROWI $lsx format:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output --convert-ls-to-lsxConversion Features
Note: Plugin names (starting with # or &) are case-insensitive, matching PukiWiki's behavior. For example, #ref, #REF, and #Ref are all recognized as the same plugin. Parameters (filenames, text, etc.) preserve their original case.
Headings
Converts PukiWiki headings to Markdown, automatically removing anchor IDs:
| PukiWiki | Markdown |
|----------|----------|
| *Heading | # Heading |
| **Heading [#abc123] | ## Heading |
| ***Heading | ### Heading |
Lists
Unordered Lists:
| PukiWiki | Markdown |
|----------|----------|
| -Item | - Item |
| --Item | - Item |
| ---Item | - Item |
Ordered Lists:
| PukiWiki | Markdown |
|----------|----------|
| +Item | 1. Item |
| ++Item | 1. Item |
| +++Item | 1. Item |
Text Formatting
| PukiWiki | Markdown |
|----------|----------|
| ''bold'' | **bold** |
| '''italic''' | *italic* |
| %%strikethrough%% | ~~strikethrough~~ |
| %%%underline%%% | <u>underline</u> |
| &br; or &br(); | <br> |
| text~ | text<br> |
| &size(20){text}; | <span style="font-size: 20px">text</span> |
| &color(red){text}; | <span style="color: red">text</span> |
| &color(red,yellow){text}; | <span style="color: red; background-color: yellow">text</span> |
| &color(red,text); | <span style="color: red">text</span> (old style) |
| COLOR(red):text | <span style="color: red">text</span> |
Notes:
- Spacing around emphasis markers: Spaces are automatically added before and after bold (
**), italic (*), and strikethrough (~~) markers to ensure proper Markdown rendering, unless spaces already exist or the markers are at the start/end of a line. For example,これは''太字''ですbecomesこれは **太字** です. - The
&colorplugin supports both new style (with braces) and old style (comma-separated):&color(color){text};and&color(color,text);are both supported. The old style does not support background color. - The
COLOR(color):format applies color until the nextCOLOR(color):directive or end of line. Multiple consecutive color directives are supported (e.g.,COLOR(red):textCOLOR(blue):text). - Nested plugin syntax:
&sizeand&colorcan be nested within each other in any order. Other inline elements (like&br;, bold, italic, etc.) can also be included inside nested plugins.
Nested Plugin Examples:
| PukiWiki | Markdown |
|----------|----------|
| &color(red){&size(20){text};}; | <span style="color: red"><span style="font-size: 20px">text</span></span> |
| &size(20){&color(red){text};}; | <span style="font-size: 20px"><span style="color: red">text</span></span> |
| &color(red){&size(20){text1&br;text2};}; | <span style="color: red"><span style="font-size: 20px">text1<br>text2</span></span> |
| &size(20){&color(blue){''bold''};}; | <span style="font-size: 20px"><span style="color: blue">**bold**</span></span> |
Comments
| PukiWiki | Markdown |
|----------|----------|
| //comment | <!-- comment --> |
Text Alignment
| PukiWiki | Markdown |
|----------|----------|
| LEFT:text | text (prefix removed) |
| CENTER:text | text (prefix removed) |
| RIGHT:text | text (prefix removed) |
Note: Alignment information is not preserved because Markdown has no standard syntax for text alignment, and HTML tags would prevent Markdown parsing of inline elements.
Escape
| PukiWiki | Markdown |
|----------|----------|
| ~*text | \*text |
| ~-text | \-text |
Escapes Markdown special characters (*, -, +, >, #, |) at line start. For non-Markdown characters, the ~ is simply removed.
Links
Internal links are converted to relative paths with minimal URL encoding. Unicode characters (Japanese, etc.) are preserved for readability, while only problematic characters (spaces, parentheses, etc.) are encoded:
| PukiWiki | Markdown |
|----------|----------|
| [[Page]] | [Page](Page.md) |
| [[Label>Page]] | [Label](Page.md) |
| [[テストページ]] | [テストページ](テストページ.md) |
| [[File (1)]] | [File (1)](File%20%281%29.md) |
| [[https://example.com]] | [https://example.com](https://example.com) |
| [[Label:https://example.com]] | [Label](https://example.com) |
| [[Label>https://example.com]] | [Label](https://example.com) |
Relative Path Resolution:
Links are converted to relative paths based on the current page location:
Current page: Project/Task
Link: [[Project/Overview]]
Output: [Project/Overview](Overview.md)
Current page: TopPage
Link: [[Project/Task]]
Output: [Project/Task](Project/Task.md)
Current page: Project/Task
Link: [[TopPage]]
Output: [TopPage](../TopPage.md)Tables
All PukiWiki tables are converted to Markdown table format. Tables without a header marker (|h) automatically get an empty header row.
With Header Marker (|h):
Input:
|Header1|Header2|h
|Data1|Data2|Output:
| Header1 | Header2 |
| --- | --- |
| Data1 | Data2 |Without Header Marker (empty header row added automatically):
Input:
|Data1|Data2|
|Data3|Data4|Output:
| | |
| --- | --- |
| Data1 | Data2 |
| Data3 | Data4 |Tables with PukiWiki Syntax in Cells:
PukiWiki syntax (links, formatting, etc.) within table cells is properly converted:
Input:
|[[TopPage]]|''Bold''|
|[[Help]]|Normal|Output:
| | |
| --- | --- |
| [TopPage](TopPage.md) | **Bold** |
| [Help](Help.md) | Normal |Table Cell Formatting:
Cells can be formatted with the following prefixes:
| PukiWiki | Description | Output |
|----------|-------------|--------|
| LEFT:text | Left-aligned cell | text (left alignment applied to column) |
| CENTER:text | Center-aligned cell | text (center alignment applied to column) |
| RIGHT:text | Right-aligned cell | text (right alignment applied to column) |
| BOLD:text | Bold text | **text** |
| SIZE(20):text | Font size (px) | <span style="font-size: 20px">text</span> |
| COLOR(red):text | Text color | <span style="color: red">text</span> |
| BGCOLOR(yellow):text | Background color (preserved as comment) | text <!-- BGCOLOR(yellow) --> |
| ~text | Bold (header cell) | **text** |
Note: BGCOLOR is not converted and is preserved as an HTML comment because Markdown tables do not support cell background colors. Converting to HTML tables would prevent Markdown syntax (links, bold, etc.) from working inside cells.
Example:
Input: |BOLD:Name|SIZE(20):Large|COLOR(red):Red|h
Output: | **Name** | <span style="font-size: 20px">Large</span> | <span style="color: red">Red</span> |
| --- | --- | --- |Multiple formatting options can be combined:
Input: |BOLD:SIZE(20):COLOR(red):BGCOLOR(yellow):All|Normal|h
Output: | <span style="font-size: 20px; color: red">**All**</span> <!-- BGCOLOR(yellow) --> | Normal |
| --- | --- |Block Plugins in Table Cells:
The #ref block plugin is supported in table cells for embedding images and file attachments:
Input: |#ref(image.png)|#ref(document.pdf,説明)|
Output: | | |
| --- | --- |
|  | [説明](PageName_attachment_document.pdf) |When #ref is used at the start of a cell, it's processed as a block plugin. Text after the closing parenthesis is ignored (standard PukiWiki block plugin behavior). All #ref parameters (alt text, size specifications, etc.) are supported.
Quotes
| PukiWiki | Markdown |
|----------|----------|
| >quote | > quote |
| >>nested quote | > > nested quote |
Horizontal Rules
| PukiWiki | Markdown |
|----------|----------|
| ---- | *** |
| #hr or #hr() | *** |
Line Breaks
| PukiWiki | Markdown | Notes |
|----------|----------|-------|
| #br or #br() | <br> + blank line | Blank line added to ensure proper Markdown parsing |
Preformatted Text
Lines starting with spaces or tabs are converted to fenced code blocks.
Input:
function() {
return 42;
}Output:
```
function() {
return 42;
}
```Vote Plugin
The #vote plugin is converted to an HTML comment plus a table showing vote results. Option labels support inline formatting (bold, links, etc.):
Input:
#vote(選択肢1[0],選択肢2[1],選択肢3[3])Output:
<!-- #vote(選択肢1[0],選択肢2[1],選択肢3[3]) -->
| 選択肢 | 投票数 |
| --- | ---: |
| 選択肢1 | 0 |
| 選択肢2 | 1 |
| 選択肢3 | 3 |With inline formatting:
Input: #vote(''Bold''[5],[[Link]][10])
Output: <!-- #vote(''Bold''[5],[[Link]][10]) -->
| 選択肢 | 投票数 |
| --- | ---: |
| **Bold** | 5 |
| [Link](Link.md) | 10 |Note: The voting functionality is lost, and the vote data is preserved as a static snapshot.
Include Plugin
The #include plugin is converted to an HTML comment plus a link to the included page, allowing navigation while preserving the original syntax:
Input:
#include(CommonHeader)Output:
<!-- #include(CommonHeader) -->
[CommonHeader](CommonHeader.md)With parameters:
Input: #include(PageName,notitle)
Output: <!-- #include(PageName,notitle) -->
[PageName](PageName.md)Hierarchical pages:
Current page: Project/Task
Input: #include(Project/Common)
Output: <!-- #include(Project/Common) -->
[Project/Common](Common.md)Note: The include functionality is lost, but the link provides navigation to the included page.
Unsupported Plugins
The following block plugins cannot be represented in Markdown and are converted to HTML comments (46 plugins total). Note that #vote and #include have special conversion handling (see their dedicated sections above):
System directives:
#author(...)- Page metadata (author and timestamp)#freeze- Page freeze setting#nofollow- Search engine hint#norelated- Suppress related pages display
Content inclusion & display:
#amazon- Amazon product information#aname- Anchor definition#includesubmenu- Include submenu
Dynamic functionality & forms:
#article- Article/BBS form#attach- File upload form#comment- Comment form#contents- Table of contents#counter- Access counter#insert- Insert form#lookup- Dictionary lookup#navi- Navigation#newpage- New page creation form#pcomment- Page comment form
Lists & navigation:
#back- Back link#ls- Child page list - Can be converted to GROWI$lsxformat with--convert-ls-to-lsxoption#ls2- Child page list (enhanced) - Can be converted to GROWI$lsxformat with--convert-ls-to-lsxoption#menu- Menu display#online- Online users display#popular- Popular pages ranking#recent- Recent changes display#related- Related pages display#search- Search form#topicpath- Breadcrumb navigation
Tracker & issue management:
#bugtrack- Bug tracker input form#bugtrack_list- Bug tracker list display#tracker- Tracker input form#tracker_list- Tracker list display
Calendar:
#calendar- Calendar display#calendar2- Calendar (alternative)#calendar_edit- Calendar edit form#calendar_read- Calendar read view#calendar_viewer- Calendar viewer
Utilities & misc:
#clear- Clear float (layout)#memo- Memo#paint- Drawing tool#random- Random display#server- Server information#setlinebreak- Line break setting#showrss- RSS feed display#stationary- Template/stationery#version- Version display#versionlist- Version list
All of these are converted to HTML comments like <!-- #plugin -->. Parameters are preserved:
Input: #contents(depth=2)
Output: <!-- #contents(depth=2) -->Text After Closing Parenthesis:
Following PukiWiki behavior, when parentheses are present, any text after the closing ) is ignored and the entire line is converted to an HTML comment. Without parentheses, the plugin name must be alone on the line.
Input: #freeze() additional text
Output: <!-- #freeze() additional text -->
Input: #contents(depth=2)this is ignored
Output: <!-- #contents(depth=2)this is ignored -->
Input: #freeze additional text
Output: #freeze additional text
(not converted, remains as-is)GROWI lsx Conversion
When using the --convert-ls-to-lsx option, PukiWiki #ls and #ls2 plugins are converted to GROWI $lsx format with relative paths:
#ls plugin (simple child page list):
| PukiWiki | GROWI lsx | Notes |
|----------|-----------|-------|
| #ls | $lsx(./) | Current page children |
| #ls() | $lsx(./) | Current page children |
| #ls(title) | <!-- #ls(title) -->$lsx(./) | Unsupported option preserved as comment |
#ls2 plugin (enhanced child page list with pattern):
| PukiWiki | GROWI lsx | Notes |
|----------|-----------|-------|
| #ls2 | $lsx(./) | Current page children |
| #ls2() | $lsx(./) | Current page children |
| #ls2(Project/Task) | $lsx(./relative/path) | Relative path calculated |
| #ls2(Page, reverse) | $lsx(./relative/path, reverse=true) | Supported option |
| #ls2(Page, title) | <!-- #ls2(Page, title) -->$lsx(./relative/path) | Unsupported option preserved as comment |
Supported options (ls2 only):
reverse→reverse=true
Unsupported options (preserved as HTML comment):
title- Heading list display (both ls and ls2)include- Include page list (ls2 only)compact- Compact display (ls2 only)link- Link display (ls2 only)
Custom Plugin Exclusion:
You can specify additional custom plugins to exclude using the --exclude-plugins option:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output -x "myplugin,customplugin"This will convert #myplugin and #customplugin to HTML comments in addition to the default plugins listed above.
Note: Dynamic functionality and layout features are lost, but the original syntax is preserved for reference in HTML comments.
Removing HTML Comments
By default, unsupported plugins and PukiWiki comments are converted to HTML comments for reference. You can use the --strip-comments option to remove all HTML comments from the output:
npx @onozaty/pukiwiki-to-md -w ./wiki -a ./attach -o ./output --strip-commentsThis removes:
- PukiWiki comment lines (
//comment) - Unsupported block plugin comments (
#contents,#comment, etc.) - Plugin-specific comments (e.g.,
#votecomment line,#includecomment line) - BGCOLOR comments in table cells
The actual converted content (tables from #vote, links from #include, etc.) is preserved.
Attachments
File Processing
Attachments are automatically detected and copied to the output directory with sanitized filenames. File references use minimal URL encoding - Unicode characters are preserved for readability while only problematic characters are encoded:
- PukiWiki format:
E38386E382B9E38388_696D6167652E706E67 - Converted format:
テスト_attachment_image.png - In Markdown:

Attachment References:
The #ref and &ref plugins support:
- Default alt text: If no alt text is specified, the filename is used
- CSV-style parameters: Filenames with commas can be quoted (
"file, name.png") - Other page attachments: Reference files from other pages (
PageName/file.png,../file.png) - Minimal URL encoding: Only characters that cause issues in Markdown links are encoded (
%, space, (), [], :, ", ,)
Examples:
Input: #ref(image.png)
Output: 
Input: #ref("file, name.png",300x200)
Output: <img src="PageName_attachment_file%2C%20name.png" alt="file, name.png" width="300" height="200">
Input: #ref(OtherPage/diagram.png)
Output: Directory Structure
Hierarchical page structures are preserved:
Input:
wiki/E38397E383ADE382B8E382A7E382AFE383882FE382BFE382B9E382AF.txt
Output:
output/プロジェクト/タスク.mdAttachments follow the same structure:
Input:
attach/E38397E383ADE382B8E382A7E382AFE383882FE382BFE382B9E382AF_696D6167652E706E67
Output:
output/プロジェクト/タスク_attachment_image.pngLimitations
Converted to HTML Comments
Many PukiWiki plugins are automatically converted to HTML comments because they cannot be represented in static Markdown. See the Unsupported Plugins section for the complete list of 46 plugins that are converted.
Excluded Pages
The following system pages are automatically excluded:
:configand:config/*- Configuration pages:RenameLog- Rename history
Note: User-created pages starting with : (e.g., :userpage) are not excluded and will be converted normally.
Unsupported Syntax
The following PukiWiki features are not converted and remain as-is:
- Custom plugins (unless specified with
--exclude-plugins)
Requirements
- Node.js 18.x or later
License
MIT
