@aaronshaf/confluence-cli 0.1.15

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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/package.json +73 -0
  4. package/src/cli/commands/attachments.ts +113 -0
  5. package/src/cli/commands/clone.ts +188 -0
  6. package/src/cli/commands/comments.ts +56 -0
  7. package/src/cli/commands/create.ts +58 -0
  8. package/src/cli/commands/delete.ts +46 -0
  9. package/src/cli/commands/doctor.ts +161 -0
  10. package/src/cli/commands/duplicate-check.ts +89 -0
  11. package/src/cli/commands/file-rename.ts +113 -0
  12. package/src/cli/commands/folder-hierarchy.ts +241 -0
  13. package/src/cli/commands/info.ts +56 -0
  14. package/src/cli/commands/labels.ts +53 -0
  15. package/src/cli/commands/move.ts +23 -0
  16. package/src/cli/commands/open.ts +145 -0
  17. package/src/cli/commands/pull.ts +241 -0
  18. package/src/cli/commands/push-errors.ts +40 -0
  19. package/src/cli/commands/push.ts +699 -0
  20. package/src/cli/commands/search.ts +62 -0
  21. package/src/cli/commands/setup.ts +124 -0
  22. package/src/cli/commands/spaces.ts +42 -0
  23. package/src/cli/commands/status.ts +88 -0
  24. package/src/cli/commands/tree.ts +190 -0
  25. package/src/cli/help.ts +425 -0
  26. package/src/cli/index.ts +413 -0
  27. package/src/cli/utils/browser.ts +34 -0
  28. package/src/cli/utils/progress-reporter.ts +49 -0
  29. package/src/cli.ts +6 -0
  30. package/src/lib/config.ts +156 -0
  31. package/src/lib/confluence-client/attachment-operations.ts +221 -0
  32. package/src/lib/confluence-client/client.ts +653 -0
  33. package/src/lib/confluence-client/comment-operations.ts +60 -0
  34. package/src/lib/confluence-client/folder-operations.ts +203 -0
  35. package/src/lib/confluence-client/index.ts +47 -0
  36. package/src/lib/confluence-client/label-operations.ts +102 -0
  37. package/src/lib/confluence-client/page-operations.ts +270 -0
  38. package/src/lib/confluence-client/search-operations.ts +60 -0
  39. package/src/lib/confluence-client/types.ts +329 -0
  40. package/src/lib/confluence-client/user-operations.ts +58 -0
  41. package/src/lib/dependency-sorter.ts +233 -0
  42. package/src/lib/errors.ts +237 -0
  43. package/src/lib/file-scanner.ts +195 -0
  44. package/src/lib/formatters.ts +314 -0
  45. package/src/lib/health-check.ts +204 -0
  46. package/src/lib/markdown/converter.ts +427 -0
  47. package/src/lib/markdown/frontmatter.ts +116 -0
  48. package/src/lib/markdown/html-converter.ts +398 -0
  49. package/src/lib/markdown/index.ts +21 -0
  50. package/src/lib/markdown/link-converter.ts +189 -0
  51. package/src/lib/markdown/reference-updater.ts +251 -0
  52. package/src/lib/markdown/slugify.ts +32 -0
  53. package/src/lib/page-state.ts +195 -0
  54. package/src/lib/resolve-page-target.ts +33 -0
  55. package/src/lib/space-config.ts +264 -0
  56. package/src/lib/sync/cleanup.ts +50 -0
  57. package/src/lib/sync/folder-path.ts +61 -0
  58. package/src/lib/sync/index.ts +2 -0
  59. package/src/lib/sync/link-resolution-pass.ts +139 -0
  60. package/src/lib/sync/sync-engine.ts +681 -0
  61. package/src/lib/sync/sync-specific.ts +221 -0
  62. package/src/lib/sync/types.ts +42 -0
  63. package/src/test/attachments.test.ts +68 -0
  64. package/src/test/clone.test.ts +373 -0
  65. package/src/test/comments.test.ts +53 -0
  66. package/src/test/config.test.ts +209 -0
  67. package/src/test/confluence-client.test.ts +535 -0
  68. package/src/test/delete.test.ts +39 -0
  69. package/src/test/dependency-sorter.test.ts +384 -0
  70. package/src/test/errors.test.ts +199 -0
  71. package/src/test/file-rename.test.ts +305 -0
  72. package/src/test/file-scanner.test.ts +331 -0
  73. package/src/test/folder-hierarchy.test.ts +337 -0
  74. package/src/test/formatters.test.ts +213 -0
  75. package/src/test/html-converter.test.ts +399 -0
  76. package/src/test/info.test.ts +56 -0
  77. package/src/test/labels.test.ts +70 -0
  78. package/src/test/link-conversion-integration.test.ts +189 -0
  79. package/src/test/link-converter.test.ts +413 -0
  80. package/src/test/link-resolution-pass.test.ts +368 -0
  81. package/src/test/markdown.test.ts +443 -0
  82. package/src/test/mocks/handlers.ts +228 -0
  83. package/src/test/move.test.ts +53 -0
  84. package/src/test/msw-schema-validation.ts +151 -0
  85. package/src/test/page-state.test.ts +542 -0
  86. package/src/test/push.test.ts +551 -0
  87. package/src/test/reference-updater.test.ts +293 -0
  88. package/src/test/resolve-page-target.test.ts +55 -0
  89. package/src/test/search.test.ts +64 -0
  90. package/src/test/setup-msw.ts +75 -0
  91. package/src/test/space-config.test.ts +516 -0
  92. package/src/test/spaces.test.ts +53 -0
  93. package/src/test/sync-engine.test.ts +486 -0
  94. package/src/types/turndown-plugin-gfm.d.ts +9 -0
