imdone-core 2.3.5 → 2.5.0

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.
@@ -22,15 +22,13 @@ export function resolveDefaultFilteredMovePosition({
22
22
  .filter(candidate => !sameTask(candidate, task))
23
23
  if (visibleDestinationCards.length === 0) return destinationCards.length
24
24
 
25
- const anchor = visibleDestinationCards[
26
- Math.min(newPosition, visibleDestinationCards.length - 1)
27
- ]
25
+ const anchor = newPosition === 0
26
+ ? visibleDestinationCards[0]
27
+ : visibleDestinationCards[newPosition - 1]
28
28
  const anchorPosition = destinationCards.findIndex(candidate => sameTask(candidate, anchor))
29
29
  if (anchorPosition < 0) {
30
30
  throw new Error(`Filtered task is missing from ${newList}: ${anchor.id}`)
31
31
  }
32
32
 
33
- return newPosition < visibleDestinationCards.length
34
- ? anchorPosition
35
- : anchorPosition + 1
33
+ return newPosition === 0 ? anchorPosition : anchorPosition + 1
36
34
  }
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@ export * from './get-tasks-to-modify.js';
12
12
  export * from './languages.js';
13
13
  export * from './list.js';
14
14
  export * from './migrate-config.js';
15
+ export * from './monquery.js';
15
16
  export * from './omit.js';
16
17
  export * from './project-factory.js';
17
18
  export * from './project.js';
@@ -23,6 +23,7 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
23
23
 
24
24
  function trackWatcherEvent(listener) {
25
25
  return (...args) => {
26
+ if (watcherPaused) return
26
27
  const event = Promise.resolve().then(() => listener(...args))
27
28
  const trackedEvent = event.catch((err) => {
28
29
  logger.error('Error processing watcher event')
@@ -34,6 +35,12 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
34
35
  }
35
36
  }
36
37
 
38
+ async function waitForWatcherEvents() {
39
+ while (watcherEvents.size > 0) {
40
+ await Promise.allSettled([...watcherEvents])
41
+ }
42
+ }
43
+
37
44
  function ready() {
38
45
  return !initializing && !refreshing
39
46
  }
@@ -49,8 +56,14 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
49
56
  repo.pauseWatcher = async function() {
50
57
  if (repo.watcher && !watcherPaused) {
51
58
  logger.info('Pausing file watcher for:', repo.path)
52
- await repo.watcher.close()
53
59
  watcherPaused = true
60
+ try {
61
+ await repo.watcher.close()
62
+ await waitForWatcherEvents()
63
+ } catch (err) {
64
+ watcherPaused = false
65
+ throw err
66
+ }
54
67
  repo.emit('watcher.paused')
55
68
  return true
56
69
  }
@@ -94,7 +107,7 @@ export function watchedFileSystemStoreMixin(repo, fs = realFs) {
94
107
 
95
108
  repo.destroy = async function () {
96
109
  if (repo.watcher) await repo.watcher.close()
97
- await Promise.allSettled([...watcherEvents])
110
+ await waitForWatcherEvents()
98
111
  await _destroy.apply(repo)
99
112
  }
100
113
 
@@ -0,0 +1,120 @@
1
+ // Derived from imdone/node-monquery 0.2.2, originally visionmedia/node-monquery.
2
+ // Retained under the MIT license used by both projects.
3
+ import assert from 'node:assert'
4
+
5
+ export function compile(node) {
6
+ switch (node.type) {
7
+ case 'field': {
8
+ const value = node.cmp
9
+ ? { [`$${node.cmp}`]: node.value }
10
+ : node.value
11
+ return { [node.name]: value }
12
+ }
13
+ case 'op':
14
+ return {
15
+ [`$${node.op}`]: [compile(node.left), compile(node.right)],
16
+ }
17
+ default:
18
+ return undefined
19
+ }
20
+ }
21
+
22
+ function comparison(value) {
23
+ switch (value) {
24
+ case '>': return 'gt'
25
+ case '<': return 'lt'
26
+ case '<=': return 'lte'
27
+ case '>=': return 'gte'
28
+ case '!=': return 'ne'
29
+ default: return null
30
+ }
31
+ }
32
+
33
+ function numeric(value) {
34
+ return !Number.isNaN(Number.parseFloat(value))
35
+ }
36
+
37
+ function quoted(value) {
38
+ return value[0] === "'" || value[0] === '"'
39
+ }
40
+
41
+ function pattern(value) {
42
+ const escaped = value
43
+ .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
44
+ .replace(/-/g, '\\x2d')
45
+ .replace(/\\\*/g, '.*')
46
+ return new RegExp(`^${escaped}$`)
47
+ }
48
+
49
+ function coerce(value) {
50
+ if (typeof value !== 'string') return value
51
+ if (value[0] === '/') return new RegExp(value.slice(1, -1))
52
+ if (value === 'true' || value === 'yes') return true
53
+ if (value === 'false' || value === 'no') return false
54
+ if (quoted(value)) return value.replace(/^['"]|['"]$/g, '')
55
+ if (value.includes('*')) return pattern(value)
56
+ return value
57
+ }
58
+
59
+ export function parse(input) {
60
+ let source = `(${input.trim()})`
61
+
62
+ const requireSyntax = (condition, message) => {
63
+ if (condition) return
64
+ assert.fail(`${message} near \`${source.slice(0, 10)}\``)
65
+ }
66
+
67
+ const field = () => {
68
+ const nameMatch = source.match(/^([-.\w]+)/)
69
+ if (!nameMatch) return undefined
70
+
71
+ const name = nameMatch[0]
72
+ source = source.slice(name.length)
73
+ const valueMatch = source.match(/ *([:><!=]*) *([-*\w.]+|".*?"|'.*?'|\/(.*)\/) */)
74
+ let value = true
75
+ let operator = null
76
+ if (valueMatch) {
77
+ source = source.slice(valueMatch[0].length)
78
+ value = valueMatch[2]
79
+ operator = comparison(valueMatch[1])
80
+ if (numeric(value)) value = Number.parseFloat(value)
81
+ }
82
+
83
+ return {
84
+ type: 'field',
85
+ name,
86
+ value: coerce(value),
87
+ ...(operator ? { cmp: operator } : {}),
88
+ }
89
+ }
90
+
91
+ const expression = () => {
92
+ requireSyntax(source[0] === '(', "missing opening '('")
93
+ source = source.slice(1)
94
+ const node = binaryOperation()
95
+ requireSyntax(source[0] === ')', "missing closing ')'")
96
+ source = source.slice(1)
97
+ return node
98
+ }
99
+
100
+ const primary = () => field() || expression()
101
+
102
+ const binaryOperation = () => {
103
+ const left = primary()
104
+ const operatorMatch = source.match(/^ *(OR|AND) */i)
105
+ if (!operatorMatch) return left
106
+ source = source.slice(operatorMatch[0].length)
107
+ return {
108
+ type: 'op',
109
+ op: operatorMatch[1].toLowerCase(),
110
+ left,
111
+ right: binaryOperation(),
112
+ }
113
+ }
114
+
115
+ return expression()
116
+ }
117
+
118
+ export default function monquery(input) {
119
+ return compile(parse(input))
120
+ }
package/lib/repository.js CHANGED
@@ -23,7 +23,7 @@ import { constants } from './constants.js'
23
23
  import debug from 'debug'
24
24
  const log = debug('imdone-core:Repository')
25
25
  import { List } from './list.js'
26
- import monquery from 'monquery'
26
+ import monquery from './monquery.js'
27
27
  import sift from 'sift'
28
28
  import { sort } from 'fast-sort'
29
29
  import JSONfns from 'json-fns'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "2.3.5",
3
+ "version": "2.5.0",
4
4
  "description": "imdone-core",
5
5
  "repository": {
6
6
  "type": "git",
@@ -84,7 +84,6 @@
84
84
  "markdown-it-emoji": "^2.0.0",
85
85
  "markdown-it-mark": "^3.0.1",
86
86
  "moment": "^2.29.1",
87
- "monquery": "https://github.com/imdone/node-monquery/archive/refs/tags/0.2.2.tar.gz",
88
87
  "multilang-extract-comments": "^0.4.0",
89
88
  "open": "^9.1.0",
90
89
  "ora": "^8.2.0",
package/types/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./get-tasks-to-modify.js";
12
12
  export * from "./languages.js";
13
13
  export * from "./list.js";
14
14
  export * from "./migrate-config.js";
15
+ export * from "./monquery.js";
15
16
  export * from "./omit.js";
16
17
  export * from "./project-factory.js";
17
18
  export * from "./project.js";
@@ -0,0 +1,3 @@
1
+ export function compile(node: any): any;
2
+ export function parse(input: any): any;
3
+ export default function monquery(input: any): any;
Binary file