confluence-cli 2.1.1 → 2.1.3
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/README.md +1 -1
- package/lib/macro-converter.js +55 -28
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -789,7 +789,7 @@ A blockquote whose first line is `**INFO**`, `**WARNING**`, or `**NOTE**` become
|
|
|
789
789
|
> Side note for the reader.
|
|
790
790
|
```
|
|
791
791
|
|
|
792
|
-
The reverse direction emits the
|
|
792
|
+
The reverse direction emits the same `> **INFO**` / `> **WARNING**` / `> **NOTE**` blockquote form, so multi-paragraph bodies round-trip cleanly. The bare `[!info]` / `[!warning]` / `[!note]` shorthand is still accepted on input for backwards compatibility.
|
|
793
793
|
|
|
794
794
|
A blockquote without one of these markers stays a **plain blockquote** (`<blockquote>…</blockquote>`) — `> …` is treated as a quotation, not an alert. Use the markers above when you want a callout.
|
|
795
795
|
|
package/lib/macro-converter.js
CHANGED
|
@@ -3,6 +3,10 @@ const { htmlToMarkdown } = require('./html-to-markdown');
|
|
|
3
3
|
|
|
4
4
|
const VALID_LINK_STYLES = ['smart', 'plain', 'wiki'];
|
|
5
5
|
const CALLOUT_MARKERS = ['info', 'warning', 'note'];
|
|
6
|
+
// U+E000 (Unicode Private Use Area) is used as the stash placeholder
|
|
7
|
+
// delimiter. Declared as an explicit escape so the byte is visible in source
|
|
8
|
+
// and survives editor / formatter / lint passes that strip invisible chars.
|
|
9
|
+
const STASH_DELIM = '\uE000';
|
|
6
10
|
|
|
7
11
|
class MacroConverter {
|
|
8
12
|
constructor({ isCloud = false, webUrlPrefix = '', buildUrl = null, linkStyle = null } = {}) {
|
|
@@ -24,23 +28,32 @@ class MacroConverter {
|
|
|
24
28
|
this.markdown.enable(['table', 'strikethrough', 'linkify']);
|
|
25
29
|
|
|
26
30
|
this.markdown.core.ruler.before('normalize', 'confluence_macros', (state) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return `> **WARNING**\n> ${content.trim().replace(/\n/g, '\n> ')}`;
|
|
31
|
+
// Stash fenced code blocks and inline code so the admonition rewrite
|
|
32
|
+
// below cannot transform `[!info]` tokens that the author intended as
|
|
33
|
+
// literal text inside code.
|
|
34
|
+
const stash = [];
|
|
35
|
+
state.src = state.src.replace(/```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]+`/g, (m) => {
|
|
36
|
+
stash.push(m);
|
|
37
|
+
return `${STASH_DELIM}${stash.length - 1}${STASH_DELIM}`;
|
|
35
38
|
});
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
// Anchor `[!info]` to the start of a line (string start or after a
|
|
41
|
+
// newline) so prose mid-paragraph, headings on the same line, and
|
|
42
|
+
// `> [!info]` GitHub-style alerts are left alone. The latter would
|
|
43
|
+
// otherwise expand to a nested blockquote that the storage handler's
|
|
44
|
+
// lazy regex cannot balance, producing malformed XML.
|
|
45
|
+
for (const m of CALLOUT_MARKERS) {
|
|
46
|
+
const re = new RegExp(`(^|\\n)\\[!${m}\\]\\s*([\\s\\S]*?)(?=\\n\\s*\\n|\\n\\s*\\[!|$)`, 'g');
|
|
47
|
+
state.src = state.src.replace(re, (_, pre, content) =>
|
|
48
|
+
`${pre}> **${m.toUpperCase()}**\n> ${content.trim().replace(/\n/g, '\n> ')}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
// Fall back to the original match if the index is out of range so a
|
|
53
|
+
// literal U+E000<digits>U+E000 in user prose survives untouched instead
|
|
54
|
+
// of becoming the string "undefined".
|
|
55
|
+
const restoreRe = new RegExp(`${STASH_DELIM}(\\d+)${STASH_DELIM}`, 'g');
|
|
56
|
+
state.src = state.src.replace(restoreRe, (m, i) => stash[+i] ?? m);
|
|
44
57
|
});
|
|
45
58
|
}
|
|
46
59
|
|
|
@@ -281,20 +294,34 @@ class MacroConverter {
|
|
|
281
294
|
return `\n\`\`\`\n${code}\n\`\`\`\n`;
|
|
282
295
|
});
|
|
283
296
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
// Emit the README-recommended `> **MARKER**` blockquote form rather than
|
|
298
|
+
// the bare `[!marker]` shorthand. The bare form has no explicit body
|
|
299
|
+
// terminator, so a blank line inside a multi-paragraph body is
|
|
300
|
+
// indistinguishable from the body ending — round-tripping such a body
|
|
301
|
+
// through markdownToStorage drops every paragraph after the first.
|
|
302
|
+
// The `>` prefix gives the blockquote-based handler an unambiguous body
|
|
303
|
+
// boundary, so multi-paragraph callouts survive download → re-upload.
|
|
304
|
+
// markdownToStorage still accepts the bare `[!marker]` form on input for
|
|
305
|
+
// backwards compatibility with already-downloaded files.
|
|
306
|
+
//
|
|
307
|
+
// Wrap the output with leading + trailing `\n` to combine with the single
|
|
308
|
+
// `\n` that htmlToMarkdown emits around adjacent `<p>` tags. Without
|
|
309
|
+
// these, a following `<p>after</p>` lazy-continues into the blockquote
|
|
310
|
+
// body and lands inside the macro on re-upload (blockquote semantics —
|
|
311
|
+
// unlike code fences, blockquotes have no closing delimiter).
|
|
312
|
+
for (const marker of CALLOUT_MARKERS) {
|
|
313
|
+
const re = new RegExp(`<ac:structured-macro ac:name="${marker}"[^>]*>[\\s\\S]*?<ac:rich-text-body>([\\s\\S]*?)<\\/ac:rich-text-body>[\\s\\S]*?<\\/ac:structured-macro>`, 'g');
|
|
314
|
+
markdown = markdown.replace(re, (_, content) => {
|
|
315
|
+
const body = htmlToMarkdown(content).trim();
|
|
316
|
+
const quotedBody = body
|
|
317
|
+
.split('\n')
|
|
318
|
+
.map((line) => (line.length === 0 ? '>' : `> ${line}`))
|
|
319
|
+
.join('\n');
|
|
320
|
+
const header = `> **${marker.toUpperCase()}**`;
|
|
321
|
+
const inner = body.length === 0 ? header : `${header}\n${quotedBody}`;
|
|
322
|
+
return `\n${inner}\n`;
|
|
323
|
+
});
|
|
324
|
+
}
|
|
298
325
|
|
|
299
326
|
// anchor macro → **ANCHOR: id** marker (round-trip with markdownToStorage).
|
|
300
327
|
// Must run before the generic <ac:structured-macro> catch-all below, which
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "confluence-cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "confluence-cli",
|
|
9
|
-
"version": "2.1.
|
|
9
|
+
"version": "2.1.3",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"axios": "^1.15.0",
|