@bestend/confluence-cli 1.15.3 → 1.15.5
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.
|
@@ -19,11 +19,15 @@ jobs:
|
|
|
19
19
|
node-version: '24.x'
|
|
20
20
|
registry-url: 'https://registry.npmjs.org'
|
|
21
21
|
|
|
22
|
-
- name:
|
|
22
|
+
- name: Ensure package version matches tag
|
|
23
23
|
run: |
|
|
24
24
|
TAG="${GITHUB_REF_NAME#v}"
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
26
|
+
echo "Tag: $TAG / package.json: $PKG_VERSION"
|
|
27
|
+
if [ "$TAG" != "$PKG_VERSION" ]; then
|
|
28
|
+
echo "package.json version mismatch: $PKG_VERSION (expected $TAG)" >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
27
31
|
|
|
28
32
|
- name: Install dependencies
|
|
29
33
|
run: npm ci
|
package/lib/confluence-client.js
CHANGED
|
@@ -24,6 +24,12 @@ class ConfluenceClient {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
sanitizeStorageContent(content) {
|
|
28
|
+
// Escape unescaped ampersands that would break XML (except already-escaped entities)
|
|
29
|
+
// This is a best-effort sanitizer; users should still provide valid XHTML when using --format storage.
|
|
30
|
+
return content.replace(/&(?![a-zA-Z]+;|#\d+;|#x[0-9a-fA-F]+;)/g, '&');
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
sanitizeApiPath(rawPath) {
|
|
28
34
|
const fallback = '/rest/api';
|
|
29
35
|
const value = (rawPath || '').trim();
|
|
@@ -61,6 +67,12 @@ class ConfluenceClient {
|
|
|
61
67
|
if (pageIdMatch) {
|
|
62
68
|
return pageIdMatch[1];
|
|
63
69
|
}
|
|
70
|
+
|
|
71
|
+
// Handle /spaces/SPACEKEY/pages/PAGEID/Title format
|
|
72
|
+
const spacesMatch = pageIdOrUrl.match(/\/spaces\/[^/]+\/pages\/(\d+)/);
|
|
73
|
+
if (spacesMatch) {
|
|
74
|
+
return spacesMatch[1];
|
|
75
|
+
}
|
|
64
76
|
|
|
65
77
|
// Handle display URLs - search by space and title
|
|
66
78
|
const displayMatch = pageIdOrUrl.match(/\/display\/([^/]+)\/(.+)/);
|
|
@@ -842,9 +854,18 @@ class ConfluenceClient {
|
|
|
842
854
|
// Convert code blocks to Confluence code macro
|
|
843
855
|
storage = storage.replace(/<pre><code(?:\s+class="language-(\w+)")?>(.*?)<\/code><\/pre>/gs, (_, lang, code) => {
|
|
844
856
|
const language = lang || 'text';
|
|
857
|
+
// Decode HTML entities inside code blocks before wrapping in CDATA
|
|
858
|
+
let decoded = code
|
|
859
|
+
.replace(/&/g, '&')
|
|
860
|
+
.replace(/</g, '<')
|
|
861
|
+
.replace(/>/g, '>')
|
|
862
|
+
.replace(/"/g, '"')
|
|
863
|
+
.replace(/'/g, "'");
|
|
864
|
+
decoded = decoded.replace(/\]\]>/g, ']]]]><![CDATA[>');
|
|
865
|
+
|
|
845
866
|
return `<ac:structured-macro ac:name="code">
|
|
846
867
|
<ac:parameter ac:name="language">${language}</ac:parameter>
|
|
847
|
-
<ac:plain-text-body><![CDATA[${
|
|
868
|
+
<ac:plain-text-body><![CDATA[${decoded}]]></ac:plain-text-body>
|
|
848
869
|
</ac:structured-macro>`;
|
|
849
870
|
});
|
|
850
871
|
|
|
@@ -885,8 +906,7 @@ class ConfluenceClient {
|
|
|
885
906
|
storage = storage.replace(/<th>(.*?)<\/th>/g, '<th><p>$1</p></th>');
|
|
886
907
|
storage = storage.replace(/<td>(.*?)<\/td>/g, '<td><p>$1</p></td>');
|
|
887
908
|
|
|
888
|
-
//
|
|
889
|
-
storage = storage.replace(/<a href="(.*?)">(.*?)<\/a>/g, '<ac:link><ri:url ri:value="$1" /><ac:plain-text-link-body><![CDATA[$2]]></ac:plain-text-link-body></ac:link>');
|
|
909
|
+
// Links: keep <a href> as-is (compatible with both Cloud and Server/Data Center)
|
|
890
910
|
|
|
891
911
|
// Convert horizontal rules
|
|
892
912
|
storage = storage.replace(/<hr\s*\/?>/g, '<hr />');
|
|
@@ -1342,6 +1362,10 @@ class ConfluenceClient {
|
|
|
1342
1362
|
storageContent = content;
|
|
1343
1363
|
}
|
|
1344
1364
|
|
|
1365
|
+
if (format === 'storage') {
|
|
1366
|
+
storageContent = this.sanitizeStorageContent(storageContent);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1345
1369
|
const pageData = {
|
|
1346
1370
|
type: 'page',
|
|
1347
1371
|
title: title,
|
|
@@ -1373,6 +1397,10 @@ class ConfluenceClient {
|
|
|
1373
1397
|
storageContent = content;
|
|
1374
1398
|
}
|
|
1375
1399
|
|
|
1400
|
+
if (format === 'storage') {
|
|
1401
|
+
storageContent = this.sanitizeStorageContent(storageContent);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1376
1404
|
const pageData = {
|
|
1377
1405
|
type: 'page',
|
|
1378
1406
|
title: title,
|
|
@@ -1419,6 +1447,10 @@ class ConfluenceClient {
|
|
|
1419
1447
|
} else { // 'storage' format
|
|
1420
1448
|
storageContent = content;
|
|
1421
1449
|
}
|
|
1450
|
+
|
|
1451
|
+
if (format === 'storage') {
|
|
1452
|
+
storageContent = this.sanitizeStorageContent(storageContent);
|
|
1453
|
+
}
|
|
1422
1454
|
} else {
|
|
1423
1455
|
// If no new content, use the existing content
|
|
1424
1456
|
storageContent = currentPage.data.body.storage.value;
|
package/package.json
CHANGED
|
@@ -141,7 +141,7 @@ describe('ConfluenceClient', () => {
|
|
|
141
141
|
|
|
142
142
|
expect(result).toContain('<ac:structured-macro ac:name="code">');
|
|
143
143
|
expect(result).toContain('<ac:parameter ac:name="language">javascript</ac:parameter>');
|
|
144
|
-
expect(result).toContain('console.log(
|
|
144
|
+
expect(result).toContain('console.log("Hello World");');
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
test('should convert lists to native Confluence format', () => {
|
|
@@ -171,12 +171,11 @@ describe('ConfluenceClient', () => {
|
|
|
171
171
|
expect(result).toContain('<td><p>Cell 1</p></td>');
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
test('should
|
|
174
|
+
test('should keep links as standard HTML anchors', () => {
|
|
175
175
|
const markdown = '[Example Link](https://example.com)';
|
|
176
176
|
const result = client.markdownToStorage(markdown);
|
|
177
177
|
|
|
178
|
-
expect(result).toContain('<
|
|
179
|
-
expect(result).toContain('ri:value="https://example.com"');
|
|
178
|
+
expect(result).toContain('<a href="https://example.com">');
|
|
180
179
|
expect(result).toContain('Example Link');
|
|
181
180
|
});
|
|
182
181
|
});
|