confluence-cli 2.1.11 → 2.2.0

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 CHANGED
@@ -7,7 +7,7 @@ A powerful command-line interface for Atlassian Confluence that allows you to re
7
7
  - 📖 **Read pages** - Get page content in text or HTML format
8
8
  - 🔍 **Search** - Find pages using Confluence's powerful search
9
9
  - â„šī¸ **Page info** - Get detailed information about pages
10
- - 🏠 **List spaces** - View all available Confluence spaces
10
+ - 🏠 **List spaces** - View available Confluence spaces
11
11
  - âœī¸ **Create pages** - Create new pages with support for Markdown, HTML, or Storage format
12
12
  - 📝 **Update pages** - Update existing page content and titles
13
13
  - đŸ—‘ī¸ **Delete pages** - Delete (or move to trash) pages by ID or URL
@@ -691,7 +691,7 @@ confluence stats
691
691
  | `read <pageId_or_url>` | Read page content | `--format <html\|text\|storage\|markdown>` |
692
692
  | `info <pageId_or_url>` | Get page information | `--format <text\|json>` |
693
693
  | `search <query>` | Search for pages | `--limit <number>` |
694
- | `spaces` | List all available spaces | |
694
+ | `spaces` | List available spaces | `--limit <number>` |
695
695
  | `find <title>` | Find a page by its title | `--space <spaceKey>` |
696
696
  | `children <pageId>` | List child pages of a page | `--recursive`, `--max-depth <number>`, `--format <list\|tree\|json>`, `--show-url`, `--show-id` |
697
697
  | `create <title> <spaceKey>` | Create a new page | `--content <string>`, `--file <path>`, `--format <storage\|html\|markdown>`|
@@ -739,7 +739,7 @@ confluence info 123456789
739
739
  # Search with limit
740
740
  confluence search "API documentation" --limit 3
741
741
 
742
- # List all spaces
742
+ # List spaces
743
743
  confluence spaces
744
744
 
745
745
  # Move a page to a new parent
package/bin/confluence.js CHANGED
@@ -139,13 +139,14 @@ program
139
139
  // List spaces command
140
140
  program
141
141
  .command('spaces')
142
- .description('List all Confluence spaces')
143
- .action(async () => {
142
+ .description('List Confluence spaces')
143
+ .option('-l, --limit <limit>', 'Limit number of results', '500')
144
+ .action(async (options) => {
144
145
  const analytics = new Analytics();
145
146
  try {
146
147
  const config = getConfig(getProfileName());
147
148
  const client = new ConfluenceClient(config);
148
- const spaces = await client.getSpaces();
149
+ const spaces = await client.getSpaces(parseInt(options.limit));
149
150
 
150
151
  console.log(chalk.blue('Available spaces:'));
151
152
  spaces.forEach(space => {
@@ -437,12 +437,12 @@ class ConfluenceClient {
437
437
  }
438
438
 
439
439
  /**
440
- * Get all spaces
440
+ * Get spaces
441
441
  */
442
- async getSpaces() {
442
+ async getSpaces(limit = 500) {
443
443
  const response = await this.client.get('/space', {
444
444
  params: {
445
- limit: 500
445
+ limit
446
446
  }
447
447
  });
448
448
 
@@ -135,7 +135,11 @@ class MacroConverter {
135
135
  buildUrl: this.buildUrl,
136
136
  webUrlPrefix: this.webUrlPrefix,
137
137
  });
138
- return walker.walk(storage);
138
+ const result = walker.walk(storage);
139
+ if (typeof options.onWarnings === 'function' && walker.warnings.length > 0) {
140
+ options.onWarnings(walker.warnings);
141
+ }
142
+ return result;
139
143
  }
140
144
  }
141
145
 
@@ -1,4 +1,4 @@
1
- const { parseDocument } = require('htmlparser2');
1
+ const { Parser, DomHandler } = require('htmlparser2');
2
2
  const { decodeHTML } = require('entities');
3
3
  const { fenceLength, cleanupWithFences } = require('./markdown-cleanup');
4
4
 
@@ -65,12 +65,57 @@ class StorageWalker {
65
65
 
66
66
  walk(storage) {
67
67
  this._depth = 0;
68
- const dom = parseDocument(storage, {
68
+ this.warnings = [];
69
+
70
+ // htmlparser2 in xmlMode is lenient: malformed input (unclosed tags,
71
+ // crossed nesting) is auto-closed without raising. We need to surface
72
+ // those events so callers can flag pages that were silently repaired.
73
+ //
74
+ // The handler emits onclosetag(name, isImplied) for *every* tag that
75
+ // wasn't matched by an explicit </tag> — including legitimate XML
76
+ // self-closing tags like `<br/>` and `<ri:attachment/>`. We
77
+ // distinguish the two by tracking each open tag's index range: a
78
+ // self-closing tag's open and close events share the same
79
+ // (startIndex, endIndex), while a genuinely auto-closed tag's close
80
+ // event lands at a later position in the source.
81
+ const handler = new DomHandler(null, { xmlMode: true });
82
+ const openStack = [];
83
+ const origOnOpenTag = handler.onopentag.bind(handler);
84
+ const origOnCloseTag = handler.onclosetag.bind(handler);
85
+ handler.onopentag = (...args) => {
86
+ openStack.push({ sIdx: parser.startIndex, eIdx: parser.endIndex });
87
+ origOnOpenTag(...args);
88
+ };
89
+ handler.onclosetag = (...args) => {
90
+ const [name, isImplied] = args;
91
+ const opened = openStack.pop();
92
+ if (isImplied) {
93
+ const selfClosing =
94
+ opened
95
+ && opened.sIdx === parser.startIndex
96
+ && opened.eIdx === parser.endIndex;
97
+ if (!selfClosing) {
98
+ const offset = parser.endIndex;
99
+ this.warnings.push({ type: 'implicit-close', tag: name, offset });
100
+ if (process.env.CONFLUENCE_CLI_VERBOSE) {
101
+ process.stderr.write(
102
+ `StorageWalker: auto-closed <${name}> at offset ${offset}\n`,
103
+ );
104
+ }
105
+ }
106
+ }
107
+ origOnCloseTag(...args);
108
+ };
109
+
110
+ const parser = new Parser(handler, {
69
111
  xmlMode: true,
70
112
  recognizeSelfClosing: true,
71
113
  decodeEntities: true,
72
114
  });
73
- return this.cleanup(this.walkNodes(dom.children));
115
+ parser.write(storage);
116
+ parser.end();
117
+
118
+ return this.cleanup(this.walkNodes(handler.dom));
74
119
  }
75
120
 
76
121
  walkNodes(nodes) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "confluence-cli",
3
- "version": "2.1.11",
3
+ "version": "2.2.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "confluence-cli",
9
- "version": "2.1.11",
9
+ "version": "2.2.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "axios": "^1.15.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "confluence-cli",
3
- "version": "2.1.11",
3
+ "version": "2.2.0",
4
4
  "description": "A command-line interface for Atlassian Confluence with page creation and editing capabilities",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -221,7 +221,7 @@ confluence search --cql 'siteSearch ~ "deployment pipeline" and space = "MYSPACE
221
221
 
222
222
  ### `spaces`
223
223
 
224
- List all accessible Confluence spaces (key and name).
224
+ List accessible Confluence spaces (key and name).
225
225
 
226
226
  ```sh
227
227
  confluence spaces