@aaronshaf/plane 0.1.3 → 0.1.6

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.
@@ -1,205 +1,217 @@
1
- import { describe, expect, it } from "bun:test"
2
- import { Effect, Schema } from "effect"
1
+ import { describe, expect, it } from "bun:test";
2
+ import { Effect, Schema } from "effect";
3
3
  import {
4
- WorklogSchema,
5
- WorklogsResponseSchema,
6
- IntakeIssueSchema,
7
- IntakeIssuesResponseSchema,
8
- PageSchema,
9
- PagesResponseSchema,
10
- CommentSchema,
11
- CommentsResponseSchema,
12
- CycleIssueSchema,
13
- CycleIssuesResponseSchema,
14
- } from "@/config"
15
-
16
- async function decode<A, I>(schema: Schema.Schema<A, I>, data: unknown): Promise<A> {
17
- return Effect.runPromise(
18
- Schema.decodeUnknown(schema)(data).pipe(Effect.mapError((e) => new Error(String(e)))),
19
- )
4
+ WorklogSchema,
5
+ WorklogsResponseSchema,
6
+ IntakeIssueSchema,
7
+ IntakeIssuesResponseSchema,
8
+ PageSchema,
9
+ PagesResponseSchema,
10
+ CommentSchema,
11
+ CommentsResponseSchema,
12
+ CycleIssueSchema,
13
+ CycleIssuesResponseSchema,
14
+ } from "@/config";
15
+
16
+ async function decode<A, I>(
17
+ schema: Schema.Schema<A, I>,
18
+ data: unknown,
19
+ ): Promise<A> {
20
+ return Effect.runPromise(
21
+ Schema.decodeUnknown(schema)(data).pipe(
22
+ Effect.mapError((e) => new Error(String(e))),
23
+ ),
24
+ );
20
25
  }
21
26
 
22
27
  describe("WorklogSchema", () => {
23
- it("decodes a full worklog", async () => {
24
- const w = await decode(WorklogSchema, {
25
- id: "w1",
26
- description: "Code review",
27
- duration: 90,
28
- logged_by_detail: { display_name: "Aaron" },
29
- created_at: "2025-01-15T10:00:00Z",
30
- })
31
- expect(w.duration).toBe(90)
32
- expect(w.logged_by_detail?.display_name).toBe("Aaron")
33
- })
34
-
35
- it("decodes with null description", async () => {
36
- const w = await decode(WorklogSchema, {
37
- id: "w2",
38
- description: null,
39
- duration: 30,
40
- created_at: "2025-01-15T10:00:00Z",
41
- })
42
- expect(w.description).toBeNull()
43
- })
44
-
45
- it("rejects missing duration", async () => {
46
- await expect(
47
- decode(WorklogSchema, { id: "w3", created_at: "2025-01-15T10:00:00Z" }),
48
- ).rejects.toThrow()
49
- })
50
- })
28
+ it("decodes a full worklog", async () => {
29
+ const w = await decode(WorklogSchema, {
30
+ id: "w1",
31
+ description: "Code review",
32
+ duration: 90,
33
+ logged_by_detail: { display_name: "Aaron" },
34
+ created_at: "2025-01-15T10:00:00Z",
35
+ });
36
+ expect(w.duration).toBe(90);
37
+ expect(w.logged_by_detail?.display_name).toBe("Aaron");
38
+ });
39
+
40
+ it("decodes with null description", async () => {
41
+ const w = await decode(WorklogSchema, {
42
+ id: "w2",
43
+ description: null,
44
+ duration: 30,
45
+ created_at: "2025-01-15T10:00:00Z",
46
+ });
47
+ expect(w.description).toBeNull();
48
+ });
49
+
50
+ it("rejects missing duration", async () => {
51
+ await expect(
52
+ decode(WorklogSchema, { id: "w3", created_at: "2025-01-15T10:00:00Z" }),
53
+ ).rejects.toThrow();
54
+ });
55
+ });
51
56
 
