imdone-core 2.3.3 → 2.3.5

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,7 @@
1
+ ## 2.3.5
2
+
3
+ - Incorporate newly added watched files into repository state before emitting `file.update`, so live board consumers can render the new task without a reload or restart.
4
+
1
5
  ## 2.3.3
2
6
 
3
7
  - Update `adm-zip` to `0.6.0` to address a high-severity ZIP parsing memory allocation vulnerability.
package/_index.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # imdone-core
2
2
 
3
- - [:file_folder: **backlog**](backlog/README)
4
3
  - [:file_folder: **docs**](docs/README)
5
4
  - [:file_folder: **notes**](notes/_index.md)
6
5
  - [CHANGELOG](CHANGELOG.md)
Binary file
@@ -0,0 +1,36 @@
1
+ function sameTask(left, right) {
2
+ return Boolean(left && right && left.equals(right))
3
+ }
4
+
5
+ export function resolveDefaultFilteredMovePosition({
6
+ task,
7
+ newList,
8
+ newPosition,
9
+ filteredCards,
10
+ repositoryListCards,
11
+ }) {
12
+ const visibleDestinationCards = filteredCards
13
+ .filter(candidate => candidate.list === newList && !sameTask(candidate, task))
14
+
15
+ if (!Number.isInteger(newPosition)
16
+ || newPosition < 0
17
+ || newPosition > visibleDestinationCards.length) {
18
+ throw new RangeError(`Filtered task position is outside ${newList}: ${newPosition}`)
19
+ }
20
+
21
+ const destinationCards = repositoryListCards
22
+ .filter(candidate => !sameTask(candidate, task))
23
+ if (visibleDestinationCards.length === 0) return destinationCards.length
24
+
25
+ const anchor = visibleDestinationCards[
26
+ Math.min(newPosition, visibleDestinationCards.length - 1)
27
+ ]
28
+ const anchorPosition = destinationCards.findIndex(candidate => sameTask(candidate, anchor))
29
+ if (anchorPosition < 0) {
30
+ throw new Error(`Filtered task is missing from ${newList}: ${anchor.id}`)
31
+ }
32
+
33
+ return newPosition < visibleDestinationCards.length
34
+ ? anchorPosition
35
+ : anchorPosition + 1
36
+ }
package/lib/index.js CHANGED
@@ -5,6 +5,7 @@ export * from './checksum.js';
5
5
  export * from './clone.js';
6
6
  export * from './config.js';
7
7
  export * from './constants.js';
8
+ export * from './default-filtered-move-position.js';
8
9
  export * from './default-settings.js';
9
10
  export * from './file.js';
10
11
  export * from './get-tasks-to-modify.js';
@@ -19,6 +19,20 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
19
19
  let initializing = false
20
20
  let refreshing = false
21
21
  let watcherPaused = false
22
+ const watcherEvents = new Set()
23
+
24
+ function trackWatcherEvent(listener) {
25
+ return (...args) => {
26
+ const event = Promise.resolve().then(() => listener(...args))
27
+ const trackedEvent = event.catch((err) => {
28
+ logger.error('Error processing watcher event')
29
+ logger.error(err)
30
+ repo.emit('watch.error', err)
31
+ })
32
+ watcherEvents.add(trackedEvent)
33
+ void trackedEvent.finally(() => watcherEvents.delete(trackedEvent))
34
+ }
35
+ }
22
36
 
23
37
  function ready() {
24
38
  return !initializing && !refreshing
@@ -80,6 +94,7 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
80
94
 
81
95
  repo.destroy = async function () {
82
96
  if (repo.watcher) await repo.watcher.close()
97
+ await Promise.allSettled([...watcherEvents])
83
98
  await _destroy.apply(repo)
84
99
  }
85
100
 
@@ -147,7 +162,10 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
147
162
  persistent: true,
148
163
  usePolling: false,
149
164
  alwaysStat: true,
150
- awaitWriteFinish: true,
165
+ awaitWriteFinish: {
166
+ stabilityThreshold: 200,
167
+ pollInterval: 50,
168
+ },
151
169
  atomic: true,
152
170
  ignoreInitial: true,
153
171
  ignored: (file) => {
@@ -169,21 +187,23 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
169
187
  initializing = false
170
188
  resolve()
171
189
  })