@@ -0,0 +1,53 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { HttpResponse, http } from 'msw';
3
+ import { ConfluenceClient } from '../lib/confluence-client/client.js';
4
+ import { server } from './setup-msw.js';
5
+
6
+ const testConfig = {
7
+ confluenceUrl: 'https://test.atlassian.net',
8
+ email: 'test@example.com',
9
+ apiToken: 'test-token',
10
+ };
11
+
12
+ describe('ConfluenceClient - movePage', () => {
13
+ test('moves page successfully', async () => {
14
+ const client = new ConfluenceClient(testConfig);
15
+ await client.movePage('page-123', 'page-456', 'append');
16
+ });
17
+
18
+ test('uses append position by default', async () => {
19
+ let capturedPosition = '';
20
+ server.use(
21
+ http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', ({ params }) => {
22
+ capturedPosition = params.position as string;
23
+ return HttpResponse.json({});
24
+ }),
25
+ );
26
+
27
+ const client = new ConfluenceClient(testConfig);
28
+ await client.movePage('page-123', 'page-456');
29
+ expect(capturedPosition).toBe('append');
30
+ });
31
+
32
+ test('throws on 404', async () => {
33
+ server.use(
34
+ http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', () => {
35
+ return HttpResponse.json({ error: 'Not found' }, { status: 404 });
36
+ }),
37
+ );
38
+
39
+ const client = new ConfluenceClient(testConfig);
40
+ await expect(client.movePage('nonexistent', 'page-456')).rejects.toThrow();
41
+ });
42
+
43
+ test('throws on 401', async () => {
44
+ server.use(
45
+ http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', () => {
46
+ return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
47
+ }),
48
+ );
49
+
50
+ const client = new ConfluenceClient(testConfig);
51
+ await expect(client.movePage('page-123', 'page-456')).rejects.toThrow();
52
+ });
53
+ });
@@ -0,0 +1,151 @@
1
+ import { Schema } from 'effect';
2
+
3
+ /**
4
+ * Validate mock data against a schema and return it
5
+ * Throws an error if validation fails, helping catch mock data issues early
6
+ */
7
+ export function validateAndReturn<A, I>(schema: Schema.Schema<A, I>, data: unknown, description: string): A {
8
+ try {
9
+ return Schema.decodeUnknownSync(schema)(data);
10
+ } catch (error) {
11
+ console.error(`Schema validation failed for ${description}:`, error);
12
+ throw error;
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Create a valid user object for mocking
18
+ */
19
+ export function createValidUser(overrides: Partial<{ accountId: string; displayName: string; email: string }> = {}): {
20
+ accountId: string;
21
+ displayName?: string;
22
+ email?: string;
23
+ } {
24
+ return {
25
+ accountId: overrides.accountId || 'test-account-id',
26
+ displayName: overrides.displayName || 'Test User',
27
+ email: overrides.email || 'test@example.com',
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Create a valid space object for mocking
33
+ */
34
+ export function createValidSpace(
35
+ overrides: Partial<{ id: string; key: string; name: string; homepageId: string }> = {},
36
+ ): {
37
+ id: string;
38
+ key: string;
39
+ name: string;
40
+ homepageId?: string;
41
+ } {
42
+ return {
43
+ id: overrides.id || 'space-123',
44
+ key: overrides.key || 'TEST',
45
+ name: overrides.name || 'Test Space',
46
+ homepageId: overrides.homepageId,
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Create a valid folder object for mocking
52
+ */
53
+ export function createValidFolder(
54
+ overrides: Partial<{
55
+ id: string;
56
+ title: string;
57
+ parentId: string | null;
58
+ parentType: string | null;
59
+ }> = {},
60
+ ): {
61
+ id: string;
62
+ type: 'folder';
63
+ title: string;
64
+ parentId?: string | null;
65
+ parentType?: string | null;
66
+ authorId?: string;
67
+ ownerId?: string;
68
+ status?: string;
69
+ } {
70
+ return {
71
+ id: overrides.id || 'folder-123',
72
+ type: 'folder',
73
+ title: overrides.title || 'Test Folder',
74
+ parentId: overrides.parentId,
75
+ parentType: overrides.parentType,
76
+ authorId: 'user-123',
77
+ ownerId: 'user-123',
78
+ status: 'current',
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Create a valid attachment object for mocking
84
+ */
85
+ export function createValidAttachment(
86
+ overrides: Partial<{
87
+ id: string;
88
+ title: string;
89
+ mediaType: string;
90
+ fileSize: number;
91
+ }> = {},
92
+ ): {
93
+ id: string;
94
+ title: string;
95
+ status?: string;
96
+ mediaType?: string;
97
+ fileSize?: number;
98
+ } {
99
+ return {
100
+ id: overrides.id || 'att-123',
101
+ title: overrides.title || 'test-file.png',
102
+ status: 'current',
103
+ mediaType: overrides.mediaType || 'image/png',
104
+ fileSize: overrides.fileSize || 1024,
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Create a valid page object for mocking
110
+ */
111
+ export function createValidPage(
112
+ overrides: Partial<{
113
+ id: string;
114
+ title: string;
115
+ spaceId: string;
116
+ parentId: string | null;
117
+ authorId: string;
118
+ version: number;
119
+ body: string;
120
+ }> = {},
121
+ ): {
122
+ id: string;
123
+ title: string;
124
+ spaceId: string;
125
+ status: string;
126
+ parentId?: string | null;
127
+ authorId?: string;
128
+ version?: { number: number; createdAt?: string };
129
+ body?: { storage?: { value: string; representation?: string } };
130
+ } {
131
+ return {
132
+ id: overrides.id || 'page-123',
133
+ title: overrides.title || 'Test Page',
134
+ spaceId: overrides.spaceId || 'space-123',
135
+ status: 'current',
136
+ parentId: overrides.parentId,
137
+ authorId: overrides.authorId || 'user-123',
138
+ version: {
139
+ number: overrides.version || 1,
140
+ createdAt: new Date().toISOString(),
141
+ },
142
+ body: overrides.body
143
+ ? {
144
+ storage: {
145
+ value: overrides.body,
146
+ representation: 'storage',
147
+ },
148
+ }
149
+ : undefined,
150
+ };
151
+ }