52
57
  describe("WorklogsResponseSchema", () => {
53
- it("decodes results", async () => {
54
- const resp = await decode(WorklogsResponseSchema, {
55
- results: [{ id: "w1", duration: 60, created_at: "2025-01-15T10:00:00Z" }],
56
- })
57
- expect(resp.results).toHaveLength(1)
58
- })
59
-
60
- it("decodes empty", async () => {
61
- const resp = await decode(WorklogsResponseSchema, { results: [] })
62
- expect(resp.results).toHaveLength(0)
63
- })
64
- })
58
+ it("decodes results", async () => {
59
+ const resp = await decode(WorklogsResponseSchema, {
60
+ results: [{ id: "w1", duration: 60, created_at: "2025-01-15T10:00:00Z" }],
61
+ });
62
+ expect(resp.results).toHaveLength(1);
63
+ });
64
+
65
+ it("decodes empty", async () => {
66
+ const resp = await decode(WorklogsResponseSchema, { results: [] });
67
+ expect(resp.results).toHaveLength(0);
68
+ });
69
+ });
65
70
 
66
71
  describe("IntakeIssueSchema", () => {
67
- it("decodes a full intake issue", async () => {
68
- const i = await decode(IntakeIssueSchema, {
69
- id: "int1",
70
- issue: "issue-uuid",
71
- issue_detail: { id: "issue-uuid", sequence_id: 42, name: "Bug report", priority: "high" },
72
- status: 0,
73
- created_at: "2025-01-15T10:00:00Z",
74
- })
75
- expect(i.status).toBe(0)
76
- expect(i.issue_detail?.sequence_id).toBe(42)
77
- })
78
-
79
- it("decodes minimal intake issue", async () => {
80
- const i = await decode(IntakeIssueSchema, {
81
- id: "int2",
82
- created_at: "2025-01-15T10:00:00Z",
83
- })
84
- expect(i.id).toBe("int2")
85
- expect(i.status).toBeUndefined()
86
- })
87
-
88
- it("rejects missing id", async () => {
89
- await expect(
90
- decode(IntakeIssueSchema, { created_at: "2025-01-15T10:00:00Z" }),
91
- ).rejects.toThrow()
92
- })
93
- })
72
+ it("decodes a full intake issue", async () => {
73
+ const i = await decode(IntakeIssueSchema, {
74
+ id: "int1",
75
+ issue: "issue-uuid",
76
+ issue_detail: {
77
+ id: "issue-uuid",
78
+ sequence_id: 42,
79
+ name: "Bug report",
80
+ priority: "high",
81
+ },
82
+ status: 0,
83
+ created_at: "2025-01-15T10:00:00Z",
84
+ });
85
+ expect(i.status).toBe(0);
86
+ expect(i.issue_detail?.sequence_id).toBe(42);
87
+ });
88
+
89
+ it("decodes minimal intake issue", async () => {
90
+ const i = await decode(IntakeIssueSchema, {
91
+ id: "int2",
92
+ created_at: "2025-01-15T10:00:00Z",
93
+ });
94
+ expect(i.id).toBe("int2");
95
+ expect(i.status).toBeUndefined();
96
+ });
97
+
98
+ it("rejects missing id", async () => {
99
+ await expect(
100
+ decode(IntakeIssueSchema, { created_at: "2025-01-15T10:00:00Z" }),
101
+ ).rejects.toThrow();
102
+ });
103
+ });
94
104
 
95
105
  describe("IntakeIssuesResponseSchema", () => {
96
- it("decodes results", async () => {
97
- const resp = await decode(IntakeIssuesResponseSchema, {
98
- results: [{ id: "int1", created_at: "2025-01-15T10:00:00Z" }],
99
- })
100
- expect(resp.results).toHaveLength(1)
101
- })
102
- })
106
+ it("decodes results", async () => {
107
+ const resp = await decode(IntakeIssuesResponseSchema, {
108
+ results: [{ id: "int1", created_at: "2025-01-15T10:00:00Z" }],
109
+ });
110
+ expect(resp.results).toHaveLength(1);
111
+ });
112
+ });
103
113
 
