@entro314labs/markdownfix 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.remarkignore +59 -0
- package/.remarkrc.js +83 -0
- package/LICENSE +21 -0
- package/README.md +346 -0
- package/cli.js +344 -0
- package/package.json +129 -0
- package/setup.js +258 -0
package/.remarkignore
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
npm-debug.log*
|
|
4
|
+
yarn-debug.log*
|
|
5
|
+
yarn-error.log*
|
|
6
|
+
|
|
7
|
+
# Build outputs
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
out/
|
|
11
|
+
.next/
|
|
12
|
+
.nuxt/
|
|
13
|
+
.cache/
|
|
14
|
+
|
|
15
|
+
# Environment files
|
|
16
|
+
.env*
|
|
17
|
+
|
|
18
|
+
# IDE files
|
|
19
|
+
.vscode/
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
*~
|
|
24
|
+
|
|
25
|
+
# OS files
|
|
26
|
+
.DS_Store
|
|
27
|
+
Thumbs.db
|
|
28
|
+
|
|
29
|
+
# Logs
|
|
30
|
+
*.log
|
|
31
|
+
logs/
|
|
32
|
+
|
|
33
|
+
# Temporary files
|
|
34
|
+
.tmp/
|
|
35
|
+
temp/
|
|
36
|
+
*.tmp
|
|
37
|
+
|
|
38
|
+
# Package manager files
|
|
39
|
+
package-lock.json
|
|
40
|
+
yarn.lock
|
|
41
|
+
pnpm-lock.yaml
|
|
42
|
+
|
|
43
|
+
# Git files
|
|
44
|
+
.git/
|
|
45
|
+
.gitignore
|
|
46
|
+
|
|
47
|
+
# Backup files
|
|
48
|
+
*.backup
|
|
49
|
+
*.bak
|
|
50
|
+
*~
|
|
51
|
+
|
|
52
|
+
# Coverage reports
|
|
53
|
+
coverage/
|
|
54
|
+
.nyc_output/
|
|
55
|
+
|
|
56
|
+
# Specific files to ignore
|
|
57
|
+
CHANGELOG.md
|
|
58
|
+
LICENSE
|
|
59
|
+
README.md
|
package/.remarkrc.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opinionated Remark configuration for markdown processing
|
|
3
|
+
* Supports .md, and .mdx files with consistent formatting
|
|
4
|
+
* Optionally supports .mdd files if mdd package is installed
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Try to load MDD plugins if available
|
|
8
|
+
let mddPlugins = [];
|
|
9
|
+
try {
|
|
10
|
+
const mddDocStructure = await import('@entro314labs/mdd/plugins/remark-mdd-document-structure.js');
|
|
11
|
+
const mddTextFormatting = await import('@entro314labs/mdd/plugins/remark-mdd-text-formatting.js');
|
|
12
|
+
const mddMdxConditional = await import('@entro314labs/mdd/plugins/remark-mdx-conditional.js');
|
|
13
|
+
|
|
14
|
+
mddPlugins = [
|
|
15
|
+
mddMdxConditional.default,
|
|
16
|
+
mddDocStructure.default,
|
|
17
|
+
mddTextFormatting.default
|
|
18
|
+
];
|
|
19
|
+
console.log('✓ MDD support enabled');
|
|
20
|
+
} catch (e) {
|
|
21
|
+
// MDD package not installed - only support .md and .mdx
|
|
22
|
+
mddPlugins = ['remark-mdx'];
|
|
23
|
+
console.log('ℹ MDD support not available (install mdd package for .mdd file support)');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
// Configure remark-stringify output formatting
|
|
28
|
+
settings: {
|
|
29
|
+
bullet: '-', // Use - for unordered lists
|
|
30
|
+
bulletOther: '*', // Use * for nested lists
|
|
31
|
+
bulletOrdered: '.', // Use 1. 2. 3. for ordered lists
|
|
32
|
+
emphasis: '_', // Use _emphasis_ over *emphasis*
|
|
33
|
+
strong: '*', // Use **strong** over __strong__
|
|
34
|
+
fence: '`', // Use ``` for code fences
|
|
35
|
+
fences: true, // Always use fences for code blocks
|
|
36
|
+
incrementListMarker: true, // Increment ordered list markers
|
|
37
|
+
listItemIndent: 'one', // Use one space for list indentation
|
|
38
|
+
quote: '"', // Use double quotes in titles
|
|
39
|
+
rule: '-', // Use --- for horizontal rules
|
|
40
|
+
ruleRepetition: 3, // Use exactly 3 characters for rules
|
|
41
|
+
ruleSpaces: false, // No spaces in horizontal rules
|
|
42
|
+
setext: false, // Use # instead of === underlines
|
|
43
|
+
tightDefinitions: true, // No blank lines between definitions
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
plugins: [
|
|
47
|
+
// Enable support for frontmatter (---, +++)
|
|
48
|
+
'remark-frontmatter',
|
|
49
|
+
|
|
50
|
+
// Enable GitHub Flavored Markdown (tables, strikethrough, etc.)
|
|
51
|
+
'remark-gfm',
|
|
52
|
+
|
|
53
|
+
// MDX/MDD plugins (loaded dynamically above)
|
|
54
|
+
...mddPlugins,
|
|
55
|
+
|
|
56
|
+
// Apply consistent style presets
|
|
57
|
+
'remark-preset-lint-consistent',
|
|
58
|
+
'remark-preset-lint-recommended',
|
|
59
|
+
'remark-preset-lint-markdown-style-guide',
|
|
60
|
+
|
|
61
|
+
// Lint rules
|
|
62
|
+
['remark-lint-heading-increment', true], // MD001
|
|
63
|
+
['remark-lint-no-duplicate-headings', true], // MD024
|
|
64
|
+
['remark-lint-no-emphasis-as-heading', true], // MD036
|
|
65
|
+
['remark-lint-emphasis-marker', '_'],
|
|
66
|
+
['remark-lint-strong-marker', '*'],
|
|
67
|
+
['remark-lint-heading-style', 'atx'],
|
|
68
|
+
['remark-lint-list-item-indent', 'one'],
|
|
69
|
+
['remark-lint-ordered-list-marker-style', '.'],
|
|
70
|
+
['remark-lint-ordered-list-marker-value', 'ordered'],
|
|
71
|
+
['remark-lint-unordered-list-marker-style', '-'],
|
|
72
|
+
['remark-lint-table-cell-padding', 'padded'],
|
|
73
|
+
['remark-lint-table-pipe-alignment', true],
|
|
74
|
+
['remark-lint-link-title-style', '"'],
|
|
75
|
+
['remark-lint-no-trailing-spaces', true],
|
|
76
|
+
['remark-lint-final-newline', true],
|
|
77
|
+
['remark-lint-hard-break-spaces', true],
|
|
78
|
+
['remark-lint-no-empty-sections', true],
|
|
79
|
+
|
|
80
|
+
// Must be last - handles the output formatting
|
|
81
|
+
'remark-stringify'
|
|
82
|
+
]
|
|
83
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Entro314 Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Markdown Formatter (markdownfix)
|
|
2
|
+
|
|
3
|
+
**Opinionated markdown formatter and linter for `.md`, `.mdd`, and `.mdx` files**
|
|
4
|
+
|
|
5
|
+
Built on the Remark ecosystem with strict, consistent formatting rules for developer documentation, technical writing, and web content. Perfect for README files, technical docs, blogs, and GitHub wikis.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ✅ **Opinionated formatting** - Consistent style across all markdown files
|
|
10
|
+
- ✅ **GitHub Flavored Markdown** - Tables, task lists, strikethrough, autolinks
|
|
11
|
+
- ✅ **MDX support** - JSX components in markdown
|
|
12
|
+
- ✅ **Comprehensive linting** - 40+ lint rules for quality and consistency
|
|
13
|
+
- ✅ **Link validation** - Check for broken links
|
|
14
|
+
- ✅ **Auto-fixing** - Automatically fix formatting issues
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install globally
|
|
20
|
+
npm install -g markdownfix
|
|
21
|
+
|
|
22
|
+
# Or use with npx (no installation)
|
|
23
|
+
npx markdownfix --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Format all markdown files in current directory
|
|
30
|
+
markdownfix format
|
|
31
|
+
|
|
32
|
+
# Check formatting without writing changes
|
|
33
|
+
markdownfix check
|
|
34
|
+
|
|
35
|
+
# Lint files for issues
|
|
36
|
+
markdownfix lint
|
|
37
|
+
|
|
38
|
+
# Format specific files
|
|
39
|
+
markdownfix format README.md docs/*.md
|
|
40
|
+
|
|
41
|
+
# Use glob patterns
|
|
42
|
+
markdownfix format --glob "src/**/*.md"
|
|
43
|
+
|
|
44
|
+
# Quiet mode (suppress output)
|
|
45
|
+
markdownfix format --quiet
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Using as a Package Script
|
|
49
|
+
|
|
50
|
+
Add to your `package.json`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"scripts": {
|
|
55
|
+
"format:md": "markdownfix format",
|
|
56
|
+
"lint:md": "markdownfix lint"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Initialize Project
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Create .remarkrc.js configuration
|
|
65
|
+
markdownfix init
|
|
66
|
+
|
|
67
|
+
# Create example content structure
|
|
68
|
+
markdownfix setup
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## What Gets Formatted
|
|
72
|
+
|
|
73
|
+
### Lists
|
|
74
|
+
- **Unordered**: `-` (never `*` or `+`)
|
|
75
|
+
- **Ordered**: `1.` incremental (never `1)`)
|
|
76
|
+
|
|
77
|
+
### Emphasis
|
|
78
|
+
- **Italic**: `_text_` (underscore, not asterisk)
|
|
79
|
+
- **Bold**: `**text**` (double asterisk, not underscore)
|
|
80
|
+
|
|
81
|
+
### Headings
|
|
82
|
+
- **Style**: ATX (`# Title`), never setext (`===`)
|
|
83
|
+
- **Hierarchy**: Must progress sequentially (no skipping levels)
|
|
84
|
+
|
|
85
|
+
### Code Blocks
|
|
86
|
+
- Always fenced (` ``` `) with language identifiers
|
|
87
|
+
- Never indented code blocks
|
|
88
|
+
|
|
89
|
+
### Formatting
|
|
90
|
+
- **Line length**: 100 characters max with smart wrapping
|
|
91
|
+
- **Tables**: Padded cells with aligned pipes (auto-formatted)
|
|
92
|
+
- **Final newline**: All files must end with `\n`
|
|
93
|
+
- **No trailing spaces**: Automatically removed
|
|
94
|
+
|
|
95
|
+
## File Support
|
|
96
|
+
|
|
97
|
+
| Extension | Support | Features | Use Case |
|
|
98
|
+
|-----------|---------|----------|----------|
|
|
99
|
+
| `.md` | ✅ Full | GFM, frontmatter, tables, task lists | Documentation, READMEs, blogs |
|
|
100
|
+
| `.mdx` | ✅ Full | Above + JSX components, imports/exports | React docs, interactive content |
|
|
101
|
+
| `.mdd` | ⚠️ Optional | Business documents (see below) | Invoices, proposals, contracts |
|
|
102
|
+
|
|
103
|
+
### MDD Support
|
|
104
|
+
|
|
105
|
+
This formatter can **optionally** format `.mdd` files if you install the [MDD package](https://www.npmjs.com/package/@entro314labs/mdd):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Install MDD support
|
|
109
|
+
pnpm add mdd
|
|
110
|
+
|
|
111
|
+
# Now .mdd files will be formatted
|
|
112
|
+
pnpm run format
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Note**: MDD is a separate project for business documents. See the [MDD project](https://github.com/entro314-labs/mdd) for details.
|
|
116
|
+
|
|
117
|
+
## CLI Commands
|
|
118
|
+
|
|
119
|
+
### Available Commands
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
markdownfix format [files...] # Format and fix markdown files
|
|
123
|
+
markdownfix check [files...] # Check without writing changes
|
|
124
|
+
markdownfix lint [files...] # Lint for issues only
|
|
125
|
+
markdownfix init # Create .remarkrc.js config
|
|
126
|
+
markdownfix setup # Create example content structure
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Command Aliases
|
|
130
|
+
|
|
131
|
+
The CLI is available via two commands:
|
|
132
|
+
|
|
133
|
+
- `markdownfix` (full name)
|
|
134
|
+
- `mdfix` (short alias)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# These are equivalent
|
|
138
|
+
markdownfix format
|
|
139
|
+
mdfix format
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Options
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
--help, -h Show help message
|
|
146
|
+
--version, -v Show version number
|
|
147
|
+
--quiet, -q Suppress output except errors
|
|
148
|
+
--glob <pattern> Use glob pattern for file matching
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Examples
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Format all markdown in project
|
|
155
|
+
mdfix format
|
|
156
|
+
|
|
157
|
+
# Check specific files
|
|
158
|
+
mdfix check README.md CHANGELOG.md
|
|
159
|
+
|
|
160
|
+
# Lint with glob pattern
|
|
161
|
+
mdfix lint --glob "docs/**/*.{md,mdx}"
|
|
162
|
+
|
|
163
|
+
# Quiet formatting
|
|
164
|
+
mdfix format --quiet
|
|
165
|
+
|
|
166
|
+
# Get help
|
|
167
|
+
mdfix --help
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Development Scripts
|
|
171
|
+
|
|
172
|
+
If you're working on the markdownfix project itself:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Formatting
|
|
176
|
+
pnpm run format # Apply fixes using remark-cli
|
|
177
|
+
pnpm run format:check # Preview changes
|
|
178
|
+
|
|
179
|
+
# Linting
|
|
180
|
+
pnpm run lint # Check compliance
|
|
181
|
+
|
|
182
|
+
# Combined
|
|
183
|
+
pnpm run process # Format then lint
|
|
184
|
+
pnpm run process:safe # Dry-run first, then process
|
|
185
|
+
pnpm test # Same as process:safe
|
|
186
|
+
|
|
187
|
+
# Utilities
|
|
188
|
+
pnpm run check-links # Validate all markdown links
|
|
189
|
+
pnpm run clean-cache # Clear remark cache
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Project Structure
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
markdownfix/
|
|
196
|
+
├── content/ # Example content
|
|
197
|
+
│ ├── docs/
|
|
198
|
+
│ ├── blog/
|
|
199
|
+
│ └── guides/
|
|
200
|
+
├── .remarkrc.js # Formatting & linting rules
|
|
201
|
+
├── .remarkignore # Files to exclude
|
|
202
|
+
├── setup.js # Bootstrap script
|
|
203
|
+
├── package.json
|
|
204
|
+
└── README.md
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Configuration
|
|
208
|
+
|
|
209
|
+
### `.remarkrc.js`
|
|
210
|
+
|
|
211
|
+
Central configuration defining:
|
|
212
|
+
- All formatting rules
|
|
213
|
+
- Plugin chain order
|
|
214
|
+
- Lint rule settings
|
|
215
|
+
|
|
216
|
+
**Plugin order is critical:**
|
|
217
|
+
1. `remark-frontmatter` - Parse YAML/TOML
|
|
218
|
+
2. `remark-gfm` - GitHub Flavored Markdown
|
|
219
|
+
3. `remark-mdx` - MDX support (conditional)
|
|
220
|
+
4. Lint presets + rules
|
|
221
|
+
5. `remark-stringify` - Must be last
|
|
222
|
+
|
|
223
|
+
### `.remarkignore`
|
|
224
|
+
|
|
225
|
+
Files excluded from processing:
|
|
226
|
+
- `README.md`
|
|
227
|
+
- `CHANGELOG.md`
|
|
228
|
+
- `LICENSE`
|
|
229
|
+
- `node_modules/`
|
|
230
|
+
- `pnpm-lock.yaml`
|
|
231
|
+
|
|
232
|
+
## Frontmatter Convention
|
|
233
|
+
|
|
234
|
+
```yaml
|
|
235
|
+
---
|
|
236
|
+
title: Required for all content files
|
|
237
|
+
date: YYYY-MM-DD format preferred
|
|
238
|
+
author: Optional but recommended
|
|
239
|
+
---
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Common Issues
|
|
243
|
+
|
|
244
|
+
### "No input" Errors
|
|
245
|
+
|
|
246
|
+
**Cause**: No markdown files found or all files excluded
|
|
247
|
+
|
|
248
|
+
**Solution**:
|
|
249
|
+
- Ensure markdown files exist in `content/` directory
|
|
250
|
+
- Check `.remarkignore` patterns
|
|
251
|
+
- Verify correct file extensions (`.md`, `.mdx`)
|
|
252
|
+
|
|
253
|
+
### Linting Failures After Formatting
|
|
254
|
+
|
|
255
|
+
**Cause**: Some rules require manual fixes (duplicate headings, broken links)
|
|
256
|
+
|
|
257
|
+
**Solution**:
|
|
258
|
+
- Read console output for specific violations
|
|
259
|
+
- Manually fix reported issues
|
|
260
|
+
- Use `pnpm run format:check` to separate formatting from lint errors
|
|
261
|
+
|
|
262
|
+
### MDX Parsing Errors
|
|
263
|
+
|
|
264
|
+
**Cause**: Invalid JSX syntax
|
|
265
|
+
|
|
266
|
+
**Solution**:
|
|
267
|
+
- Verify JSX is valid JavaScript
|
|
268
|
+
- Check all tags are properly closed
|
|
269
|
+
- Ensure React components use `<Component />` not `<Component>`
|
|
270
|
+
|
|
271
|
+
## Bootstrap New Project
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# Create example content structure
|
|
275
|
+
node setup.js
|
|
276
|
+
|
|
277
|
+
# Install dependencies
|
|
278
|
+
pnpm install
|
|
279
|
+
|
|
280
|
+
# Verify everything works
|
|
281
|
+
pnpm run process:safe
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Editor Integration
|
|
285
|
+
|
|
286
|
+
**Disable VS Code remark extensions** - they may conflict with this opinionated configuration. Always use command line processing.
|
|
287
|
+
|
|
288
|
+
## Two Projects, One Ecosystem
|
|
289
|
+
|
|
290
|
+
This repository focuses on **developer documentation** (READMEs, technical docs, blogs).
|
|
291
|
+
|
|
292
|
+
For **business documents** (invoices, proposals, letters, contracts), we have a companion project:
|
|
293
|
+
|
|
294
|
+
### 📄 [MDD (Markdown Document)](https://github.com/entro314-labs/mdd)
|
|
295
|
+
|
|
296
|
+
MDD extends markdown with business-focused features:
|
|
297
|
+
|
|
298
|
+
- Letterheads and headers/footers
|
|
299
|
+
- Signature blocks
|
|
300
|
+
- Contact information blocks
|
|
301
|
+
- Professional PDF/DOCX output
|
|
302
|
+
- Invoice and proposal templates
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Quick example
|
|
306
|
+
cd ../mdd
|
|
307
|
+
pnpm run preview examples/invoice.mdd
|
|
308
|
+
# Opens professional HTML invoice in browser
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**When to use which:**
|
|
312
|
+
|
|
313
|
+
| Use Case | Project | File Type |
|
|
314
|
+
|----------|---------|-----------|
|
|
315
|
+
| README files | Markdown Formatter | `.md` |
|
|
316
|
+
| Technical docs | Markdown Formatter | `.md` |
|
|
317
|
+
| Blog posts | Markdown Formatter | `.md` / `.mdx` |
|
|
318
|
+
| React documentation | Markdown Formatter | `.mdx` |
|
|
319
|
+
| **Business letters** | **MDD** | `.mdd` |
|
|
320
|
+
| **Invoices** | **MDD** | `.mdd` |
|
|
321
|
+
| **Proposals** | **MDD** | `.mdd` |
|
|
322
|
+
| **Contracts** | **MDD** | `.mdd` |
|
|
323
|
+
|
|
324
|
+
## Documentation
|
|
325
|
+
|
|
326
|
+
- **[COMPREHENSIVE-GUIDE.md](COMPREHENSIVE-GUIDE.md)** - Detailed technical guide
|
|
327
|
+
- **[content/guides/style-guide.md](content/guides/style-guide.md)** - Style specifications
|
|
328
|
+
|
|
329
|
+
## Tech Stack
|
|
330
|
+
|
|
331
|
+
- **Remark** - Markdown processor
|
|
332
|
+
- **Unified** - AST transformation
|
|
333
|
+
- **GFM** - GitHub Flavored Markdown
|
|
334
|
+
- **MDX** - JSX in markdown
|
|
335
|
+
|
|
336
|
+
## Contributing
|
|
337
|
+
|
|
338
|
+
This is an opinionated formatter with specific style decisions. Contributions should:
|
|
339
|
+
- Maintain existing formatting rules
|
|
340
|
+
- Add value for developer documentation
|
|
341
|
+
- Not break existing lint rules
|
|
342
|
+
- Include test cases
|
|
343
|
+
|
|
344
|
+
## License
|
|
345
|
+
|
|
346
|
+
MIT
|
package/cli.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI tool for markdown formatting and linting
|
|
5
|
+
* Provides commands to format, lint, and check markdown files
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { remark } from 'remark';
|
|
9
|
+
import { read } from 'to-vfile';
|
|
10
|
+
import { reporter } from 'vfile-reporter';
|
|
11
|
+
import remarkPresetLintRecommended from 'remark-preset-lint-recommended';
|
|
12
|
+
import remarkPresetLintConsistent from 'remark-preset-lint-consistent';
|
|
13
|
+
import remarkPresetLintMarkdownStyleGuide from 'remark-preset-lint-markdown-style-guide';
|
|
14
|
+
import remarkFrontmatter from 'remark-frontmatter';
|
|
15
|
+
import remarkGfm from 'remark-gfm';
|
|
16
|
+
import remarkStringify from 'remark-stringify';
|
|
17
|
+
import fs from 'fs/promises';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import { glob } from 'glob';
|
|
20
|
+
|
|
21
|
+
const MARKDOWN_EXTENSIONS = ['md', 'mdx', 'mdd'];
|
|
22
|
+
|
|
23
|
+
// Import configuration from .remarkrc.js
|
|
24
|
+
let remarkConfig;
|
|
25
|
+
try {
|
|
26
|
+
const configModule = await import(path.join(process.cwd(), '.remarkrc.js'));
|
|
27
|
+
remarkConfig = configModule.default;
|
|
28
|
+
} catch (e) {
|
|
29
|
+
console.warn('⚠️ No .remarkrc.js found in current directory, using default config');
|
|
30
|
+
remarkConfig = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Show help text
|
|
35
|
+
*/
|
|
36
|
+
function showHelp() {
|
|
37
|
+
console.log(`
|
|
38
|
+
markdownfix - Opinionated markdown formatter and linter
|
|
39
|
+
|
|
40
|
+
USAGE:
|
|
41
|
+
markdownfix <command> [options] [files...]
|
|
42
|
+
|
|
43
|
+
COMMANDS:
|
|
44
|
+
format [files] Format markdown files (writes changes)
|
|
45
|
+
check [files] Check formatting without writing changes
|
|
46
|
+
lint [files] Lint markdown files (no formatting)
|
|
47
|
+
init Create .remarkrc.js configuration file
|
|
48
|
+
setup Create example content structure
|
|
49
|
+
|
|
50
|
+
OPTIONS:
|
|
51
|
+
--help, -h Show this help message
|
|
52
|
+
--version, -v Show version number
|
|
53
|
+
--quiet, -q Suppress output except errors
|
|
54
|
+
--glob <pattern> Use glob pattern (e.g., "**/*.md")
|
|
55
|
+
|
|
56
|
+
EXAMPLES:
|
|
57
|
+
# Format all markdown files in current directory
|
|
58
|
+
markdownfix format
|
|
59
|
+
|
|
60
|
+
# Check specific files
|
|
61
|
+
markdownfix check README.md docs/*.md
|
|
62
|
+
|
|
63
|
+
# Lint with glob pattern
|
|
64
|
+
markdownfix lint --glob "src/**/*.md"
|
|
65
|
+
|
|
66
|
+
# Format quietly
|
|
67
|
+
markdownfix format --quiet
|
|
68
|
+
|
|
69
|
+
# Initialize configuration
|
|
70
|
+
markdownfix init
|
|
71
|
+
|
|
72
|
+
For more information, visit: https://github.com/entro314-labs/markdownfix
|
|
73
|
+
`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get files to process
|
|
78
|
+
*/
|
|
79
|
+
async function getFiles(args, globPattern) {
|
|
80
|
+
if (globPattern) {
|
|
81
|
+
return glob(globPattern, { ignore: 'node_modules/**' });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (args.length > 0) {
|
|
85
|
+
return args;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Default: find all markdown files in current directory and subdirectories
|
|
89
|
+
const patterns = MARKDOWN_EXTENSIONS.map(ext => `**/*.${ext}`);
|
|
90
|
+
const allFiles = [];
|
|
91
|
+
|
|
92
|
+
for (const pattern of patterns) {
|
|
93
|
+
const files = await glob(pattern, { ignore: ['node_modules/**', '.git/**'] });
|
|
94
|
+
allFiles.push(...files);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return allFiles;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Process files with remark
|
|
102
|
+
*/
|
|
103
|
+
async function processFiles(files, options = {}) {
|
|
104
|
+
const { write = false, quiet = false, lintOnly = false } = options;
|
|
105
|
+
|
|
106
|
+
let hasErrors = false;
|
|
107
|
+
let processedCount = 0;
|
|
108
|
+
|
|
109
|
+
for (const filePath of files) {
|
|
110
|
+
try {
|
|
111
|
+
const file = await read(filePath);
|
|
112
|
+
|
|
113
|
+
// Build processor
|
|
114
|
+
let processor = remark()
|
|
115
|
+
.use(remarkFrontmatter, ['yaml'])
|
|
116
|
+
.use(remarkGfm);
|
|
117
|
+
|
|
118
|
+
// Add lint presets
|
|
119
|
+
processor = processor
|
|
120
|
+
.use(remarkPresetLintRecommended)
|
|
121
|
+
.use(remarkPresetLintConsistent)
|
|
122
|
+
.use(remarkPresetLintMarkdownStyleGuide);
|
|
123
|
+
|
|
124
|
+
// Add stringify for formatting (unless lint-only)
|
|
125
|
+
if (!lintOnly) {
|
|
126
|
+
processor = processor.use(remarkStringify, {
|
|
127
|
+
bullet: '-',
|
|
128
|
+
emphasis: '_',
|
|
129
|
+
fences: true,
|
|
130
|
+
listItemIndent: 'one',
|
|
131
|
+
rule: '-',
|
|
132
|
+
strong: '*',
|
|
133
|
+
tightDefinitions: true
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const result = await processor.process(file);
|
|
138
|
+
|
|
139
|
+
// Check for lint errors/warnings
|
|
140
|
+
if (result.messages.length > 0) {
|
|
141
|
+
if (!quiet) {
|
|
142
|
+
console.error(reporter(result));
|
|
143
|
+
}
|
|
144
|
+
hasErrors = true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Write changes if requested and not lint-only
|
|
148
|
+
if (write && !lintOnly) {
|
|
149
|
+
await fs.writeFile(filePath, String(result));
|
|
150
|
+
if (!quiet) {
|
|
151
|
+
console.log(`✓ Formatted: ${filePath}`);
|
|
152
|
+
}
|
|
153
|
+
processedCount++;
|
|
154
|
+
} else if (!write && !lintOnly && !quiet) {
|
|
155
|
+
// Preview mode
|
|
156
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
157
|
+
console.log(`File: ${filePath}`);
|
|
158
|
+
console.log('='.repeat(60));
|
|
159
|
+
console.log(String(result));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(`✗ Error processing ${filePath}:`, error.message);
|
|
164
|
+
hasErrors = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { hasErrors, processedCount, totalFiles: files.length };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Initialize .remarkrc.js configuration
|
|
173
|
+
*/
|
|
174
|
+
async function initConfig() {
|
|
175
|
+
const configPath = path.join(process.cwd(), '.remarkrc.js');
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
await fs.access(configPath);
|
|
179
|
+
console.log('⚠️ .remarkrc.js already exists');
|
|
180
|
+
return;
|
|
181
|
+
} catch {
|
|
182
|
+
// File doesn't exist, create it
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const configContent = `/**
|
|
186
|
+
* Remark configuration for markdown formatting and linting
|
|
187
|
+
* @see https://github.com/remarkjs/remark
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
export default {
|
|
191
|
+
plugins: [
|
|
192
|
+
// Frontmatter support
|
|
193
|
+
['remark-frontmatter', ['yaml']],
|
|
194
|
+
|
|
195
|
+
// GitHub Flavored Markdown
|
|
196
|
+
'remark-gfm',
|
|
197
|
+
|
|
198
|
+
// Presets
|
|
199
|
+
'remark-preset-lint-recommended',
|
|
200
|
+
'remark-preset-lint-consistent',
|
|
201
|
+
'remark-preset-lint-markdown-style-guide',
|
|
202
|
+
|
|
203
|
+
// Formatting rules
|
|
204
|
+
['remark-lint-emphasis-marker', '_'],
|
|
205
|
+
['remark-lint-strong-marker', '*'],
|
|
206
|
+
['remark-lint-unordered-list-marker-style', '-'],
|
|
207
|
+
['remark-lint-ordered-list-marker-style', '.'],
|
|
208
|
+
['remark-lint-maximum-line-length', 100],
|
|
209
|
+
|
|
210
|
+
// Stringify options for formatting
|
|
211
|
+
['remark-stringify', {
|
|
212
|
+
bullet: '-',
|
|
213
|
+
emphasis: '_',
|
|
214
|
+
fences: true,
|
|
215
|
+
listItemIndent: 'one',
|
|
216
|
+
rule: '-',
|
|
217
|
+
strong: '*',
|
|
218
|
+
tightDefinitions: true
|
|
219
|
+
}]
|
|
220
|
+
]
|
|
221
|
+
};
|
|
222
|
+
`;
|
|
223
|
+
|
|
224
|
+
await fs.writeFile(configPath, configContent);
|
|
225
|
+
console.log('✓ Created .remarkrc.js configuration file');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Main CLI entry point
|
|
230
|
+
*/
|
|
231
|
+
async function main() {
|
|
232
|
+
const args = process.argv.slice(2);
|
|
233
|
+
|
|
234
|
+
// Handle version
|
|
235
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
236
|
+
const pkg = JSON.parse(await fs.readFile(new URL('./package.json', import.meta.url), 'utf-8'));
|
|
237
|
+
console.log(pkg.version);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Handle help
|
|
242
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
243
|
+
showHelp();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const command = args[0];
|
|
248
|
+
const commandArgs = args.slice(1);
|
|
249
|
+
|
|
250
|
+
// Parse options
|
|
251
|
+
const options = {
|
|
252
|
+
quiet: commandArgs.includes('--quiet') || commandArgs.includes('-q'),
|
|
253
|
+
glob: null
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Extract glob pattern
|
|
257
|
+
const globIndex = commandArgs.findIndex(arg => arg === '--glob');
|
|
258
|
+
if (globIndex !== -1 && commandArgs[globIndex + 1]) {
|
|
259
|
+
options.glob = commandArgs[globIndex + 1];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Filter out option flags to get file arguments
|
|
263
|
+
const fileArgs = commandArgs.filter(arg =>
|
|
264
|
+
!arg.startsWith('--') &&
|
|
265
|
+
!arg.startsWith('-') &&
|
|
266
|
+
arg !== options.glob
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// Execute command
|
|
270
|
+
switch (command) {
|
|
271
|
+
case 'format': {
|
|
272
|
+
const files = await getFiles(fileArgs, options.glob);
|
|
273
|
+
if (files.length === 0) {
|
|
274
|
+
console.log('No markdown files found');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (!options.quiet) {
|
|
278
|
+
console.log(`Formatting ${files.length} file(s)...`);
|
|
279
|
+
}
|
|
280
|
+
const result = await processFiles(files, { write: true, quiet: options.quiet });
|
|
281
|
+
if (!options.quiet) {
|
|
282
|
+
console.log(`\n✓ Formatted ${result.processedCount} of ${result.totalFiles} files`);
|
|
283
|
+
}
|
|
284
|
+
process.exit(result.hasErrors ? 1 : 0);
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
case 'check': {
|
|
289
|
+
const files = await getFiles(fileArgs, options.glob);
|
|
290
|
+
if (files.length === 0) {
|
|
291
|
+
console.log('No markdown files found');
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (!options.quiet) {
|
|
295
|
+
console.log(`Checking ${files.length} file(s)...`);
|
|
296
|
+
}
|
|
297
|
+
const result = await processFiles(files, { write: false, quiet: options.quiet });
|
|
298
|
+
if (!options.quiet) {
|
|
299
|
+
console.log(`\n${result.hasErrors ? '✗' : '✓'} Checked ${result.totalFiles} files`);
|
|
300
|
+
}
|
|
301
|
+
process.exit(result.hasErrors ? 1 : 0);
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
case 'lint': {
|
|
306
|
+
const files = await getFiles(fileArgs, options.glob);
|
|
307
|
+
if (files.length === 0) {
|
|
308
|
+
console.log('No markdown files found');
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (!options.quiet) {
|
|
312
|
+
console.log(`Linting ${files.length} file(s)...`);
|
|
313
|
+
}
|
|
314
|
+
const result = await processFiles(files, { lintOnly: true, quiet: options.quiet });
|
|
315
|
+
if (!options.quiet) {
|
|
316
|
+
console.log(`\n${result.hasErrors ? '✗' : '✓'} Linted ${result.totalFiles} files`);
|
|
317
|
+
}
|
|
318
|
+
process.exit(result.hasErrors ? 1 : 0);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
case 'init': {
|
|
323
|
+
await initConfig();
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case 'setup': {
|
|
328
|
+
// Import and run setup.js
|
|
329
|
+
const setupPath = new URL('./setup.js', import.meta.url);
|
|
330
|
+
await import(setupPath);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
default:
|
|
335
|
+
console.error(`Unknown command: ${command}`);
|
|
336
|
+
console.error('Run "markdownfix --help" for usage information');
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
main().catch(error => {
|
|
342
|
+
console.error('Fatal error:', error);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@entro314labs/markdownfix",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "Opinionated markdown formatter and linter for MD, MDD and MDX files using Remark/Unified ecosystem",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/entro314-labs/markdownfix.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/entro314-labs/markdownfix#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/entro314-labs/markdownfix/issues"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
".remarkrc.js",
|
|
16
|
+
".remarkignore",
|
|
17
|
+
"setup.js",
|
|
18
|
+
"cli.js",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"markdownfix": "./cli.js",
|
|
24
|
+
"mdfix": "./cli.js",
|
|
25
|
+
"markdownfix-setup": "./setup.js"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"markdown",
|
|
29
|
+
"mdx",
|
|
30
|
+
"mdd",
|
|
31
|
+
"linter",
|
|
32
|
+
"formatter",
|
|
33
|
+
"remark",
|
|
34
|
+
"gfm",
|
|
35
|
+
"unified",
|
|
36
|
+
"markdownfix",
|
|
37
|
+
"markdown-linter",
|
|
38
|
+
"opinionated"
|
|
39
|
+
],
|
|
40
|
+
"author": "Dominikos Pritis",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"markdown-link-check": "^3.14.1",
|
|
44
|
+
"remark-cli": "^12.0.1"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22.0.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@adobe/remark-gridtables": "^3.0.15",
|
|
51
|
+
"@code-dot-org/remark-plugins": "^2.0.0",
|
|
52
|
+
"@entro314labs/mdd": "^0.0.6",
|
|
53
|
+
"@theguild/remark-mermaid": "^0.3.0",
|
|
54
|
+
"fumadocs-docgen": "^3.0.2",
|
|
55
|
+
"glob": "^11.0.3",
|
|
56
|
+
"js-yaml": "^4.1.0",
|
|
57
|
+
"rehype-remark": "^10.0.1",
|
|
58
|
+
"remark": "^15.0.1",
|
|
59
|
+
"remark-directive": "^4.0.0",
|
|
60
|
+
"remark-docx": "^0.1.8",
|
|
61
|
+
"remark-emoji": "^5.0.2",
|
|
62
|
+
"remark-frontmatter": "^5.0.0",
|
|
63
|
+
"remark-gfm": "^4.0.1",
|
|
64
|
+
"remark-html": "^16.0.1",
|
|
65
|
+
"remark-linkify": "^1.1.0",
|
|
66
|
+
"remark-lint": "^10.0.1",
|
|
67
|
+
"remark-lint-alphabetize-lists": "^3.0.0",
|
|
68
|
+
"remark-lint-definition-case": "^4.0.1",
|
|
69
|
+
"remark-lint-emphasis-marker": "^4.0.1",
|
|
70
|
+
"remark-lint-final-newline": "^3.0.1",
|
|
71
|
+
"remark-lint-frontmatter-schema": "^3.15.4",
|
|
72
|
+
"remark-lint-hard-break-spaces": "^4.1.1",
|
|
73
|
+
"remark-lint-heading-capitalization": "^1.3.0",
|
|
74
|
+
"remark-lint-heading-increment": "^4.0.1",
|
|
75
|
+
"remark-lint-heading-style": "^4.0.1",
|
|
76
|
+
"remark-lint-link-title-style": "^4.0.1",
|
|
77
|
+
"remark-lint-list-item-bullet-indent": "^5.0.1",
|
|
78
|
+
"remark-lint-list-item-indent": "^4.0.1",
|
|
79
|
+
"remark-lint-list-item-style": "^3.0.1",
|
|
80
|
+
"remark-lint-match-punctuation": "^0.2.1",
|
|
81
|
+
"remark-lint-maximum-line-length": "^4.1.1",
|
|
82
|
+
"remark-lint-mdash-style": "^1.1.1",
|
|
83
|
+
"remark-lint-mdx-jsx-attribute-sort": "^1.0.1",
|
|
84
|
+
"remark-lint-mdx-jsx-no-void-children": "^1.0.1",
|
|
85
|
+
"remark-lint-mdx-jsx-quote-style": "^1.0.1",
|
|
86
|
+
"remark-lint-mdx-jsx-self-close": "^1.0.1",
|
|
87
|
+
"remark-lint-no-dead-urls": "^2.0.1",
|
|
88
|
+
"remark-lint-no-duplicate-headings": "^4.0.1",
|
|
89
|
+
"remark-lint-no-duplicate-headings-in-section": "^4.0.1",
|
|
90
|
+
"remark-lint-no-emphasis-as-heading": "^4.0.1",
|
|
91
|
+
"remark-lint-no-empty-sections": "^4.0.0",
|
|
92
|
+
"remark-lint-no-heading-indent": "^5.0.1",
|
|
93
|
+
"remark-lint-no-heading-punctuation": "^4.0.1",
|
|
94
|
+
"remark-lint-no-trailing-spaces": "^3.0.2",
|
|
95
|
+
"remark-lint-ordered-list-marker-style": "^4.0.1",
|
|
96
|
+
"remark-lint-ordered-list-marker-value": "^4.0.1",
|
|
97
|
+
"remark-lint-strong-marker": "^4.0.1",
|
|
98
|
+
"remark-lint-table-cell-padding": "^5.1.1",
|
|
99
|
+
"remark-lint-table-pipe-alignment": "^4.1.1",
|
|
100
|
+
"remark-lint-table-pipes": "^5.0.1",
|
|
101
|
+
"remark-lint-unordered-list-marker-style": "^4.0.1",
|
|
102
|
+
"remark-mdc": "^3.7.0",
|
|
103
|
+
"remark-mdx": "^3.1.1",
|
|
104
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
105
|
+
"remark-preset-lint-consistent": "^6.0.1",
|
|
106
|
+
"remark-preset-lint-markdown-style-guide": "^6.0.1",
|
|
107
|
+
"remark-preset-lint-recommended": "^7.0.1",
|
|
108
|
+
"remark-preset-remcohaszing": "^3.1.1",
|
|
109
|
+
"remark-rehype": "^11.1.2",
|
|
110
|
+
"remark-stringify": "^11.0.0",
|
|
111
|
+
"remark-toc": "^9.0.0",
|
|
112
|
+
"remark-typography": "^0.6.36",
|
|
113
|
+
"remark-validate-links": "^13.1.0",
|
|
114
|
+
"to-vfile": "^8.0.0",
|
|
115
|
+
"unified-lint-rule": "^3.0.1",
|
|
116
|
+
"unist-util-visit": "^5.0.0",
|
|
117
|
+
"vfile-reporter": "^8.1.1"
|
|
118
|
+
},
|
|
119
|
+
"scripts": {
|
|
120
|
+
"lint": "remark . --quiet --frail",
|
|
121
|
+
"format": "remark . --output --quiet",
|
|
122
|
+
"format:check": "remark . --quiet",
|
|
123
|
+
"check-links": "markdown-link-check **/*.{md,mdx,mdd}",
|
|
124
|
+
"process": "pnpm run format && pnpm run lint",
|
|
125
|
+
"process:safe": "pnpm run format:check && pnpm run lint",
|
|
126
|
+
"clean-cache": "rm -rf .remark-cache",
|
|
127
|
+
"test": "pnpm run process:safe"
|
|
128
|
+
}
|
|
129
|
+
}
|
package/setup.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Setup script for markdown processor project
|
|
5
|
+
* Creates necessary directories and example files
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs/promises'
|
|
9
|
+
import path from 'path'
|
|
10
|
+
|
|
11
|
+
const EXAMPLE_FILES = {
|
|
12
|
+
'content/docs/getting-started.md': `---
|
|
13
|
+
title: Getting Started Guide
|
|
14
|
+
date: 2024-01-15
|
|
15
|
+
author: Team
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Getting Started Guide
|
|
19
|
+
|
|
20
|
+
This is an example markdown file that will be processed by our formatter.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
1. Clone the repository
|
|
25
|
+
2. Run \`npm install\`
|
|
26
|
+
3. Start formatting your files
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
Before you begin, make sure you have:
|
|
31
|
+
|
|
32
|
+
* Node.js 16 or higher
|
|
33
|
+
* npm or yarn package manager
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
The formatter supports various commands:
|
|
38
|
+
|
|
39
|
+
- \`npm run lint\` - Check for issues
|
|
40
|
+
- \`npm run format\` - Fix formatting
|
|
41
|
+
- \`npm run process\` - Complete processing
|
|
42
|
+
|
|
43
|
+
**Note**: Always backup your files before processing.
|
|
44
|
+
|
|
45
|
+
> **Warning**: Some changes cannot be automatically fixed and require manual review.
|
|
46
|
+
|
|
47
|
+
For more details, see the [API Reference](./api-reference.md).
|
|
48
|
+
`,
|
|
49
|
+
|
|
50
|
+
'content/docs/api-reference.md': `---
|
|
51
|
+
title: API Reference
|
|
52
|
+
date: 2024-01-20
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# API Reference
|
|
56
|
+
|
|
57
|
+
## Configuration Options
|
|
58
|
+
|
|
59
|
+
| Option | Type | Default | Description |
|
|
60
|
+
|--------|------|---------|-------------|
|
|
61
|
+
| \`bullet\` | string | \`-\` | Unordered list marker |
|
|
62
|
+
| \`emphasis\` | string | \`_\` | Emphasis marker |
|
|
63
|
+
| \`strong\` | string | \`*\` | Strong marker |
|
|
64
|
+
|
|
65
|
+
## Available Scripts
|
|
66
|
+
|
|
67
|
+
### npm run lint
|
|
68
|
+
|
|
69
|
+
Checks all markdown files for style violations.
|
|
70
|
+
|
|
71
|
+
\`\`\`bash
|
|
72
|
+
npm run lint
|
|
73
|
+
\`\`\`
|
|
74
|
+
|
|
75
|
+
### npm run format
|
|
76
|
+
|
|
77
|
+
Automatically fixes formatting issues.
|
|
78
|
+
|
|
79
|
+
\`\`\`bash
|
|
80
|
+
npm run format
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
## Custom Rules
|
|
84
|
+
|
|
85
|
+
You can add custom rules in \`.remarkrc.js\`:
|
|
86
|
+
|
|
87
|
+
\`\`\`javascript
|
|
88
|
+
['remark-lint-maximum-line-length', 80]
|
|
89
|
+
\`\`\`
|
|
90
|
+
`,
|
|
91
|
+
|
|
92
|
+
'content/blog/index.md': `# Blog Posts
|
|
93
|
+
|
|
94
|
+
Welcome to our blog! Here are our latest posts:
|
|
95
|
+
|
|
96
|
+
## Recent Posts
|
|
97
|
+
|
|
98
|
+
- [Markdown Tips and Tricks](./2024-01-15-markdown-tips.md)
|
|
99
|
+
- [MDX Features Overview](./2024-02-01-mdx-features.mdx)
|
|
100
|
+
|
|
101
|
+
## Archive
|
|
102
|
+
|
|
103
|
+
Browse all posts by date or category.
|
|
104
|
+
`,
|
|
105
|
+
|
|
106
|
+
'content/guides/style-guide.md': `---
|
|
107
|
+
title: Markdown Style Guide
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
# Markdown Style Guide
|
|
111
|
+
|
|
112
|
+
This document defines the formatting standards enforced by this project.
|
|
113
|
+
|
|
114
|
+
## Headings
|
|
115
|
+
|
|
116
|
+
- Use ATX-style headings (\`#\` syntax)
|
|
117
|
+
- Don't skip heading levels
|
|
118
|
+
- Add blank lines before and after headings
|
|
119
|
+
|
|
120
|
+
### Good Example
|
|
121
|
+
|
|
122
|
+
\`\`\`markdown
|
|
123
|
+
# Main Heading
|
|
124
|
+
|
|
125
|
+
## Section Heading
|
|
126
|
+
|
|
127
|
+
### Subsection Heading
|
|
128
|
+
\`\`\`
|
|
129
|
+
|
|
130
|
+
### Bad Example
|
|
131
|
+
|
|
132
|
+
\`\`\`markdown
|
|
133
|
+
#Main Heading
|
|
134
|
+
####Skipped Levels
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
## Lists
|
|
138
|
+
|
|
139
|
+
### Unordered Lists
|
|
140
|
+
|
|
141
|
+
Use hyphens (\`-\`) for unordered lists:
|
|
142
|
+
|
|
143
|
+
\`\`\`markdown
|
|
144
|
+
- First item
|
|
145
|
+
- Second item
|
|
146
|
+
- Nested item
|
|
147
|
+
- Another nested item
|
|
148
|
+
\`\`\`
|
|
149
|
+
|
|
150
|
+
### Ordered Lists
|
|
151
|
+
|
|
152
|
+
Use periods (\`.\`) for ordered lists:
|
|
153
|
+
|
|
154
|
+
\`\`\`markdown
|
|
155
|
+
1. First step
|
|
156
|
+
2. Second step
|
|
157
|
+
3. Third step
|
|
158
|
+
\`\`\`
|
|
159
|
+
|
|
160
|
+
## Emphasis
|
|
161
|
+
|
|
162
|
+
- Use \`_underscores_\` for _emphasis_
|
|
163
|
+
- Use \`**asterisks**\` for **strong emphasis**
|
|
164
|
+
|
|
165
|
+
## Code
|
|
166
|
+
|
|
167
|
+
### Inline Code
|
|
168
|
+
|
|
169
|
+
Use \`backticks\` for inline code.
|
|
170
|
+
|
|
171
|
+
### Code Blocks
|
|
172
|
+
|
|
173
|
+
Always use fenced code blocks with language identifiers:
|
|
174
|
+
|
|
175
|
+
\`\`\`javascript
|
|
176
|
+
function example() {
|
|
177
|
+
return "Hello World"
|
|
178
|
+
}
|
|
179
|
+
\`\`\`
|
|
180
|
+
|
|
181
|
+
## Links
|
|
182
|
+
|
|
183
|
+
- Use descriptive link text
|
|
184
|
+
- Include link titles when helpful: [Example](https://example.com "Example Website")
|
|
185
|
+
|
|
186
|
+
## Images
|
|
187
|
+
|
|
188
|
+
Always include descriptive alt text:
|
|
189
|
+
|
|
190
|
+
\`\`\`markdown
|
|
191
|
+

|
|
192
|
+
\`\`\`
|
|
193
|
+
`
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function createDirectory(dirPath) {
|
|
197
|
+
try {
|
|
198
|
+
await fs.mkdir(dirPath, { recursive: true })
|
|
199
|
+
console.log(`✓ Created directory: ${dirPath}`)
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(`✗ Failed to create directory ${dirPath}:`, error.message)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function createFile(filePath, content) {
|
|
206
|
+
try {
|
|
207
|
+
// Ensure the directory exists
|
|
208
|
+
const dir = path.dirname(filePath)
|
|
209
|
+
await createDirectory(dir)
|
|
210
|
+
|
|
211
|
+
// Write the file
|
|
212
|
+
await fs.writeFile(filePath, content, 'utf8')
|
|
213
|
+
console.log(`✓ Created file: ${filePath}`)
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.error(`✗ Failed to create file ${filePath}:`, error.message)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function setup() {
|
|
220
|
+
console.log('🚀 Setting up markdown processor project...\n')
|
|
221
|
+
|
|
222
|
+
// Create directories
|
|
223
|
+
const directories = [
|
|
224
|
+
'content',
|
|
225
|
+
'content/docs',
|
|
226
|
+
'content/blog',
|
|
227
|
+
'content/guides'
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
console.log('📁 Creating directories...')
|
|
231
|
+
for (const dir of directories) {
|
|
232
|
+
await createDirectory(dir)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log('\n📝 Creating example files...')
|
|
236
|
+
for (const [filePath, content] of Object.entries(EXAMPLE_FILES)) {
|
|
237
|
+
await createFile(filePath, content)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log('\n✅ Setup complete!')
|
|
241
|
+
console.log('\nNext steps:')
|
|
242
|
+
console.log('1. Run `npm install` to install dependencies')
|
|
243
|
+
console.log('2. Run `npm run process` to format the example files')
|
|
244
|
+
console.log('3. Check the `content/` directory for formatted examples')
|
|
245
|
+
console.log('4. Add your own markdown files to the `content/` directory')
|
|
246
|
+
console.log('\nAvailable commands:')
|
|
247
|
+
console.log('- `npm run lint` - Check for formatting issues')
|
|
248
|
+
console.log('- `npm run format` - Fix formatting issues')
|
|
249
|
+
console.log('- `npm run process` - Format and lint files')
|
|
250
|
+
console.log('- `npm run check-links` - Check for broken links')
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Run setup if this script is executed directly
|
|
254
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
255
|
+
setup().catch(console.error)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { setup }
|