pipe-kan 0.13.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/pipe-kan.js +67 -27
  2. package/package.json +1 -1
package/dist/pipe-kan.js CHANGED
@@ -27,15 +27,27 @@ function issueType(fields) {
27
27
  const name = fields?.issuetype?.name ?? fields?.issueType?.name;
28
28
  return typeof name === "string" ? name : undefined;
29
29
  }
30
+ function asIssueKey(value) {
31
+ if (typeof value === "string") {
32
+ const key = value.trim();
33
+ return /^[A-Za-z][A-Za-z0-9_]*-\d+$/.test(key) ? key : undefined;
34
+ }
35
+ if (value && typeof value === "object" && "key" in value) {
36
+ return asIssueKey(value.key);
37
+ }
38
+ return;
39
+ }
30
40
  function epicKey(fields) {
31
- if (typeof fields?.parent?.key === "string")
32
- return fields.parent.key;
33
- const link = fields?.["Epic Link"];
34
- if (typeof link === "string" && link)
35
- return link;
36
- if (link && typeof link === "object" && "key" in link) {
37
- const key = link.key;
38
- if (typeof key === "string" && key)
41
+ if (!fields)
42
+ return;
43
+ const named = asIssueKey(fields.parent) ?? asIssueKey(fields.parentEpic) ?? asIssueKey(fields["Epic Link"]);
44
+ if (named)
45
+ return named;
46
+ for (const [name, value] of Object.entries(fields)) {
47
+ if (!name.startsWith("customfield_"))
48
+ continue;
49
+ const key = asIssueKey(value);
50
+ if (key)
39
51
  return key;
40
52
  }
41
53
  return;
@@ -345,7 +357,7 @@ function createJiraCli(opts = {}) {
345
357
  "issue",
346
358
  "list",
347
359
  "-q",
348
- `parent="${key}" OR "Epic Link"="${key}"`,
360
+ `(parent="${key}" OR "Epic Link"="${key}")`,
349
361
  "--raw"
350
362
  ]);
351
363
  if (result.code !== 0) {
@@ -364,7 +376,7 @@ function createJiraCli(opts = {}) {
364
376
  "issue",
365
377
  "list",
366
378
  "-q",
367
- `parent in (${list}) OR "Epic Link" in (${list})`,
379
+ `(parent in (${list}) OR "Epic Link" in (${list}))`,
368
380
  "--raw"
369
381
  ]);
370
382
  if (result.code !== 0) {
@@ -550,6 +562,24 @@ function stampMissingEpic(board, epic) {
550
562
  }
551
563
  return board;
552
564
  }
565
+ function stampRawParent(raw, epic) {
566
+ if (!Array.isArray(raw))
567
+ return [];
568
+ return raw.map((issue) => {
569
+ if (!issue || typeof issue !== "object")
570
+ return issue;
571
+ const current = issue;
572
+ const fields = current.fields;
573
+ if (!fields || typeof fields !== "object" || fields.parent)
574
+ return issue;
575
+ return { ...current, fields: { ...fields, parent: { key: epic } } };
576
+ });
577
+ }
578
+ function cardsOf(raw) {
579
+ if (!Array.isArray(raw))
580
+ return [];
581
+ return issuesToBoard(raw).columns.flatMap((column) => column.cards);
582
+ }
553
583
  function createApp(opts) {
554
584
  const cli = opts.cli ?? createStoreCli(opts.store);
555
585
  let flags = DEFAULT_FLAGS;
@@ -593,22 +623,33 @@ function createApp(opts) {
593
623
  async refresh(next) {
594
624
  if (next !== undefined)
595
625
  flags = next;
596
- childrenError = undefined;
597
626
  const [issues, epics] = await Promise.all([
598
627
  cli.list(flags),
599
628
  cli.listEpics()
600
629
  ]);
601
- payload = JSON.parse(issues);
602
- epicsPayload = JSON.parse(epics);
603
- const keys = listedEpicKeys();
630
+ const nextPayload = JSON.parse(issues);
631
+ const nextEpics = JSON.parse(epics);
632
+ const keys = issuesToBoard(nextEpics).epics.map((epic) => epic.key);
633
+ let nextChildren = [];
634
+ let nextHasCache = false;
635
+ let nextError;
604
636
  try {
605
- childrenRaw = JSON.parse(await cli.listChildren(keys));
606
- hasChildrenCache = true;
637
+ nextChildren = JSON.parse(await cli.listChildren(keys));
638
+ const cards = cardsOf(nextChildren);
639
+ if (cards.length > 0 && !cards.some((card) => card.epic)) {
640
+ nextChildren = (await Promise.all(keys.map(async (key) => stampRawParent(JSON.parse(await cli.listEpic(key)), key)))).flat();
641
+ }
642
+ nextHasCache = true;
607
643
  } catch (err) {
608
- hasChildrenCache = false;
609
- childrenRaw = [];
610
- childrenError = err instanceof Error ? err.message : "Epic children list failed";
644
+ nextHasCache = false;
645
+ nextChildren = [];
646
+ nextError = err instanceof Error ? err.message : "Epic children list failed";
611
647
  }
648
+ payload = nextPayload;
649
+ epicsPayload = nextEpics;
650
+ childrenRaw = nextChildren;
651
+ hasChildrenCache = nextHasCache;
652
+ childrenError = nextError;
612
653
  return app.board();
613
654
  },
614
655
  async children(epic) {
@@ -620,10 +661,9 @@ function createApp(opts) {
620
661
  epic: card.epic ?? epic
621
662
  }))
622
663
  ]));
623
- return {
624
- columns: Object.entries(cards).filter(([, list]) => list.length).map(([title, list]) => ({ id: title, title, cards: list })),
625
- epics: []
626
- };
664
+ const columns = Object.entries(cards).filter(([, list]) => list.length).map(([title, list]) => ({ id: title, title, cards: list }));
665
+ if (columns.length)
666
+ return { columns, epics: [] };
627
667
  }
628
668
  return stampMissingEpic(issuesToBoard(JSON.parse(await cli.listEpic(epic))), epic);
629
669
  },
@@ -1070,6 +1110,10 @@ async function runServer(opts) {
1070
1110
  await new Promise((resolve) => server.listen(port, host, resolve));
1071
1111
  const origin = `http://127.0.0.1:${port}`;
1072
1112
  const fakeConfig = writeJiraConfig(join4(tmpdir(), "pipe-kan"), origin);
1113
+ console.log(`pipe-kan http://${host}:${port}`);
1114
+ console.log(`cli ${kind === "jira" ? resolveJiraBin() : "store"}`);
1115
+ console.log(`Fake Jira ${origin}/rest/api/2/search`);
1116
+ console.log(`Fake Jira config ${fakeConfig}`);
1073
1117
  if (kind === "jira") {
1074
1118
  try {
1075
1119
  await refreshFromJira(app, kind, { piped: Boolean(piped) });
@@ -1078,10 +1122,6 @@ async function runServer(opts) {
1078
1122
  console.error(err);
1079
1123
  }
1080
1124
  }
1081
- console.log(`pipe-kan http://${host}:${port}`);
1082
- console.log(`cli ${kind === "jira" ? resolveJiraBin() : "store"}`);
1083
- console.log(`Fake Jira ${origin}/rest/api/2/search`);
1084
- console.log(`Fake Jira config ${fakeConfig}`);
1085
1125
  }
1086
1126
 
1087
1127
  // src/bin.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipe-kan",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Local Kanban for jira-cli",
5
5
  "license": "MIT",
6
6
  "type": "module",