104
114
  describe("PageSchema", () => {
105
- it("decodes a page", async () => {
106
- const p = await decode(PageSchema, {
107
- id: "pg1",
108
- name: "Architecture Overview",
109
- created_at: "2025-01-15T10:00:00Z",
110
- updated_at: "2025-01-16T10:00:00Z",
111
- })
112
- expect(p.name).toBe("Architecture Overview")
113
- expect(p.updated_at).toBe("2025-01-16T10:00:00Z")
114
- })
115
-
116
- it("accepts null description_html", async () => {
117
- const p = await decode(PageSchema, {
118
- id: "pg2",
119
- name: "Empty page",
120
- description_html: null,
121
- created_at: "2025-01-15T10:00:00Z",
122
- })
123
- expect(p.description_html).toBeNull()
124
- })
125
-
126
- it("rejects missing name", async () => {
127
- await expect(
128
- decode(PageSchema, { id: "pg3", created_at: "2025-01-15T10:00:00Z" }),
129
- ).rejects.toThrow()
130
- })
131
- })
115
+ it("decodes a page", async () => {
116
+ const p = await decode(PageSchema, {
117
+ id: "pg1",
118
+ name: "Architecture Overview",
119
+ created_at: "2025-01-15T10:00:00Z",
120
+ updated_at: "2025-01-16T10:00:00Z",
121
+ });
122
+ expect(p.name).toBe("Architecture Overview");
123
+ expect(p.updated_at).toBe("2025-01-16T10:00:00Z");
124
+ });
125
+
126
+ it("accepts null description_html", async () => {
127
+ const p = await decode(PageSchema, {
128
+ id: "pg2",
129
+ name: "Empty page",
130
+ description_html: null,
131
+ created_at: "2025-01-15T10:00:00Z",
132
+ });
133
+ expect(p.description_html).toBeNull();
134
+ });
135
+
136
+ it("rejects missing name", async () => {
137
+ await expect(
138
+ decode(PageSchema, { id: "pg3", created_at: "2025-01-15T10:00:00Z" }),
139
+ ).rejects.toThrow();
140
+ });
141
+ });
132
142
 
133
143
  describe("PagesResponseSchema", () => {
134
- it("decodes results", async () => {
135
- const resp = await decode(PagesResponseSchema, {
136
- results: [{ id: "pg1", name: "Arch", created_at: "2025-01-15T10:00:00Z" }],
137
- })
138
- expect(resp.results[0].name).toBe("Arch")
139
- })
140
- })
144
+ it("decodes results", async () => {
145
+ const resp = await decode(PagesResponseSchema, {
146
+ results: [
147
+ { id: "pg1", name: "Arch", created_at: "2025-01-15T10:00:00Z" },
148
+ ],
149
+ });
150
+ expect(resp.results[0].name).toBe("Arch");
151
+ });
152
+ });
141
153
 
142
154
  describe("CommentSchema", () => {
143
- it("decodes a comment", async () => {
144
- const c = await decode(CommentSchema, {
145
- id: "c1",
146
- comment_html: "<p>Hello</p>",
147
- actor_detail: { display_name: "Aaron" },
148
- created_at: "2025-01-15T10:00:00Z",
149
- })
150
- expect(c.comment_html).toBe("<p>Hello</p>")
151
- expect(c.actor_detail?.display_name).toBe("Aaron")
152
- })
153
-
154
- it("decodes without optional fields", async () => {
155
- const c = await decode(CommentSchema, {
156
- id: "c2",
157
- created_at: "2025-01-15T10:00:00Z",
158
- })
159
- expect(c.id).toBe("c2")
160
- })
161
-
162
- it("rejects missing id", async () => {
163
- await expect(
164
- decode(CommentSchema, { created_at: "2025-01-15T10:00:00Z" }),
165
- ).rejects.toThrow()
166
- })
167
- })
155
+ it("decodes a comment", async () => {
156
+ const c = await decode(CommentSchema, {
157
+ id: "c1",
158
+ comment_html: "<p>Hello</p>",
159
+ actor_detail: { display_name: "Aaron" },
160
+ created_at: "2025-01-15T10:00:00Z",
161
+ });
162
+ expect(c.comment_html).toBe("<p>Hello</p>");
163
+ expect(c.actor_detail?.display_name).toBe("Aaron");
164
+ });
165
+
166
+ it("decodes without optional fields", async () => {
167
+ const c = await decode(CommentSchema, {
168
+ id: "c2",
169
+ created_at: "2025-01-15T10:00:00Z",
170
+ });
171
+ expect(c.id).toBe("c2");
172
+ });
173
+
174
+ it("rejects missing id", async () => {
175
+ await expect(
176
+ decode(CommentSchema, { created_at: "2025-01-15T10:00:00Z" }),
177
+ ).rejects.toThrow();
178
+ });
179
+ });
168
180
 
