github-issue-tower-defence-management 1.147.2 → 1.147.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.147.4](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.147.3...v1.147.4) (2026-08-09)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **story:** consolidate a story view link written for an earlier view id ([#1464](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1464)) ([31c2035](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/31c2035320933b65544a3c0e3bc88b90d1a20c07))
7
+
8
+ ## [1.147.3](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.147.2...v1.147.3) (2026-08-09)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **story:** keep the story view link on the first line of the story issue body ([#1460](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1460)) ([20b911a](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/20b911a5062e65d726e9a1a8b8be03f2307b2e17))
14
+
1
15
  ## [1.147.2](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.147.1...v1.147.2) (2026-08-09)
2
16
 
3
17
 
@@ -29,10 +29,8 @@ class ConvertCheckboxToIssueInStoryIssueUseCase {
29
29
  console.warn(`ConvertCheckboxToIssueInStoryIssueUseCase: story issue not found by URL (possibly deleted), skipping story. storyIssueUrl: ${storyIssue.url}`);
30
30
  continue;
31
31
  }
32
- const storyViewLink = this.buildStoryViewLink(input.urlOfStoryView, storyOption.name);
33
- let newBody = freshStoryIssue.body;
34
- if (!freshStoryIssue.body.includes(storyViewLink)) {
35
- newBody = `${storyViewLink}\n\n${newBody}`;
32
+ let newBody = this.bodyWithStoryViewLinkOnFirstLine(freshStoryIssue.body, input.urlOfStoryView, storyOption.name);
33
+ if (newBody !== freshStoryIssue.body) {
36
34
  await this.issueRepository.updateIssue({
37
35
  ...freshStoryIssue,
38
36
  body: newBody,
@@ -64,9 +62,40 @@ class ConvertCheckboxToIssueInStoryIssueUseCase {
64
62
  }
65
63
  }
66
64
  };
65
+ this.bodyWithStoryViewLinkOnFirstLine = (body, urlOfStoryView, storyName) => {
66
+ const storyViewLink = this.buildStoryViewLink(urlOfStoryView, storyName);
67
+ const storyViewLinkPattern = this.buildStoryViewLinkPattern(urlOfStoryView, storyName);
68
+ const isStoryViewLinkLine = (line) => storyViewLinkPattern.test(line);
69
+ const lines = body.split('\n');
70
+ const remainingLines = [];
71
+ for (let i = 0; i < lines.length; i++) {
72
+ if (!isStoryViewLinkLine(lines[i])) {
73
+ remainingLines.push(lines[i]);
74
+ continue;
75
+ }
76
+ if (i + 1 < lines.length && lines[i + 1].trim() === '') {
77
+ i++;
78
+ continue;
79
+ }
80
+ if (remainingLines.length > 0 &&
81
+ remainingLines[remainingLines.length - 1].trim() === '') {
82
+ remainingLines.pop();
83
+ }
84
+ }
85
+ while (remainingLines.length > 0 && remainingLines[0].trim() === '') {
86
+ remainingLines.shift();
87
+ }
88
+ return `${storyViewLink}\n\n${remainingLines.join('\n')}`;
89
+ };
67
90
  this.buildStoryViewLink = (urlOfStoryView, storyName) => {
68
91
  return `${urlOfStoryView}?sliceBy%5Bvalue%5D=${(0, utils_1.encodeForURI)(storyName)}`;
69
92
  };
93
+ this.buildStoryViewLinkPattern = (urlOfStoryView, storyName) => {
94
+ const escapeForRegularExpression = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
95
+ const storyViewProjectUrl = urlOfStoryView.split('/views/')[0];
96
+ const storySliceQuery = `?sliceBy%5Bvalue%5D=${(0, utils_1.encodeForURI)(storyName)}`;
97
+ return new RegExp(`${escapeForRegularExpression(storyViewProjectUrl)}(/views/\\d+)?${escapeForRegularExpression(storySliceQuery)}(?![\\w%])`);
98
+ };
70
99
  this.findCheckboxTextsNotCreatedIssue = (storyIssueBody) => {
71
100
  const regexToFindCheckboxes = /^- \[ ] (.*)$/gm;
72
101
  const match = storyIssueBody.match(regexToFindCheckboxes);
@@ -1 +1 @@
1
- {"version":3,"file":"ConvertCheckboxToIssueInStoryIssueUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ConvertCheckboxToIssueInStoryIssueUseCase.ts"],"names":[],"mappings":";;;AAIA,mCAAuC;AACvC,+DAAgE;AAGhE,MAAa,yCAAyC;IACpD,YACW,eAOR;QAPQ,oBAAe,GAAf,eAAe,CAOvB;QAGH,QAAG,GAAG,KAAK,EAAE,KAQZ,EAAiB,EAAE;YAClB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAClC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;YACT,CAAC;YAED,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC;gBAC7D,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7C,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CACzC,CAAC;gBACF,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC/D,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC9C,SAAS;gBACX,CAAC;qBAAM,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW,EAAE,CAAC;oBACvC,MAAM,IAAI,KAAK,CAAC,0BAA0B,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChE,CAAC;qBAAM,IACL,UAAU,CAAC,QAAQ;oBACnB,UAAU,CAAC,MAAM,KAAK,mCAAkB,EACxC,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAC9D,UAAU,CAAC,GAAG,CACf,CAAC;gBACF,IAAI,CAAC,eAAe,EAAE,CAAC;oBACrB,OAAO,CAAC,IAAI,CACV,8HAA8H,UAAU,CAAC,GAAG,EAAE,CAC/I,CAAC;oBACF,SAAS;gBACX,CAAC;gBACD,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAC3C,KAAK,CAAC,cAAc,EACpB,WAAW,CAAC,IAAI,CACjB,CAAC;gBACF,IAAI,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC;gBACnC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;oBAClD,OAAO,GAAG,GAAG,aAAa,OAAO,OAAO,EAAE,CAAC;oBAC3C,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC;wBACrC,GAAG,eAAe;wBAClB,IAAI,EAAE,OAAO;qBACd,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,KAAK,CAAC,sCAAsC,EAAE,CAAC;oBAClD,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAChC,SAAS;gBACX,CAAC;gBACD,MAAM,4BAA4B,GAChC,IAAI,CAAC,gCAAgC,CAAC,OAAO,CAAC,CAAC;gBACjD,KAAK,MAAM,YAAY,IAAI,4BAA4B,EAAE,CAAC;oBACxD,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CACrC,WAAW,EACX,GAAG,WAAW,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE,CACjD,CAAC;oBACF,MAAM,YAAY,GAAG,mBAAmB,eAAe,CAAC,GAAG,EAAE,CAAC;oBAC9D,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAC9D,eAAe,CAAC,GAAG,EACnB,eAAe,CAAC,IAAI,EACpB,UAAU,EACV,YAAY,EACZ,CAAC,KAAK,CAAC,OAAO,CAAC,EACf,EAAE,CACH,CAAC;oBACF,MAAM,WAAW,GAAG,sBAAsB,eAAe,CAAC,GAAG,IAAI,eAAe,CAAC,IAAI,WAAW,cAAc,EAAE,CAAC;oBACjH,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,SAAS,YAAY,EAAE,EACvB,SAAS,WAAW,EAAE,CACvB,CAAC;oBACF,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC;wBACrC,GAAG,eAAe;wBAClB,IAAI,EAAE,OAAO;qBACd,CAAC,CAAC;oBACH,MAAM,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAC1C,KAAK,CAAC,OAAO,EACb,WAAW,CACZ,CAAC;oBACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;oBACvE,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,MAAM,IAAI,KAAK,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;oBACrD,CAAC;oBACD,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CACpC,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAClC,QAAQ,EACR,WAAW,CAAC,EAAE,CACf,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,uBAAkB,GAAG,CAAC,cAAsB,EAAE,SAAiB,EAAU,EAAE;YACzE,OAAO,GAAG,cAAc,uBAAuB,IAAA,oBAAY,EAAC,SAAS,CAAC,EAAE,CAAC;QAC3E,CAAC,CAAC;QACF,qCAAgC,GAAG,CAAC,cAAsB,EAAY,EAAE;YACtE,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;YAChD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;YAC1D,IAAI,CAAC,KAAK;gBAAE,OAAO,EAAE,CAAC;YACtB,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,QAAQ,EAAE,EAAE,CACX,QAAQ,KAAK,EAAE;gBACf,CAAC,QAAQ,CAAC,KAAK,CAAC,yCAAyC,CAAC;gBAC1D,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC5B,CAAC;QACJ,CAAC,CAAC;IApHC,CAAC;CAqHL;AA/HD,8FA+HC"}
1
+ {"version":3,"file":"ConvertCheckboxToIssueInStoryIssueUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ConvertCheckboxToIssueInStoryIssueUseCase.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.147.2",
3
+ "version": "1.147.4",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -1208,6 +1208,147 @@ Some description without checkboxes`,
1208
1208
  }),
1209
1209
  ).rejects.toThrow('GraphQL request failed');
1210
1210
  });
1211
+
1212
+ describe('story view link position', () => {
1213
+ const storyViewLink = 'https://example.com?sliceBy%5Bvalue%5D=Story%201';
1214
+
1215
+ const runWithBody = async (body: string): Promise<void> => {
1216
+ jest.clearAllMocks();
1217
+ mockIssueRepository.getIssueByUrl.mockResolvedValue({
1218
+ ...basicStoryIssue1,
1219
+ body,
1220
+ });
1221
+ const useCase = new ConvertCheckboxToIssueInStoryIssueUseCase(
1222
+ mockIssueRepository,
1223
+ );
1224
+ await useCase.run({
1225
+ project: singleStoryProject,
1226
+ issues: [basicStoryIssue1],
1227
+ cacheUsed: false,
1228
+ urlOfStoryView: 'https://example.com',
1229
+ storyObjectMap: singleStoryObjectMap,
1230
+ manager: 'ManagerName',
1231
+ createTaskFromStoryBodyCheckboxEnabled: false,
1232
+ });
1233
+ };
1234
+
1235
+ it('moves the story view link back to the first line when it sits in the middle of the body', async () => {
1236
+ await runWithBody(`Background text
1237
+
1238
+ ${storyViewLink}
1239
+
1240
+ - [ ] Task 1`);
1241
+
1242
+ expect(mockIssueRepository.updateIssue.mock.calls).toHaveLength(1);
1243
+ expect(mockIssueRepository.updateIssue.mock.calls[0][0].body)
1244
+ .toBe(`${storyViewLink}
1245
+
1246
+ Background text
1247
+
1248
+ - [ ] Task 1`);
1249
+ });
1250
+
1251
+ it('moves the story view link back to the first line when it sits at the bottom of the body', async () => {
1252
+ await runWithBody(`Background text
1253
+
1254
+ - [ ] Task 1
1255
+
1256
+ ${storyViewLink}`);
1257
+
1258
+ expect(mockIssueRepository.updateIssue.mock.calls).toHaveLength(1);
1259
+ expect(mockIssueRepository.updateIssue.mock.calls[0][0].body)
1260
+ .toBe(`${storyViewLink}
1261
+
1262
+ Background text
1263
+
1264
+ - [ ] Task 1`);
1265
+ });
1266
+
1267
+ it('leaves a single story view link on the first line when the body holds more than one copy', async () => {
1268
+ await runWithBody(`${storyViewLink}
1269
+
1270
+ Background text
1271
+
1272
+ ${storyViewLink}`);
1273
+
1274
+ expect(mockIssueRepository.updateIssue.mock.calls).toHaveLength(1);
1275
+ expect(mockIssueRepository.updateIssue.mock.calls[0][0].body)
1276
+ .toBe(`${storyViewLink}
1277
+
1278
+ Background text`);
1279
+ });
1280
+
1281
+ it('does not update the issue when the story view link is already the first line', async () => {
1282
+ await runWithBody(`${storyViewLink}
1283
+
1284
+ - [ ] Task 1`);
1285
+
1286
+ expect(mockIssueRepository.updateIssue).not.toHaveBeenCalled();
1287
+ });
1288
+ });
1289
+
1290
+ describe('story view link written for an earlier view id', () => {
1291
+ const urlOfStoryView =
1292
+ 'https://github.com/users/TestUser/projects/48/views/48';
1293
+ const currentStoryViewLink = `${urlOfStoryView}?sliceBy%5Bvalue%5D=Story%201`;
1294
+ const earlierStoryViewLink =
1295
+ 'https://github.com/users/TestUser/projects/48/views/44?sliceBy%5Bvalue%5D=Story%201';
1296
+ const otherStoryViewLink = `${urlOfStoryView}?sliceBy%5Bvalue%5D=Story%202`;
1297
+
1298
+ const runWithBody = async (body: string): Promise<void> => {
1299
+ jest.clearAllMocks();
1300
+ mockIssueRepository.getIssueByUrl.mockResolvedValue({
1301
+ ...basicStoryIssue1,
1302
+ body,
1303
+ });
1304
+ const useCase = new ConvertCheckboxToIssueInStoryIssueUseCase(
1305
+ mockIssueRepository,
1306
+ );
1307
+ await useCase.run({
1308
+ project: singleStoryProject,
1309
+ issues: [basicStoryIssue1],
1310
+ cacheUsed: false,
1311
+ urlOfStoryView,
1312
+ storyObjectMap: singleStoryObjectMap,
1313
+ manager: 'ManagerName',
1314
+ createTaskFromStoryBodyCheckboxEnabled: false,
1315
+ });
1316
+ };
1317
+
1318
+ it('removes a story view link that names an earlier view id of the same project', async () => {
1319
+ await runWithBody(`${currentStoryViewLink}
1320
+
1321
+ ${earlierStoryViewLink}
1322
+
1323
+ - [ ] Task 1`);
1324
+
1325
+ expect(mockIssueRepository.updateIssue.mock.calls).toHaveLength(1);
1326
+ expect(mockIssueRepository.updateIssue.mock.calls[0][0].body)
1327
+ .toBe(`${currentStoryViewLink}
1328
+
1329
+ - [ ] Task 1`);
1330
+ });
1331
+
1332
+ it('lifts a story view link that names an earlier view id to the current link on the first line', async () => {
1333
+ await runWithBody(`Background text
1334
+
1335
+ ${earlierStoryViewLink}`);
1336
+
1337
+ expect(mockIssueRepository.updateIssue.mock.calls).toHaveLength(1);
1338
+ expect(mockIssueRepository.updateIssue.mock.calls[0][0].body)
1339
+ .toBe(`${currentStoryViewLink}
1340
+
1341
+ Background text`);
1342
+ });
1343
+
1344
+ it('keeps a story view link that names a different story', async () => {
1345
+ await runWithBody(`${currentStoryViewLink}
1346
+
1347
+ ${otherStoryViewLink}`);
1348
+
1349
+ expect(mockIssueRepository.updateIssue).not.toHaveBeenCalled();
1350
+ });
1351
+ });
1211
1352
  });
1212
1353
 
1213
1354
  describe('buildStoryViewLink', () => {
@@ -56,13 +56,12 @@ export class ConvertCheckboxToIssueInStoryIssueUseCase {
56
56
  );
57
57
  continue;
58
58
  }
59
- const storyViewLink = this.buildStoryViewLink(
59
+ let newBody = this.bodyWithStoryViewLinkOnFirstLine(
60
+ freshStoryIssue.body,
60
61
  input.urlOfStoryView,
61
62
  storyOption.name,
62
63
  );
63
- let newBody = freshStoryIssue.body;
64
- if (!freshStoryIssue.body.includes(storyViewLink)) {
65
- newBody = `${storyViewLink}\n\n${newBody}`;
64
+ if (newBody !== freshStoryIssue.body) {
66
65
  await this.issueRepository.updateIssue({
67
66
  ...freshStoryIssue,
68
67
  body: newBody,
@@ -115,9 +114,56 @@ export class ConvertCheckboxToIssueInStoryIssueUseCase {
115
114
  }
116
115
  }
117
116
  };
117
+ bodyWithStoryViewLinkOnFirstLine = (
118
+ body: string,
119
+ urlOfStoryView: string,
120
+ storyName: string,
121
+ ): string => {
122
+ const storyViewLink = this.buildStoryViewLink(urlOfStoryView, storyName);
123
+ const storyViewLinkPattern = this.buildStoryViewLinkPattern(
124
+ urlOfStoryView,
125
+ storyName,
126
+ );
127
+ const isStoryViewLinkLine = (line: string): boolean =>
128
+ storyViewLinkPattern.test(line);
129
+ const lines = body.split('\n');
130
+ const remainingLines: string[] = [];
131
+ for (let i = 0; i < lines.length; i++) {
132
+ if (!isStoryViewLinkLine(lines[i])) {
133
+ remainingLines.push(lines[i]);
134
+ continue;
135
+ }
136
+ if (i + 1 < lines.length && lines[i + 1].trim() === '') {
137
+ i++;
138
+ continue;
139
+ }
140
+ if (
141
+ remainingLines.length > 0 &&
142
+ remainingLines[remainingLines.length - 1].trim() === ''
143
+ ) {
144
+ remainingLines.pop();
145
+ }
146
+ }
147
+ while (remainingLines.length > 0 && remainingLines[0].trim() === '') {
148
+ remainingLines.shift();
149
+ }
150
+ return `${storyViewLink}\n\n${remainingLines.join('\n')}`;
151
+ };
118
152
  buildStoryViewLink = (urlOfStoryView: string, storyName: string): string => {
119
153
  return `${urlOfStoryView}?sliceBy%5Bvalue%5D=${encodeForURI(storyName)}`;
120
154
  };
155
+ buildStoryViewLinkPattern = (
156
+ urlOfStoryView: string,
157
+ storyName: string,
158
+ ): RegExp => {
159
+ const escapeForRegularExpression = (value: string): string =>
160
+ value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
161
+ const storyViewProjectUrl = urlOfStoryView.split('/views/')[0];
162
+ const storySliceQuery = `?sliceBy%5Bvalue%5D=${encodeForURI(storyName)}`;
163
+ return new RegExp(
164
+ `${escapeForRegularExpression(storyViewProjectUrl)}(/views/\\d+)?${escapeForRegularExpression(storySliceQuery)}(?![\\w%])`,
165
+ );
166
+ };
121
167
  findCheckboxTextsNotCreatedIssue = (storyIssueBody: string): string[] => {
122
168
  const regexToFindCheckboxes = /^- \[ ] (.*)$/gm;
123
169
  const match = storyIssueBody.match(regexToFindCheckboxes);
@@ -15,7 +15,9 @@ export declare class ConvertCheckboxToIssueInStoryIssueUseCase {
15
15
  manager: Member["name"];
16
16
  createTaskFromStoryBodyCheckboxEnabled: boolean;
17
17
  }) => Promise<void>;
18
+ bodyWithStoryViewLinkOnFirstLine: (body: string, urlOfStoryView: string, storyName: string) => string;
18
19
  buildStoryViewLink: (urlOfStoryView: string, storyName: string) => string;
20
+ buildStoryViewLinkPattern: (urlOfStoryView: string, storyName: string) => RegExp;
19
21
  findCheckboxTextsNotCreatedIssue: (storyIssueBody: string) => string[];
20
22
  }
21
23
  //# sourceMappingURL=ConvertCheckboxToIssueInStoryIssueUseCase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConvertCheckboxToIssueInStoryIssueUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ConvertCheckboxToIssueInStoryIssueUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,qBAAa,yCAAyC;IAElD,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACb,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,eAAe,GACf,mBAAmB,CACtB;gBAPQ,eAAe,EAAE,IAAI,CAC5B,eAAe,EACb,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,eAAe,GACf,mBAAmB,CACtB;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,cAAc,CAAC;QAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACxB,sCAAsC,EAAE,OAAO,CAAC;KACjD,KAAG,OAAO,CAAC,IAAI,CAAC,CAwFf;IACF,kBAAkB,GAAI,gBAAgB,MAAM,EAAE,WAAW,MAAM,KAAG,MAAM,CAEtE;IACF,gCAAgC,GAAI,gBAAgB,MAAM,KAAG,MAAM,EAAE,CAcnE;CACH"}
1
+ {"version":3,"file":"ConvertCheckboxToIssueInStoryIssueUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ConvertCheckboxToIssueInStoryIssueUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,qBAAa,yCAAyC;IAElD,QAAQ,CAAC,eAAe,EAAE,IAAI,CAC5B,eAAe,EACb,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,eAAe,GACf,mBAAmB,CACtB;gBAPQ,eAAe,EAAE,IAAI,CAC5B,eAAe,EACb,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,eAAe,GACf,mBAAmB,CACtB;IAGH,GAAG,GAAU,OAAO;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,cAAc,CAAC;QAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACxB,sCAAsC,EAAE,OAAO,CAAC;KACjD,KAAG,OAAO,CAAC,IAAI,CAAC,CAuFf;IACF,gCAAgC,GAC9B,MAAM,MAAM,EACZ,gBAAgB,MAAM,EACtB,WAAW,MAAM,KAChB,MAAM,CA8BP;IACF,kBAAkB,GAAI,gBAAgB,MAAM,EAAE,WAAW,MAAM,KAAG,MAAM,CAEtE;IACF,yBAAyB,GACvB,gBAAgB,MAAM,EACtB,WAAW,MAAM,KAChB,MAAM,CAQP;IACF,gCAAgC,GAAI,gBAAgB,MAAM,KAAG,MAAM,EAAE,CAcnE;CACH"}