@bestend/confluence-cli 1.16.0 → 1.16.2
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/.github/workflows/publish.yml +1 -1
- package/bin/confluence.js +20 -20
- package/lib/confluence-client.js +27 -8
- package/package.json +1 -1
package/bin/confluence.js
CHANGED
|
@@ -194,8 +194,8 @@ program
|
|
|
194
194
|
console.log(`ID: ${chalk.blue(result.id)}`);
|
|
195
195
|
}
|
|
196
196
|
console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
|
|
197
|
-
console.log(`URL: ${chalk.gray(
|
|
198
|
-
|
|
197
|
+
console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
|
|
198
|
+
|
|
199
199
|
analytics.track('create', true);
|
|
200
200
|
} catch (error) {
|
|
201
201
|
analytics.track('create', false);
|
|
@@ -249,8 +249,8 @@ program
|
|
|
249
249
|
console.log(`ID: ${chalk.blue(result.id)}`);
|
|
250
250
|
console.log(`Parent: ${chalk.blue(parentInfo.title)} (${parentId})`);
|
|
251
251
|
console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
|
|
252
|
-
console.log(`URL: ${chalk.gray(
|
|
253
|
-
|
|
252
|
+
console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
|
|
253
|
+
|
|
254
254
|
analytics.track('create_child', true);
|
|
255
255
|
} catch (error) {
|
|
256
256
|
analytics.track('create_child', false);
|
|
@@ -301,8 +301,8 @@ program
|
|
|
301
301
|
console.log(`Title: ${chalk.blue(result.title)}`);
|
|
302
302
|
console.log(`ID: ${chalk.blue(result.id)}`);
|
|
303
303
|
console.log(`Version: ${chalk.blue(result.version.number)}`);
|
|
304
|
-
console.log(`URL: ${chalk.gray(
|
|
305
|
-
|
|
304
|
+
console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
|
|
305
|
+
|
|
306
306
|
analytics.track('update', true);
|
|
307
307
|
} catch (error) {
|
|
308
308
|
analytics.track('update', false);
|
|
@@ -407,8 +407,8 @@ program
|
|
|
407
407
|
console.log(`Title: ${chalk.green(pageInfo.title)}`);
|
|
408
408
|
console.log(`ID: ${chalk.green(pageInfo.id)}`);
|
|
409
409
|
console.log(`Space: ${chalk.green(pageInfo.space.name)} (${pageInfo.space.key})`);
|
|
410
|
-
console.log(`URL: ${chalk.gray(
|
|
411
|
-
|
|
410
|
+
console.log(`URL: ${chalk.gray(client.pageUrl(pageInfo.url))}`);
|
|
411
|
+
|
|
412
412
|
analytics.track('find', true);
|
|
413
413
|
} catch (error) {
|
|
414
414
|
analytics.track('find', false);
|
|
@@ -1084,7 +1084,7 @@ program
|
|
|
1084
1084
|
console.log(` - ...and ${result.failures.length - 10} more`);
|
|
1085
1085
|
}
|
|
1086
1086
|
}
|
|
1087
|
-
console.log(`URL: ${chalk.gray(
|
|
1087
|
+
console.log(`URL: ${chalk.gray(client.pageUrl(result.rootPage._links.webui))}`);
|
|
1088
1088
|
if (options.failOnError && result.failures?.length) {
|
|
1089
1089
|
analytics.track('copy_tree', false);
|
|
1090
1090
|
console.error(chalk.red('Completed with failures and --fail-on-error is set.'));
|
|
@@ -1146,7 +1146,7 @@ program
|
|
|
1146
1146
|
type: page.type,
|
|
1147
1147
|
status: page.status,
|
|
1148
1148
|
spaceKey: page.space?.key,
|
|
1149
|
-
url:
|
|
1149
|
+
url: client.pageUrl(`/spaces/${page.space?.key}/pages/${page.id}`),
|
|
1150
1150
|
parentId: page.parentId || resolvedPageId
|
|
1151
1151
|
}))
|
|
1152
1152
|
};
|
|
@@ -1158,7 +1158,7 @@ program
|
|
|
1158
1158
|
|
|
1159
1159
|
// Build tree structure
|
|
1160
1160
|
const tree = buildTree(children, resolvedPageId);
|
|
1161
|
-
printTree(tree,
|
|
1161
|
+
printTree(tree, client, options, 1);
|
|
1162
1162
|
|
|
1163
1163
|
console.log('');
|
|
1164
1164
|
console.log(chalk.gray(`Total: ${children.length} child page${children.length === 1 ? '' : 's'}`));
|
|
@@ -1175,7 +1175,7 @@ program
|
|
|
1175
1175
|
}
|
|
1176
1176
|
|
|
1177
1177
|
if (options.showUrl) {
|
|
1178
|
-
const url =
|
|
1178
|
+
const url = client.pageUrl(`/spaces/${page.space?.key}/pages/${page.id}`);
|
|
1179
1179
|
output += `\n ${chalk.gray(url)}`;
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
@@ -1227,27 +1227,27 @@ function buildTree(pages, rootId) {
|
|
|
1227
1227
|
}
|
|
1228
1228
|
|
|
1229
1229
|
// Helper function to print tree
|
|
1230
|
-
function printTree(nodes,
|
|
1230
|
+
function printTree(nodes, client, options, depth = 1) {
|
|
1231
1231
|
nodes.forEach((node, index) => {
|
|
1232
1232
|
const isLast = index === nodes.length - 1;
|
|
1233
1233
|
const indent = ' '.repeat(depth - 1);
|
|
1234
1234
|
const prefix = isLast ? '└── ' : '├── ';
|
|
1235
|
-
|
|
1235
|
+
|
|
1236
1236
|
let output = `${indent}${prefix}📄 ${chalk.green(node.title)}`;
|
|
1237
|
-
|
|
1237
|
+
|
|
1238
1238
|
if (options.showId) {
|
|
1239
1239
|
output += ` ${chalk.gray(`(ID: ${node.id})`)}`;
|
|
1240
1240
|
}
|
|
1241
|
-
|
|
1241
|
+
|
|
1242
1242
|
if (options.showUrl) {
|
|
1243
|
-
const url =
|
|
1243
|
+
const url = client.pageUrl(`/spaces/${node.space?.key}/pages/${node.id}`);
|
|
1244
1244
|
output += `\n${indent}${isLast ? ' ' : '│ '}${chalk.gray(url)}`;
|
|
1245
1245
|
}
|
|
1246
|
-
|
|
1246
|
+
|
|
1247
1247
|
console.log(output);
|
|
1248
|
-
|
|
1248
|
+
|
|
1249
1249
|
if (node.children && node.children.length > 0) {
|
|
1250
|
-
printTree(node.children,
|
|
1250
|
+
printTree(node.children, client, options, depth + 1);
|
|
1251
1251
|
}
|
|
1252
1252
|
});
|
|
1253
1253
|
}
|
package/lib/confluence-client.js
CHANGED
|
@@ -23,6 +23,25 @@ class ConfluenceClient {
|
|
|
23
23
|
baseURL: this.baseURL,
|
|
24
24
|
headers
|
|
25
25
|
});
|
|
26
|
+
|
|
27
|
+
// Auto-detect context path (e.g., "/wiki" or "") from first API response
|
|
28
|
+
this._contextPath = null;
|
|
29
|
+
this.client.interceptors.response.use((response) => {
|
|
30
|
+
if (this._contextPath === null && response.data?._links?.context !== undefined) {
|
|
31
|
+
this._contextPath = response.data._links.context;
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Build a full page URL from a webui path (e.g., /spaces/SPACE/pages/123)
|
|
39
|
+
* Context path is auto-detected from API responses.
|
|
40
|
+
*/
|
|
41
|
+
pageUrl(path) {
|
|
42
|
+
if (!path) return '';
|
|
43
|
+
const context = this._contextPath || '';
|
|
44
|
+
return `https://${this.domain}${context}${path}`;
|
|
26
45
|
}
|
|
27
46
|
|
|
28
47
|
sanitizeStorageContent(content, options = {}) {
|
|
@@ -373,7 +392,7 @@ class ConfluenceClient {
|
|
|
373
392
|
const webui = page._links?.webui || '';
|
|
374
393
|
return {
|
|
375
394
|
title: page.title,
|
|
376
|
-
url:
|
|
395
|
+
url: this.pageUrl(webui)
|
|
377
396
|
};
|
|
378
397
|
}
|
|
379
398
|
return null;
|
|
@@ -467,7 +486,7 @@ class ConfluenceClient {
|
|
|
467
486
|
// Format: - [Page Title](URL)
|
|
468
487
|
const childPagesList = childPages.map(page => {
|
|
469
488
|
const webui = page._links?.webui || '';
|
|
470
|
-
const url =
|
|
489
|
+
const url = this.pageUrl(webui);
|
|
471
490
|
if (url) {
|
|
472
491
|
return `- [${page.title}](${url})`;
|
|
473
492
|
} else {
|
|
@@ -859,7 +878,7 @@ class ConfluenceClient {
|
|
|
859
878
|
// - pre/code → ac:structured-macro code blocks with CDATA
|
|
860
879
|
// - blockquote → info/warning/note macros
|
|
861
880
|
// - th/td content wrapped in p
|
|
862
|
-
// - hr →
|
|
881
|
+
// - hr → removed (Confluence does not use horizontal rules)
|
|
863
882
|
let storage = html;
|
|
864
883
|
|
|
865
884
|
// Wrap li content in p tags (Confluence requirement)
|
|
@@ -915,8 +934,8 @@ class ConfluenceClient {
|
|
|
915
934
|
|
|
916
935
|
// Links: keep <a href> as-is (compatible with both Cloud and Server/Data Center)
|
|
917
936
|
|
|
918
|
-
//
|
|
919
|
-
storage = storage.replace(/<hr\s*\/?>/g, '
|
|
937
|
+
// Remove horizontal rules (Confluence does not use them)
|
|
938
|
+
storage = storage.replace(/<hr\s*\/?>/g, '');
|
|
920
939
|
|
|
921
940
|
return storage;
|
|
922
941
|
}
|
|
@@ -1135,12 +1154,12 @@ class ConfluenceClient {
|
|
|
1135
1154
|
markdown = markdown.replace(/<ac:structured-macro ac:name="include"[^>]*>[\s\S]*?<ac:parameter ac:name="">[\s\S]*?<ac:link>[\s\S]*?<ri:page\s+ri:space-key="([^"]+)"\s+ri:content-title="([^"]+)"[^>]*\/>[\s\S]*?<\/ac:link>[\s\S]*?<\/ac:parameter>[\s\S]*?<\/ac:structured-macro>/g, (_, spaceKey, title) => {
|
|
1136
1155
|
// Try to build a proper URL - if spaceKey starts with ~, it's a user space
|
|
1137
1156
|
if (spaceKey.startsWith('~')) {
|
|
1138
|
-
const spacePath =
|
|
1139
|
-
return `\n> 📄 **${labels.includePage}**: [${title}](
|
|
1157
|
+
const spacePath = `/display/${spaceKey}/${encodeURIComponent(title)}`;
|
|
1158
|
+
return `\n> 📄 **${labels.includePage}**: [${title}](${this.pageUrl(spacePath)})\n`;
|
|
1140
1159
|
} else {
|
|
1141
1160
|
// For non-user spaces, we cannot construct a valid link without the page ID.
|
|
1142
1161
|
// Document that manual correction is required.
|
|
1143
|
-
return `\n> 📄 **${labels.includePage}**: [${title}](
|
|
1162
|
+
return `\n> 📄 **${labels.includePage}**: [${title}](${this.pageUrl(`/spaces/${spaceKey}/pages/[PAGE_ID_HERE]`)}) _(manual link correction required)_\n`;
|
|
1144
1163
|
}
|
|
1145
1164
|
});
|
|
1146
1165
|
|