169
181
  describe("CommentsResponseSchema", () => {
170
- it("decodes results", async () => {
171
- const resp = await decode(CommentsResponseSchema, {
172
- results: [{ id: "c1", created_at: "2025-01-15T10:00:00Z" }],
173
- })
174
- expect(resp.results).toHaveLength(1)
175
- })
176
- })
182
+ it("decodes results", async () => {
183
+ const resp = await decode(CommentsResponseSchema, {
184
+ results: [{ id: "c1", created_at: "2025-01-15T10:00:00Z" }],
185
+ });
186
+ expect(resp.results).toHaveLength(1);
187
+ });
188
+ });
177
189
 
178
190
  describe("CycleIssueSchema", () => {
179
- it("decodes with detail", async () => {
180
- const ci = await decode(CycleIssueSchema, {
181
- id: "ci1",
182
- issue: "i1",
183
- issue_detail: { id: "i1", sequence_id: 5, name: "Fix bug" },
184
- })
185
- expect(ci.issue_detail?.sequence_id).toBe(5)
186
- })
187
-
188
- it("decodes without detail", async () => {
189
- const ci = await decode(CycleIssueSchema, { id: "ci2", issue: "i2" })
190
- expect(ci.issue).toBe("i2")
191
- })
192
-
193
- it("rejects missing issue", async () => {
194
- await expect(decode(CycleIssueSchema, { id: "ci3" })).rejects.toThrow()
195
- })
196
- })
191
+ it("decodes with detail", async () => {
192
+ const ci = await decode(CycleIssueSchema, {
193
+ id: "ci1",
194
+ issue: "i1",
195
+ issue_detail: { id: "i1", sequence_id: 5, name: "Fix bug" },
196
+ });
197
+ expect(ci.issue_detail?.sequence_id).toBe(5);
198
+ });
199
+
200
+ it("decodes without detail", async () => {
201
+ const ci = await decode(CycleIssueSchema, { id: "ci2", issue: "i2" });
202
+ expect(ci.issue).toBe("i2");
203
+ });
204
+
205
+ it("rejects missing issue", async () => {
206
+ await expect(decode(CycleIssueSchema, { id: "ci3" })).rejects.toThrow();
207
+ });
208
+ });
197
209
 
198
210
  describe("CycleIssuesResponseSchema", () => {
199
- it("decodes results", async () => {
200
- const resp = await decode(CycleIssuesResponseSchema, {
201
- results: [{ id: "ci1", issue: "i1" }],
202
- })
203
- expect(resp.results).toHaveLength(1)
204
- })
205
- })
211
+ it("decodes results", async () => {
212
+ const resp = await decode(CycleIssuesResponseSchema, {
213
+ results: [{ id: "ci1", issue: "i1" }],
214
+ });
215
+ expect(resp.results).toHaveLength(1);
216
+ });
217
+ });
@@ -1,78 +1,80 @@
1
- import { describe, expect, it, beforeEach, afterEach } from "bun:test"
2
- import { toXml } from "@/output"
1
+ import { describe, expect, it, beforeEach, afterEach } from "bun:test";
2
+ import { toXml } from "@/output";
3
3
 
