comment-block-transformer 0.2.3 → 0.2.4
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/CHANGELOG.md +8 -0
- package/package.json +3 -3
- package/test/error-handling.test.js +251 -0
- package/test/indent-string.test.js +68 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.2.4](https://github.com/DavidWells/markdown-magic/compare/comment-block-transformer@0.2.3...comment-block-transformer@0.2.4) (2026-01-08)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package comment-block-transformer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
## [0.2.3](https://github.com/DavidWells/markdown-magic/compare/comment-block-transformer@0.2.2...comment-block-transformer@0.2.3) (2025-12-30)
|
|
7
15
|
|
|
8
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comment-block-transformer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Transform markdown blocks based on configured transforms",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"release:major": "pnpm run build && pnpm version major && pnpm publish"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"comment-block-parser": "1.1.
|
|
18
|
+
"comment-block-parser": "1.1.3"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^22.0.0",
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "966eb812a9044c8bcf7d5caf04a860dade0506af"
|
|
29
29
|
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// Tests for error handling in blockTransformer
|
|
2
|
+
|
|
3
|
+
const { test } = require('uvu')
|
|
4
|
+
const assert = require('uvu/assert')
|
|
5
|
+
const { blockTransformer } = require('../src')
|
|
6
|
+
|
|
7
|
+
test('throws when removeComments is used without outputPath', async () => {
|
|
8
|
+
const text = `
|
|
9
|
+
<!-- block test -->
|
|
10
|
+
content
|
|
11
|
+
<!-- /block -->
|
|
12
|
+
`
|
|
13
|
+
try {
|
|
14
|
+
await blockTransformer(text, {
|
|
15
|
+
removeComments: true,
|
|
16
|
+
transforms: {
|
|
17
|
+
test: (api) => api.content
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
assert.unreachable('should have thrown')
|
|
21
|
+
} catch (e) {
|
|
22
|
+
assert.ok(e.message.includes('removeComments'))
|
|
23
|
+
assert.ok(e.message.includes('outputPath'))
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('removeComments works when outputPath differs from srcPath', async () => {
|
|
28
|
+
const text = `
|
|
29
|
+
<!-- block test -->
|
|
30
|
+
content
|
|
31
|
+
<!-- /block -->
|
|
32
|
+
`
|
|
33
|
+
const result = await blockTransformer(text, {
|
|
34
|
+
srcPath: '/input.md',
|
|
35
|
+
outputPath: '/output.md',
|
|
36
|
+
removeComments: true,
|
|
37
|
+
transforms: {
|
|
38
|
+
test: (api) => api.content
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
assert.is(result.stripComments, true)
|
|
43
|
+
assert.is(result.isNewPath, true)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('propagates parse errors from unbalanced tags', async () => {
|
|
47
|
+
const text = `
|
|
48
|
+
<!-- block test -->
|
|
49
|
+
content missing close tag
|
|
50
|
+
`
|
|
51
|
+
try {
|
|
52
|
+
await blockTransformer(text, {
|
|
53
|
+
transforms: {
|
|
54
|
+
test: (api) => api.content
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
assert.unreachable('should have thrown')
|
|
58
|
+
} catch (e) {
|
|
59
|
+
assert.ok(e.message.includes('unbalanced') || e.message.includes('Fix content'))
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('includes srcPath in error message when available', async () => {
|
|
64
|
+
const text = `
|
|
65
|
+
<!-- block test -->
|
|
66
|
+
missing close tag
|
|
67
|
+
`
|
|
68
|
+
try {
|
|
69
|
+
await blockTransformer(text, {
|
|
70
|
+
srcPath: '/path/to/file.md',
|
|
71
|
+
transforms: {
|
|
72
|
+
test: (api) => api.content
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
assert.unreachable('should have thrown')
|
|
76
|
+
} catch (e) {
|
|
77
|
+
assert.ok(e.message.includes('/path/to/file.md'))
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('handles transform returning number', async () => {
|
|
82
|
+
const text = `
|
|
83
|
+
<!-- block numberTest -->
|
|
84
|
+
original
|
|
85
|
+
<!-- /block -->
|
|
86
|
+
`
|
|
87
|
+
const result = await blockTransformer(text, {
|
|
88
|
+
transforms: {
|
|
89
|
+
numberTest: () => 42
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
assert.ok(result.updatedContents.includes('42'))
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test('handles transform returning array', async () => {
|
|
97
|
+
const text = `
|
|
98
|
+
<!-- block arrayTest -->
|
|
99
|
+
original
|
|
100
|
+
<!-- /block -->
|
|
101
|
+
`
|
|
102
|
+
const result = await blockTransformer(text, {
|
|
103
|
+
transforms: {
|
|
104
|
+
arrayTest: () => ['item1', 'item2', 'item3']
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
assert.ok(result.updatedContents.includes('item1'))
|
|
109
|
+
assert.ok(result.updatedContents.includes('item2'))
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('handles transform returning object', async () => {
|
|
113
|
+
const text = `
|
|
114
|
+
<!-- block objectTest -->
|
|
115
|
+
original
|
|
116
|
+
<!-- /block -->
|
|
117
|
+
`
|
|
118
|
+
const result = await blockTransformer(text, {
|
|
119
|
+
transforms: {
|
|
120
|
+
objectTest: () => ({ key: 'value', nested: { a: 1 } })
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
assert.ok(result.updatedContents.includes('key'))
|
|
125
|
+
assert.ok(result.updatedContents.includes('value'))
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test('handles async transform that throws', async () => {
|
|
129
|
+
const text = `
|
|
130
|
+
<!-- block failingTransform -->
|
|
131
|
+
content
|
|
132
|
+
<!-- /block -->
|
|
133
|
+
`
|
|
134
|
+
try {
|
|
135
|
+
await blockTransformer(text, {
|
|
136
|
+
transforms: {
|
|
137
|
+
failingTransform: async () => {
|
|
138
|
+
throw new Error('Transform failed!')
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
assert.unreachable('should have thrown')
|
|
143
|
+
} catch (e) {
|
|
144
|
+
assert.ok(e.message.includes('Transform failed!'))
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test('handles sync transform that throws', async () => {
|
|
149
|
+
const text = `
|
|
150
|
+
<!-- block syncFail -->
|
|
151
|
+
content
|
|
152
|
+
<!-- /block -->
|
|
153
|
+
`
|
|
154
|
+
try {
|
|
155
|
+
await blockTransformer(text, {
|
|
156
|
+
transforms: {
|
|
157
|
+
syncFail: () => {
|
|
158
|
+
throw new Error('Sync transform error')
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
assert.unreachable('should have thrown')
|
|
163
|
+
} catch (e) {
|
|
164
|
+
assert.ok(e.message.includes('Sync transform error'))
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
test('handles null config gracefully', async () => {
|
|
169
|
+
const text = `
|
|
170
|
+
<!-- block test -->
|
|
171
|
+
content
|
|
172
|
+
<!-- /block -->
|
|
173
|
+
`
|
|
174
|
+
// Should not throw, just return unchanged content
|
|
175
|
+
const result = await blockTransformer(text, null)
|
|
176
|
+
assert.ok(result.missingTransforms.length > 0)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('handles empty transforms object', async () => {
|
|
180
|
+
const text = `
|
|
181
|
+
<!-- block unknownTransform -->
|
|
182
|
+
content
|
|
183
|
+
<!-- /block -->
|
|
184
|
+
`
|
|
185
|
+
const result = await blockTransformer(text, {
|
|
186
|
+
transforms: {}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
assert.is(result.missingTransforms.length, 1)
|
|
190
|
+
assert.is(result.missingTransforms[0].transform, 'unknownTransform')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('handles middleware that throws', async () => {
|
|
194
|
+
const text = `
|
|
195
|
+
<!-- block test -->
|
|
196
|
+
content
|
|
197
|
+
<!-- /block -->
|
|
198
|
+
`
|
|
199
|
+
try {
|
|
200
|
+
await blockTransformer(text, {
|
|
201
|
+
transforms: {
|
|
202
|
+
test: (api) => api.content
|
|
203
|
+
},
|
|
204
|
+
beforeMiddleware: [
|
|
205
|
+
{
|
|
206
|
+
name: 'failingMiddleware',
|
|
207
|
+
transform: () => {
|
|
208
|
+
throw new Error('Middleware error')
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
})
|
|
213
|
+
assert.unreachable('should have thrown')
|
|
214
|
+
} catch (e) {
|
|
215
|
+
assert.ok(e.message.includes('Middleware error'))
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('handles transform returning undefined', async () => {
|
|
220
|
+
const text = `
|
|
221
|
+
<!-- block noReturn -->
|
|
222
|
+
original content
|
|
223
|
+
<!-- /block -->
|
|
224
|
+
`
|
|
225
|
+
const result = await blockTransformer(text, {
|
|
226
|
+
transforms: {
|
|
227
|
+
noReturn: () => undefined
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Original content should be preserved when transform returns undefined
|
|
232
|
+
assert.ok(result.updatedContents.includes('original content'))
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('handles transform returning empty string', async () => {
|
|
236
|
+
const text = `
|
|
237
|
+
<!-- block emptyReturn -->
|
|
238
|
+
original content
|
|
239
|
+
<!-- /block -->
|
|
240
|
+
`
|
|
241
|
+
const result = await blockTransformer(text, {
|
|
242
|
+
transforms: {
|
|
243
|
+
emptyReturn: () => ''
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
// Empty string is falsy, so original content is preserved (per implementation)
|
|
248
|
+
assert.ok(result.updatedContents.includes('original content'))
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test.run()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Tests for indentString utility function
|
|
2
|
+
|
|
3
|
+
const { test } = require('uvu')
|
|
4
|
+
const assert = require('uvu/assert')
|
|
5
|
+
const { indentString } = require('../src')
|
|
6
|
+
|
|
7
|
+
test('indentString - returns empty string unchanged', () => {
|
|
8
|
+
assert.is(indentString('', 2), '')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('indentString - returns null/undefined unchanged', () => {
|
|
12
|
+
assert.is(indentString(null, 2), null)
|
|
13
|
+
assert.is(indentString(undefined, 2), undefined)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('indentString - indents single line', () => {
|
|
17
|
+
assert.is(indentString('hello', 2), ' hello')
|
|
18
|
+
assert.is(indentString('hello', 4), ' hello')
|
|
19
|
+
assert.is(indentString('hello', 0), 'hello')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('indentString - indents multiple lines', () => {
|
|
23
|
+
const input = 'line1\nline2\nline3'
|
|
24
|
+
const expected = ' line1\n line2\n line3'
|
|
25
|
+
assert.is(indentString(input, 2), expected)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('indentString - preserves existing indentation', () => {
|
|
29
|
+
const input = ' already indented\n more indented'
|
|
30
|
+
const expected = ' already indented\n more indented'
|
|
31
|
+
assert.is(indentString(input, 2), expected)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('indentString - handles empty lines in multiline string', () => {
|
|
35
|
+
const input = 'line1\n\nline3'
|
|
36
|
+
const expected = ' line1\n \n line3'
|
|
37
|
+
assert.is(indentString(input, 2), expected)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('indentString - handles lines with only whitespace', () => {
|
|
41
|
+
const input = 'line1\n \nline3'
|
|
42
|
+
const expected = ' line1\n \n line3'
|
|
43
|
+
assert.is(indentString(input, 2), expected)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('indentString - handles large indent counts', () => {
|
|
47
|
+
assert.is(indentString('x', 10), ' x')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('indentString - handles trailing newline', () => {
|
|
51
|
+
const input = 'line1\nline2\n'
|
|
52
|
+
const expected = ' line1\n line2\n '
|
|
53
|
+
assert.is(indentString(input, 2), expected)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('indentString - handles leading newline', () => {
|
|
57
|
+
const input = '\nline1\nline2'
|
|
58
|
+
const expected = ' \n line1\n line2'
|
|
59
|
+
assert.is(indentString(input, 2), expected)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('indentString - handles tabs in content', () => {
|
|
63
|
+
const input = 'line\twith\ttabs'
|
|
64
|
+
const expected = ' line\twith\ttabs'
|
|
65
|
+
assert.is(indentString(input, 2), expected)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test.run()
|