172
- .on('add', async function (path, stat) {
190
+ .on('add', trackWatcherEvent(async function (path, stat) {
173
191
  logger.log('Watcher received add event for file: ' + path)
174
192
  if (stat.isDirectory()) return
175
- let file = repo.getFile(path)
193
+ const relativePath = repo.getRelativePath(path)
194
+ let file = repo.getFile(relativePath)
176
195
  if (file === undefined) {
177
196
  log('Creating file: ' + path)
178
197
  file = new File({
179
198
  repoId: repo.getId(),
180
- filePath: path,
199
+ filePath: relativePath,
181
200
  languages: repo.languages,
182
201
  project: repo.project,
183
202
  })
184
203
  }
185
204
 
186
- stat = await repo.fileOK()
205
+ stat = await repo.fileOK(relativePath)
206
+ if (!stat) return
187
207
  log('fileOK returned: ' + JSON.stringify(stat))
188
208
  if (stat.mtime <= file.getModifiedTime()) {
189
209
  return log('File update already applied. Change ignored for file: ' + path)
@@ -192,8 +212,8 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
192
212
  file = await repo.readFile(file)
193
213
  repo.emit('watch.add', file)
194
214
  repo.emitFileUpdate(file)
195
- })
196
- .on('change', async function (path, stat) {
215
+ }))
216
+ .on('change', trackWatcherEvent(async function (path, stat) {
197
217
  logger.log(
198
218
  `Watcher received change event for file: ${path} repoPath: ${repo.path}`,
199
219
  stat.mtime
@@ -201,10 +221,10 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
201
221
  if (!path || stat.isDirectory()) return
202
222
 
203
223
  const relPath = repo.getRelativePath(path)
204
- if (!initializing && _isImdoneConfig(relPath)) onConfigChange(relPath)
205
- if (!initializing && _isImdoneIgnore(relPath)) onIgnoreChange(relPath)
224
+ if (!initializing && _isImdoneConfig(relPath)) return onConfigChange(relPath)
225
+ if (!initializing && _isImdoneIgnore(relPath)) return onIgnoreChange(relPath)
206
226
 
207
- var file = repo.getFile(path) || path
227
+ var file = repo.getFile(path)
208
228
  const isFile = File.isFile(file)
209
229
  // BACKLOG ## Handle the case where the file is not in the repo
210
230
  // #urgent #1.12.0
@@ -216,28 +236,37 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
216
236
  return
217
237
  }
218
238
 
219
- const ok = await repo.fileOK((file && file.path) || path)
239
+ const ok = await repo.fileOK(file?.path || path)
220
240
  if (!ok) return
221
241
  log('Reading file: ' + path)
222
- if (!isFile) file = repo.getFile(path)
242
+ if (!isFile) {
243
+ const relativePath = repo.getRelativePath(path)
244
+ file = repo.getFile(relativePath) || new File({
245
+ repoId: repo.getId(),
246
+ filePath: relativePath,
247
+ languages: repo.languages,
248
+ project: repo.project,
249
+ })
250
+ }
223
251
  file = await repo.readFile(file)
224
252
  repo.emit('watch.change', file)
225
253
  repo.emitFileUpdate(file)
226
- })
227
- .on('delete', async function (path) {
254
+ }))
255
+ .on('unlink', trackWatcherEvent(async function (path) {
228
256
  log('Watcher received unlink event for file: ' + path)
229
- repo.removeFilePath(path)
230
- var file = new File({
257
+ const relativePath = repo.getRelativePath(path)
258
+ const file = repo.getFile(relativePath) || new File({
231
259
  repoId: repo.getId(),
232
- filePath: path,
260
+ filePath: relativePath,
233
261
  languages: repo.languages,
234
262
  project: repo.project,
235
263
  })
236
- log('Removing file: ' + path)
264
+ repo.removeFilePath(relativePath)
265
+ log('Removing file: ' + relativePath)
237
266
  repo.removeFile(file)
238
267
  repo.emit('watch.delete', file)
239
268
  repo.emitFileUpdate(file, true)
240
- })
269
+ }))
241
270
  });
242
271
  }
243
272
 
package/lib/project.js CHANGED
@@ -21,6 +21,7 @@ import { renderMarkdown, extractWikilinkTopics } from './adapters/markdown.js';
21
21
  import { getFunctionSignature } from './adapters/parsers/function-parser.js';
22
22
  import { format } from './adapters/parsers/content-transformer.js';
23
23
  import { logger } from './adapters/logger.js';
24
+ import { resolveDefaultFilteredMovePosition } from './default-filtered-move-position.js';
24
25
 
25
26
  function calculateTotals(lists = []) {
26
27
  const totals = {}
@@ -459,6 +460,17 @@ export class WorkerProject extends Project {
459
460
  return await this.repo.moveTask({task, newList, newPos})
460
461
  }
461
462
 
463
+ async moveTaskInDefaultFilteredCards(task, newList, newPos) {
464
+ const repositoryPosition = resolveDefaultFilteredMovePosition({
465
+ task,
466
+ newList,
467
+ newPosition: newPos,
468
+ filteredCards: this.getDefaultFilteredCards(),
469
+ repositoryListCards: this.repo.getTasksInList(newList),
470
+ })
471
+ return await this.repo.moveTask({task, newList, newPos: repositoryPosition})
472
+ }
473
+
462
474
  getFile(filePath) {
463
475
  return this.repo.getFile(filePath)
464
476
  }
package/lib/repository.js CHANGED
@@ -988,7 +988,7 @@ export class Repository extends Emitter {
988
988
  if (!file.updated) return file
989
989
 
990
990
  await this.extractTasks(file)
991
- await this.addFile()
991
+ await this.addFile(file)
992
992
 
993
993
  return file
994
994
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "imdone-core",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,7 @@
1
+ export function resolveDefaultFilteredMovePosition({ task, newList, newPosition, filteredCards, repositoryListCards, }: {
2
+ task: any;
3
+ newList: any;
4
+ newPosition: any;
5
+ filteredCards: any;
6
+ repositoryListCards: any;
7
+ }): any;
package/types/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./checksum.js";
5
5
  export * from "./clone.js";
6
6
  export * from "./config.js";
7
7
  export * from "./constants.js";
8
+ export * from "./default-filtered-move-position.js";
8
9
  export * from "./default-settings.js";
9
10
  export * from "./file.js";
10
11
  export * from "./get-tasks-to-modify.js";
@@ -79,6 +79,7 @@ export class WorkerProject {
79
79
  addTag(task: any, tag: any): Promise<any>;
80
80
  removeTag(task: any, tag: any): Promise<any>;
81
81
  moveTask(task: any, newList: any, newPos: any): Promise<any>;
82
+ moveTaskInDefaultFilteredCards(task: any, newList: any, newPos: any): Promise<any>;
82
83
  getFile(filePath: any): any;
83
84
  getFileForTask(task: any): any;
84
85
  rollBackFileForTask(task: any): any;
package/.imdone-cli.yml DELETED
@@ -1,3 +0,0 @@
1
- backlogDir: backlog
2
- providers:
3
- - github