4
4
  describe("toXml", () => {
5
- it("wraps results in <results> root element", () => {
6
- const out = toXml([{ id: "1", name: "Foo" }])
7
- expect(out).toStartWith("<results>")
8
- expect(out).toEndWith("</results>")
9
- })
5
+ it("wraps results in <results> root element", () => {
6
+ const out = toXml([{ id: "1", name: "Foo" }]);
7
+ expect(out).toStartWith("<results>");
8
+ expect(out).toEndWith("</results>");
9
+ });
10
10
 
11
- it("renders each item as an <item> element with attributes", () => {
12
- const out = toXml([{ id: "abc", name: "My Project" }])
13
- expect(out).toContain('<item id="abc" name="My Project">')
14
- })
11
+ it("renders each item as an <item> element with attributes", () => {
12
+ const out = toXml([{ id: "abc", name: "My Project" }]);
13
+ expect(out).toContain('<item id="abc" name="My Project">');
14
+ });
15
15
 
16
- it("renders an empty <results> for empty array", () => {
17
- const out = toXml([])
18
- expect(out).toBe("<results>\n\n</results>")
19
- })
16
+ it("renders an empty <results> for empty array", () => {
17
+ const out = toXml([]);
18
+ expect(out).toBe("<results>\n\n</results>");
19
+ });
20
20
 
21
- it("renders multiple items", () => {
22
- const out = toXml([
23
- { id: "1", name: "A" },
24
- { id: "2", name: "B" },
25
- ])
26
- expect(out).toContain('id="1"')
27
- expect(out).toContain('id="2"')
28
- })
21
+ it("renders multiple items", () => {
22
+ const out = toXml([
23
+ { id: "1", name: "A" },
24
+ { id: "2", name: "B" },
25
+ ]);
26
+ expect(out).toContain('id="1"');
27
+ expect(out).toContain('id="2"');
28
+ });
29
29
 
30
- it("escapes & in attribute values", () => {
31
- const out = toXml([{ name: "Canvas & Codegen" }])
32
- expect(out).toContain("Canvas &amp; Codegen")
33
- expect(out).not.toContain("Canvas & Codegen")
34
- })
30
+ it("escapes & in attribute values", () => {
31
+ const out = toXml([{ name: "Canvas & Codegen" }]);
32
+ expect(out).toContain("Canvas &amp; Codegen");
33
+ expect(out).not.toContain("Canvas & Codegen");
34
+ });
35
35
 
36
- it("escapes < and > in attribute values", () => {
37
- const out = toXml([{ name: "<tag>" }])
38
- expect(out).toContain("&lt;tag&gt;")
39
- })
36
+ it("escapes < and > in attribute values", () => {
37
+ const out = toXml([{ name: "<tag>" }]);
38
+ expect(out).toContain("&lt;tag&gt;");
39
+ });
40
40
 
41
- it("escapes quotes in attribute values", () => {
42
- const out = toXml([{ name: 'say "hi"' }])
43
- expect(out).toContain("&quot;hi&quot;")
44
- })
41
+ it("escapes quotes in attribute values", () => {
42
+ const out = toXml([{ name: 'say "hi"' }]);
43
+ expect(out).toContain("&quot;hi&quot;");
44
+ });
45
45
 
46
- it("renders nested objects as child elements", () => {
47
- const out = toXml([{ id: "1", state: { name: "Todo", group: "unstarted" } }])
48
- expect(out).toContain("<state")
49
- expect(out).toContain('name="Todo"')
50
- expect(out).toContain('group="unstarted"')
51
- })
46
+ it("renders nested objects as child elements", () => {
47
+ const out = toXml([
48
+ { id: "1", state: { name: "Todo", group: "unstarted" } },
49
+ ]);
50
+ expect(out).toContain("<state");
51
+ expect(out).toContain('name="Todo"');
52
+ expect(out).toContain('group="unstarted"');
53
+ });
52
54
 
53
- it("renders nested arrays as child elements", () => {
54
- const out = toXml([{ id: "1", tags: ["a", "b"] }])
55
- expect(out).toContain("<tags>")
56
- expect(out).toContain("</tags>")
57
- })
55
+ it("renders nested arrays as child elements", () => {
56
+ const out = toXml([{ id: "1", tags: ["a", "b"] }]);
57
+ expect(out).toContain("<tags>");
58
+ expect(out).toContain("</tags>");
59
+ });
58
60
 
59
- it("handles null values as empty string in attributes", () => {
60
- const out = toXml([{ id: "1", color: null }])
61
- expect(out).toContain('color=""')
62
- })
63
- })
61
+ it("handles null values as empty string in attributes", () => {
62
+ const out = toXml([{ id: "1", color: null }]);
63
+ expect(out).toContain('color=""');
64
+ });
65
+ });
64
66
 
65
67
  describe("argv stripping", () => {
66
- it("removes --json from process.argv when present", async () => {
67
- process.argv.push("--json-test-flag-xyz")
68
- // The module is already loaded; test that toXml is a function (module loaded ok)
69
- expect(typeof toXml).toBe("function")
70
- process.argv.pop()
71
- })
68
+ it("removes --json from process.argv when present", async () => {
69
+ process.argv.push("--json-test-flag-xyz");
70
+ // The module is already loaded; test that toXml is a function (module loaded ok)
71
+ expect(typeof toXml).toBe("function");
72
+ process.argv.pop();
73
+ });
72
74
 
73
- it("jsonMode and xmlMode are booleans", async () => {
74
- const { jsonMode, xmlMode } = await import("@/output")
75
- expect(typeof jsonMode).toBe("boolean")
76
- expect(typeof xmlMode).toBe("boolean")
77
- })
78
- })
75
+ it("jsonMode and xmlMode are booleans", async () => {
76
+ const { jsonMode, xmlMode } = await import("@/output");
77
+ expect(typeof jsonMode).toBe("boolean");
78
+ expect(typeof xmlMode).toBe("boolean");
79
+ });
80
+ });