imdone-core 1.46.2 → 1.47.1

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/.imdoneignore CHANGED
@@ -8,3 +8,4 @@ tmp
8
8
  imdone-export.json
9
9
  .imdone/templates
10
10
  .imdone
11
+ notes/archive
@@ -1,5 +1,5 @@
1
1
  const FileProjectContext = require('./domain/entities/FileProjectContext')
2
- const { isNumber } = require('./task')
2
+ const { isNumber } = require('./adapters/parsers/task/CardContentParser')
3
3
 
4
4
  module.exports = class ProjectContext extends FileProjectContext {
5
5
  constructor(repo) {
@@ -44,8 +44,8 @@ module.exports = {
44
44
  return fs.promises.writeFile.apply({}, args)
45
45
  },
46
46
 
47
- readdir(...args) {
48
- return fs.readdir.apply({}, args)
47
+ async readdir(...args) {
48
+ return fs.promises.readdir.apply({}, args)
49
49
  },
50
50
 
51
51
  unlinkSync(...args) {
@@ -2,7 +2,6 @@ const { createReadStream } = require('fs')
2
2
  const ReadStreamMarkdownParser = require('./ReadStreamMarkdownParser')
3
3
  const path = require('path')
4
4
  const languages = require('../../../languages')
5
- const appContext = require('../../../context/ApplicationContext')
6
5
  const ReadStreamCodeParser = require('./ReadStreamCodeParser')
7
6
 
8
7
  function getLang(languages, filePath) {
@@ -15,21 +14,27 @@ function getLanguages(config) {
15
14
  return { ...languages, ...configLanguages }
16
15
  }
17
16
 
18
- module.exports = {
19
- async getFileParser(filePath) {
20
- const { config } = appContext()
21
- const languages = getLanguages(config)
22
- const lang = getLang(languages, filePath)
23
- if (lang.name === 'text') {
24
- return new ReadStreamMarkdownParser(createReadStream(filePath))
25
- } else {
26
- const parser = new ReadStreamCodeParser(
27
- createReadStream(filePath),
28
- filePath,
29
- lang
30
- )
31
- await parser.init()
32
- return parser
33
- }
34
- },
17
+ // DOING Use task line parsers for vs code extension and obsidian plugin
18
+ // <!--
19
+ // order:-10000030
20
+ // -->
21
+
22
+ module.exports.getFileParser = async function getFileParser (filePath, config, readStream) {
23
+ if (!readStream) {
24
+ readStream = createReadStream(filePath)
25
+ }
26
+ const languages = getLanguages(config)
27
+ const lang = getLang(languages, filePath)
28
+ if (lang.name === 'text') {
29
+ return new ReadStreamMarkdownParser(readStream, config)
30
+ } else {
31
+ const parser = new ReadStreamCodeParser(
32
+ readStream,
33
+ filePath,
34
+ lang,
35
+ config.lists
36
+ )
37
+ await parser.init()
38
+ return parser
39
+ }
35
40
  }
@@ -1,121 +1,114 @@
1
1
  const path = require('path')
2
2
  const ReadStreamTaskParser = require('./ReadStreamTaskParser')
3
3
  const CodeStyleTaskParser = require('../task/CodeStyleTaskParser')
4
+ const languages = require('../../../languages')
4
5
  const extractComments = require('multilang-extract-comments')
5
6
  const eol = require('eol')
6
- const ReadLine = require('readline')
7
7
  const { Readable } = require('stream')
8
8
 
9
- async function streamToString(stream) {
10
- const chunks = []
11
-
12
- for await (const chunk of stream) {
13
- chunks.push(Buffer.from(chunk))
14
- }
15
-
16
- return Buffer.concat(chunks).toString('utf-8')
17
- }
18
-
19
- function stringToStream(string) {
20
- const lines = eol.split(string).map((line) => line + String(eol.auto))
21
- return Readable.from(lines)
22
- }
23
-
24
9
  module.exports = class ReadStreamCodeParser extends ReadStreamTaskParser {
25
- constructor(readStream, filePath, lang) {
10
+ constructor(readStream, filePath, lang, lists) {
26
11
  super(readStream)
12
+ this.lists = lists
27
13
  this.filePath = filePath
28
14
  this.lang = lang
29
15
  this.taskParsers = [new CodeStyleTaskParser()]
30
16
  }
31
17
 
32
18
  async init() {
33
- const content = await streamToString(this.readStream)
34
- this.comments = await this.extractComments(content)
35
- this.readStream = stringToStream(content)
36
- this.readInterface = this.getReadInterface()
37
-
38
- let line = null
39
- let lines = []
40
- let lineNo = 1
41
- let comment = null
42
- do {
43
- const { value, done } = await this.readLine()
44
- line = done ? null : value
45
- comment = this.getCommentAtLine(lineNo)
46
- let lineInComment = ''
47
- if (comment) {
48
- lineInComment = comment.lines[lineNo - comment.begin]
49
- }
50
- lines.push(lineInComment)
51
- lineNo += 1
52
- } while (line !== null)
53
- this.readInterface.close()
54
- this.readStream = Readable.from(
55
- lines.map((line) => line + String(eol.auto))
56
- )
57
- this.readInterface = this.getReadInterface()
19
+ const code = await streamToString(this.readStream)
20
+ // TODO Getting tokens from lists should be done higher up in the controller
21
+ const tokens = this.lists.filter(list => !list.filter).map(list => list.name)
22
+ this.cards = this.parseCards(code, tokens)
58
23
  }
59
24
 
60
25
  async readTask() {
61
- const task = await super.readTask()
62
- task.multiLineComment =
63
- this.getCommentAtLine(task.line).info.type === 'multiline'
64
- task.descriptionStartsWith = task.multiLineComment
65
- ? this.lang.block.ignore
66
- : this.lang.symbol
67
-
68
- return task
26
+ return this.cards.shift()
69
27
  }
70
28
 
71
- getCommentAtLine(lineNo) {
72
- return this.comments.find(
73
- (comment) => lineNo >= comment.begin && lineNo <= comment.end
74
- )
29
+ parseCards(code, tokens = ['TODO']) {
30
+ const comments = this.parseComments(code);
31
+ const cards = [];
32
+
33
+ Object.keys(comments).forEach((comment) => {
34
+ const { begin, end, content } = comments[comment];
35
+ const line = begin;
36
+ const lastLine = end - 1;
37
+ const lines = content.split('\n');
38
+
39
+ // Check if the comment contains "TODO"
40
+ lines.forEach(codeLine => {
41
+ if (tokens.find((token) => codeLine.includes(token))) {
42
+ // Get all lines from start to end
43
+
44
+ cards.push({
45
+ content,
46
+ line,
47
+ lastLine,
48
+ });
49
+ }
50
+ });
51
+ });
52
+ return cards;
75
53
  }
76
-
77
- getReadInterface() {
78
- return ReadLine.createInterface({
79
- input: this.readStream,
80
- crlfDelay: Infinity,
81
- console: false,
82
- })
54
+
55
+ parseComments(code) {
56
+ const options = getLanguageOptions(this.filePath);
57
+ const comments = extractComments(code, options);
58
+ return comments;
83
59
  }
60
+
61
+ }
84
62
 
85
- async extractComments(content) {
86
- const lang = this.lang
87
- const multiLineComment = lang.block
88
- ? [
89
- {
90
- start: lang.block.start,
91
- middle: lang.block.ignore,
92
- end: lang.block.end,
93
- },
94
- ]
95
- : []
96
- const options = {
97
- pattern: {
98
- name: lang.name,
99
- nameMatchers: [path.extname(this.filePath)],
100
- singleLineComment: [{ start: lang.symbol }],
101
- multiLineComment,
102
- },
103
- }
104
- const comments = extractComments(content, options)
105
- const contentLines = eol.split(content)
106
- return Object.values(comments).map((comment) => {
107
- const lines = eol.split(comment.content)
108
- const linesInContent = contentLines.slice(comment.begin - 1, comment.end)
109
- let contentStartIndex = linesInContent.findIndex((line) =>
110
- line.includes(lines[0])
111
- )
112
- for (let i = 0; i < contentStartIndex; i++) {
113
- lines.unshift('')
114
- }
115
- return {
116
- ...comment,
117
- lines,
63
+
64
+ function getLanguageOptions(filePath) {
65
+ const extension = path.extname(filePath)
66
+ const language = languages[extension]
67
+
68
+
69
+ const {
70
+ name,
71
+ symbol,
72
+ block,
73
+ } = language ||
74
+ {
75
+ name: 'text',
76
+ symbol: '',
77
+ block: {
78
+ start: undefined,
79
+ end: undefined,
80
+ ignore: undefined,
118
81
  }
119
- })
82
+ };
83
+ // Use lang to get comment patterns
84
+
85
+ const {
86
+ start,
87
+ ignore: middle,
88
+ end
89
+ } = block || {};
90
+
91
+ return language && {
92
+ pattern: {
93
+ name,
94
+ nameMatchers: extension && [extension] || [],
95
+ singleLineComment: symbol && [{ start: symbol }] || [],
96
+ multiLineComment: start && end && [{ start, middle, end }] || [],
97
+ },
98
+ };
99
+ }
100
+
101
+ async function streamToString(stream) {
102
+ const chunks = []
103
+
104
+ for await (const chunk of stream) {
105
+ chunks.push(Buffer.from(chunk))
120
106
  }
107
+
108
+ return Buffer.concat(chunks).toString('utf-8')
109
+ }
110
+
111
+ function stringToStream(string) {
112
+ const lines = eol.split(string).map((line) => line + String(eol.auto))
113
+ return Readable.from(lines)
121
114
  }
@@ -1,19 +1,17 @@
1
1
  const ReadStreamTaskParser = require('./ReadStreamTaskParser')
2
2
  const HashStyleTaskParser = require('../task/HashStyleTaskParser')
3
3
  const MarkdownStyleTaskParser = require('../task/MarkdownStyleTaskParser')
4
- const CheckStyleTaskParser = require('../task/CheckStyleTaskParser')
5
- const appContext = require('../../../context/ApplicationContext')
4
+ // const CheckStyleTaskParser = require('../task/CheckStyleTaskParser')
6
5
 
7
6
  module.exports = class ReadStreamMarkdownParser extends ReadStreamTaskParser {
8
- constructor(readStream) {
9
- super(readStream)
10
- const { config } = appContext()
7
+ constructor(readStream, config) {
8
+ super(readStream, config)
11
9
  this.taskParsers = [
12
- new HashStyleTaskParser(),
13
- new MarkdownStyleTaskParser(),
10
+ new HashStyleTaskParser(config),
11
+ new MarkdownStyleTaskParser(config),
14
12
  ]
15
- if (config.isAddCheckBoxTasks()) {
16
- this.taskParsers.push(new CheckStyleTaskParser())
17
- }
13
+ // if (config.isAddCheckBoxTasks()) {
14
+ // this.taskParsers.push(new CheckStyleTaskParser())
15
+ // }
18
16
  }
19
17
  }
@@ -1,19 +1,14 @@
1
- const appContext = require('../../../context/ApplicationContext')
2
- const Config = require('../../../config')
3
1
  const ReadLine = require('readline')
4
- const START_TAG = '<card>'
5
- const END_TAG = '</card>'
2
+ const blankLinesToEndTask = 2
6
3
 
7
4
  module.exports = class ReadStreamTaskParser {
8
5
  constructor(readStream) {
9
- this.config = appContext().config
10
6
  this.readStream = readStream
11
7
  this.task = null
12
8
  this.line = null
13
9
  this.taskParsers = []
14
10
  this.lineNo = 0
15
11
  this.blankLines = 0
16
- this.blankLinesToEndTask = this.config.blankLinesToEndTask
17
12
  this.readInterface = ReadLine.createInterface({
18
13
  input: this.readStream,
19
14
  crlfDelay: Infinity,
@@ -23,9 +18,8 @@ module.exports = class ReadStreamTaskParser {
23
18
 
24
19
  async readTask() {
25
20
  let taskOrStreamDone = false
26
- this.task = null
21
+ this.task = this.nextTask || null
27
22
  this.blankLines = 0
28
- this.hasStartTag = false
29
23
 
30
24
  try {
31
25
  while (!taskOrStreamDone) {
@@ -50,7 +44,7 @@ module.exports = class ReadStreamTaskParser {
50
44
  throw error
51
45
  }
52
46
 
53
- this.trimBlankLinesToEndTask()
47
+ this.trimLinesToEndTask()
54
48
  return this.task
55
49
  }
56
50
 
@@ -59,19 +53,24 @@ module.exports = class ReadStreamTaskParser {
59
53
  }
60
54
 
61
55
  isEndOfTask(line) {
62
- if (this.task && this.task.hasCardTags) return true
63
- if (this.hasStartTag) return false
64
-
65
56
  if (line.trim() === '') {
66
57
  this.blankLines++
67
58
  } else {
68
59
  this.blankLines = 0
69
60
  }
70
61
 
71
- return (
72
- this.getTaskFromLine(this.line.value) ||
73
- this.blankLines > this.blankLinesToEndTask - 1
74
- )
62
+ this.nextTask = this.getTaskFromLine(line)
63
+
64
+ if (this.blankLines > blankLinesToEndTask - 1) {
65
+ this.nextTask = undefined
66
+ return true
67
+ }
68
+
69
+ if (this.nextTask) {
70
+ return true
71
+ }
72
+
73
+ return false
75
74
  }
76
75
 
77
76
  getTaskFromLine(line) {
@@ -84,30 +83,23 @@ module.exports = class ReadStreamTaskParser {
84
83
  }
85
84
 
86
85
  addLineToTask(line) {
87
- if (line.trim() === START_TAG && this.task.description.length == 0) {
88
- this.hasStartTag = true
89
- } else if (line.trim() === END_TAG && this.hasStartTag) {
90
- this.task.hasCardTags = true
91
- } else {
92
- this.task.description.push(line)
93
- }
94
-
86
+ this.task.description.push(line)
95
87
  this.task.lastLine = this.lineNo
96
88
  }
97
89
 
98
- trimBlankLinesToEndTask() {
90
+ trimLinesToEndTask() {
99
91
  if (!this.task) return
100
92
  if (
101
- this.blankLines == this.blankLinesToEndTask &&
102
- this.blankLinesToEndTask > 1 &&
103
- !this.task.hasCardTags
93
+ this.blankLines == blankLinesToEndTask
104
94
  ) {
105
- this.task.description.splice(
106
- this.task.description.length - this.blankLines + 1,
107
- this.blankLinesToEndTask - 1
108
- )
109
- this.task.lastLine = this.task.lastLine - this.blankLines
95
+ this.task.description.length = this.task.description.length - (this.blankLines - 1)
96
+ } else if (this.nextTask){
97
+ this.task.description.length = this.task.description.length - (this.blankLines + 1)
98
+ } else {
99
+ this.task.description.length = this.task.description.length - this.blankLines
110
100
  }
101
+
102
+ this.task.lastLine = this.task.line + this.task.description.length - 1
111
103
  }
112
104
 
113
105
  close() {
@@ -5,24 +5,35 @@ const FILE_TYPES = {
5
5
  MARKDOWN: 'markdown',
6
6
  CODE: 'code',
7
7
  }
8
+ const TASK_TYPES = {
9
+ CODE: 'CODE',
10
+ HASHTAG: 'HASHTAG',
11
+ MARKDOWN: 'MARKDOWN',
12
+ }
8
13
 
14
+ const DEFAULT_TOKEN_PREFIX = '#'
9
15
  const START_TAG = '<card>'
10
16
  const END_TAG = '</card>'
11
17
  const CODE_STYLE_PATTERN = '([A-Z]+[A-Z-_]+?)((:)(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$'
12
18
  const LIST_NAME_PATTERN = '[\\p{L}0-9-_]{2,}' // [a-zA-Z-_]+?
13
- const HASH_STYLE_REGEX = new XRegExp(
14
- `#(${LIST_NAME_PATTERN})(:(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$`,
15
- 'gm'
16
- )
17
- const HASH_STYLE_META_ORDER_REGEX = new XRegExp(
18
- `#(${LIST_NAME_PATTERN})[ \\t]+(.+)$`, 'gm'
19
- )
20
19
  const LINK_STYLE_REGEX = new XRegExp(
21
20
  `(\\[.*\\]\\s?)?(\\[(.+)\\]\\(#(${LIST_NAME_PATTERN})(:)(-?[\\d.]+(?:e-?\\d+)?)?\\))`,
22
21
  'gm'
23
22
  )
24
23
 
25
24
  const CHECK_REGEX = /^(\s*- )\[([x ])\]/
25
+
26
+ function getHashStyleRegex(tokenPrefix = DEFAULT_TOKEN_PREFIX, orderMeta = false) {
27
+ return orderMeta ?
28
+ new XRegExp(
29
+ `${tokenPrefix}(${LIST_NAME_PATTERN})[ \\t]+(.+)$`, 'gm'
30
+ ) :
31
+ new XRegExp(
32
+ `${tokenPrefix}(${LIST_NAME_PATTERN})(:(-?[\\d.]+(?:e-?\\d+)?)?)?[ \\t]+(.+)$`,
33
+ 'gm'
34
+ )
35
+ }
36
+
26
37
  function getCheckedData(content) {
27
38
  const taskRegex = new RegExp(CHECK_REGEX)
28
39
  const result = taskRegex.exec(content)
@@ -65,10 +76,10 @@ function isCheckBoxTask (config, line, beforeText) {
65
76
  function hasTaskInText(config, text, isCodeFile) {
66
77
  return (
67
78
  (isCodeFile && hasCodeStyleTask(config, text)) ||
68
- ((new XRegExp(HASH_STYLE_REGEX).test(text) ||
69
- new XRegExp(HASH_STYLE_META_ORDER_REGEX).test(text) ||
79
+ ((new XRegExp(getHashStyleRegex(config.tokenPrefix)).test(text) ||
80
+ new XRegExp(getHashStyleRegex(config.tokenPrefix, true)).test(text) ||
70
81
  new XRegExp(LINK_STYLE_REGEX).test(text)) &&
71
- config.lists.find((list) => text.includes(`#${list.name}`)))
82
+ config.lists.find((list) => text.includes(`${config.tokenPrefix}${list.name}`)))
72
83
  )
73
84
  }
74
85
 
@@ -276,15 +287,34 @@ function getTaskContent ({
276
287
  getTextFileTaskContent({ config, content, beforeText, fileType })
277
288
  }
278
289
 
290
+ function getRawTask ({tokenPrefix = DEFAULT_TOKEN_PREFIX, orderMeta, beforeText = '', hasColon = false, list, order= '', text, type}) {
291
+ if (type === TASK_TYPES.MARKDOWN) {
292
+ return `${beforeText}[${text}](${tokenPrefix}${list}:${
293
+ orderMeta ? '' : order
294
+ })`
295
+ }
296
+ const colon = hasColon || (isNumber(order) && !orderMeta) ? ':' : '';
297
+ return `${beforeText}${tokenPrefix}${list}${colon}${
298
+ orderMeta ? '' : order
299
+ } ${text}`
300
+ }
301
+
302
+ function isNumber (value) {
303
+ return !isNaN(parseFloat(value)) && isFinite(value)
304
+ }
305
+
279
306
  module.exports = {
280
307
  FILE_TYPES,
308
+ TASK_TYPES,
281
309
  getTaskContent,
310
+ getRawTask,
282
311
  isBeforeTextMarkdownList,
283
312
  padDescription,
284
313
  getCheckedData,
314
+ hasTaskInText,
315
+ isNumber,
316
+ getHashStyleRegex,
285
317
  CHECK_REGEX,
286
318
  LIST_NAME_PATTERN,
287
- HASH_STYLE_REGEX,
288
- HASH_STYLE_META_ORDER_REGEX,
289
319
  LINK_STYLE_REGEX
290
320
  }
@@ -1,8 +1,8 @@
1
1
  const TaskParser = require('./TaskParser')
2
2
 
3
3
  module.exports = class CodeStyleTaskParser extends TaskParser {
4
- constructor() {
5
- super('CODE')
4
+ constructor(config) {
5
+ super('CODE', config)
6
6
  }
7
7
 
8
8
  get pattern() {
@@ -1,23 +1,26 @@
1
1
  const TaskParser = require('./TaskParser')
2
+ const { getHashStyleRegex } = require('./CardContentParser')
2
3
 
3
4
  module.exports = class HashStyleTaskParser extends TaskParser {
4
- constructor() {
5
- super('HASHTAG')
5
+ constructor(config) {
6
+ super('HASHTAG', config)
6
7
  }
7
8
 
8
9
  get pattern() {
9
- return /^(.*?)#([a-zA-Z-_]+?)((:)(-?[\d.]+(?:e-?\d+)?)?)?[ \t]+(.+)$/gm
10
+ const config = this.config
11
+ return getHashStyleRegex(config.tokenPrefix, config.orderMeta)
10
12
  }
11
13
 
12
14
  parse(lineContent, line, matchResult) {
13
- const [match, beforeText, list, orderGroup, colon, order, text] = matchResult
15
+ const [rawTask, list, orderGroup, order, text] = matchResult
16
+
14
17
  return {
15
- beforeText,
18
+ // beforeText,
16
19
  text,
17
20
  order,
18
21
  list,
19
22
  line,
20
- colon,
23
+ colon: orderGroup && orderGroup.startsWith(':'),
21
24
  type: this.type,
22
25
  }
23
26
  }
@@ -1,8 +1,8 @@
1
1
  const TaskParser = require('./TaskParser')
2
2
 
3
3
  module.exports = class MarkdownStyleTaskParser extends TaskParser {
4
- constructor() {
5
- super('MARKDOWN')
4
+ constructor(config) {
5
+ super('MARKDOWN', config)
6
6
  }
7
7
 
8
8
  get pattern() {
@@ -1,5 +1,3 @@
1
- const Config = require('../../../config')
2
- const appContext = require('../../../context/ApplicationContext')
3
1
 
4
2
  class Task {
5
3
  constructor({ beforeText, text, list, line, order, checked, colon, type }) {
@@ -17,8 +15,8 @@ class Task {
17
15
  }
18
16
 
19
17
  module.exports = class TaskParser {
20
- constructor(type) {
21
- this.config = appContext().config
18
+ constructor(type, config) {
19
+ this.config = config
22
20
  this.type = type
23
21
  }
24
22
 
package/lib/config.js CHANGED
@@ -3,7 +3,19 @@
3
3
  const _cloneDeep = require('lodash.clonedeep')
4
4
  const _assign = require('lodash.assign')
5
5
  const _get = require('lodash.get')
6
- const { JOURNAL_TYPE, DEFAULT_CONFIG } = require('./constants')
6
+ const {
7
+ JOURNAL_TYPE,
8
+ DEFAULT_CONFIG,
9
+ CONFIG_FILE_YML,
10
+ CONFIG_DIR
11
+ } = require('./constants')
12
+ const _path = require('path')
13
+ const findUp = require('find-up')
14
+ const { loadYAML } = require('./adapters/yaml')
15
+ const {
16
+ exists,
17
+ readFile,
18
+ } = require('./adapters/file-gateway')
7
19
 
8
20
  /**
9
21
  * Description
@@ -187,20 +199,12 @@ class Config {
187
199
  return _get(this, 'settings.cards.archiveCompleted', false)
188
200
  }
189
201
 
190
- get doneList() {
191
- return this.getDoneList()
202
+ get tokenPrefix() {
203
+ return _get(this, 'settings.cards.tokenPrefix', '#')
192
204
  }
193
205
 
194
- get blankLinesToEndTask() {
195
- let blankLinesToEndTask = Math.round(
196
- _get(this, 'settings.cards.blankLinesToEndTask', 1)
197
- )
198
- if (blankLinesToEndTask > 2) {
199
- blankLinesToEndTask = 2
200
- } else if (blankLinesToEndTask < 1) {
201
- blankLinesToEndTask = 1
202
- }
203
- return blankLinesToEndTask
206
+ get doneList() {
207
+ return this.getDoneList()
204
208
  }
205
209
 
206
210
  getMetaSep() {
@@ -209,5 +213,37 @@ class Config {
209
213
  }
210
214
  }
211
215
 
212
- Config.newDefaultConfig = (config = {}) => new Config({...DEFAULT_CONFIG, lists: [...DEFAULT_CONFIG.lists], ...config})
216
+ Config.newDefaultConfig = (config = {}) => new Config(
217
+ {
218
+ ...DEFAULT_CONFIG,
219
+ lists: [
220
+ ...DEFAULT_CONFIG.lists
221
+ ],
222
+ ...config
223
+ }
224
+ )
225
+
226
+ Config.findImdonePath = async (cwd) => {
227
+ const configDir = await findUp(CONFIG_DIR, { cwd, type: 'directory' })
228
+ return _path.dirname(configDir)
229
+ }
230
+
231
+ Config.getYamlConfig = async (filePath) => {
232
+ if (!(await exists(filePath))) return
233
+ const configData = await readFile(filePath, 'utf-8')
234
+ let configLike = {}
235
+ try {
236
+ configLike = loadYAML(configData.toString())
237
+ } catch (e) {
238
+ /* noop */
239
+ }
240
+ return configLike
241
+ }
242
+
243
+ Config.load = async (imdonePath) => {
244
+ const configPath = _path.join(imdonePath, CONFIG_FILE_YML)
245
+ const configLike = await Config.getYamlConfig(configPath)
246
+ return new Config(configLike)
247
+ }
248
+
213
249
  module.exports = Config
@@ -0,0 +1,31 @@
1
+ const Config = require('../config')
2
+
3
+ class ApplicationContext {
4
+ constructor({
5
+ project,
6
+ repo,
7
+ projectContext,
8
+ projectReader,
9
+ projectPresenter,
10
+ }) {
11
+ this.project = project;
12
+ this.repo = repo;
13
+ this.projectContext = projectContext;
14
+ this.projectReader = projectReader;
15
+ this.projectPresenter = projectPresenter;
16
+ this.innerConfig = Config.newDefaultConfig()
17
+ }
18
+
19
+ set config(config) {
20
+ this.innerConfig = config
21
+ this.repo && (this.repo.config = config)
22
+ }
23
+
24
+ get config() {
25
+ return (this.repo && this.repo.config) || this.innerConfig
26
+ }
27
+
28
+ }
29
+ const context = new ApplicationContext({})
30
+
31
+ module.exports = () => context
@@ -21,6 +21,7 @@ cards:
21
21
  addCompletedMeta: false #override
22
22
  addCheckBoxTasks: false #override
23
23
  doneList: DONE #override if
24
+ tokenPrefix: '#' #override
24
25
  taskPrefix: '##' #override
25
26
  tagPrefix: '+' #override
26
27
  metaSep: ':' #override
package/lib/file.js CHANGED
@@ -24,14 +24,14 @@ var _clone = require('lodash.clone'),
24
24
  {
25
25
  FILE_TYPES,
26
26
  getTaskContent,
27
+ getRawTask,
28
+ getHashStyleRegex,
29
+ hasTaskInText,
27
30
  LIST_NAME_PATTERN,
28
- HASH_STYLE_REGEX,
29
- HASH_STYLE_META_ORDER_REGEX,
30
31
  LINK_STYLE_REGEX,
31
32
  } = require('./adapters/parsers/task/CardContentParser')
32
33
 
33
34
  const appContext = require('./context/ApplicationContext')
34
- const { isNumber } = require('./task')
35
35
  const { hasBlankLines } = require('./tools')
36
36
 
37
37
  const ERRORS = {
@@ -296,6 +296,11 @@ File.prototype.transformTasks = function (config, modify) {
296
296
  .forEach(task => this.transformTask({config, modify, task}))
297
297
  }
298
298
 
299
+ // TODO Blank lines should be allowed in code tasks
300
+ // #imdone-1.47.0
301
+ // <!--
302
+ // order:-120
303
+ // -->
299
304
  File.prototype.extractCodeStyleTasks = function (config, pos, content) {
300
305
  var self = this
301
306
  var codeStyleRegex = new RegExp(CODE_STYLE_PATTERN, 'gm')
@@ -346,7 +351,7 @@ File.prototype.extractCodeStyleTasks = function (config, pos, content) {
346
351
  }
347
352
 
348
353
  File.prototype.extractHashStyleTasks = function (config, pos, content) {
349
- var hashStyleRegex = new XRegExp(HASH_STYLE_REGEX)
354
+ var hashStyleRegex = getHashStyleRegex(config.tokenPrefix)
350
355
  var lang = this.getLang()
351
356
  var result
352
357
  while ((result = hashStyleRegex.exec(content)) !== null) {
@@ -449,7 +454,7 @@ File.prototype.extractCheckboxTasks = function (config, pos, content) {
449
454
  content: content.substring(result.index),
450
455
  pos: posInContent,
451
456
  })
452
- task.rawTask = File.getRawTask(type, text, list, task.order)
457
+ task.rawTask = getRawTask({tokenPrefix: config.tokenPrefix, orderMeta: config.orderMeta, list, text, type})
453
458
  tasks.push(task)
454
459
  }
455
460
  if (tasks) {
@@ -484,17 +489,6 @@ File.prototype.extractCheckboxTasks = function (config, pos, content) {
484
489
  }
485
490
  }
486
491
 
487
- File.getRawTask = function (type, text, list, order) {
488
- const TYPES = Task.Types
489
- if (type === TYPES.MARKDOWN) {
490
- return `[${text}](#${list}:${order})`
491
- } else if (appContext().repo.config.orderMeta) {
492
- return `#${list} ${text}`
493
- }
494
-
495
- return `#${list}:${order} ${text}`
496
- }
497
-
498
492
  File.prototype.extractTasks = function (config) {
499
493
  this.tasks = []
500
494
  if (this.isMarkDownFile()) {
@@ -628,7 +622,7 @@ File.prototype.deleteTask = function (task, config) {
628
622
  config
629
623
  )
630
624
  } else if (task.type === Task.Types.HASHTAG) {
631
- this.deleteCodeOrHashTask(HASH_STYLE_REGEX, task, config)
625
+ this.deleteCodeOrHashTask(getHashStyleRegex(config.tokenPrefix), task, config)
632
626
  }
633
627
  } else {
634
628
  const fileContent = this.getContentLines()
@@ -643,19 +637,6 @@ File.prototype.deleteTask = function (task, config) {
643
637
  }
644
638
  }
645
639
 
646
- File.TASK_TYPE_TEMPLATES = {
647
- HASHTAG: (t, config) => {
648
- const colon = t.hasColon || (isNumber(t.order) && !config.orderMeta) ? ':' : '';
649
- return `${t.beforeText || ''}#${t.list}${colon}${
650
- config.orderMeta ? '' : t.order
651
- } ${t.text}`;
652
- },
653
- MARKDOWN: (t, config) =>
654
- `${t.beforeText || ''}[${t.text}](#${t.list}:${
655
- config.orderMeta ? '' : t.order
656
- })`,
657
- }
658
-
659
640
  File.prototype.modifyTask = function (task, config, noEmit) {
660
641
  task.orderModified = true
661
642
  task.updateOrderMeta(config)
@@ -669,7 +650,16 @@ File.prototype.modifyTask = function (task, config, noEmit) {
669
650
  } else {
670
651
  task.updateContent()
671
652
  const fileContent = this.getContentLines()
672
- let text = File.TASK_TYPE_TEMPLATES[task.type](task, config)
653
+ let text = getRawTask({
654
+ tokenPrefix: config.tokenPrefix,
655
+ orderMeta: config.orderMeta,
656
+ beforeText: task.beforeText,
657
+ hasColon: task.hasColon,
658
+ list: task.list,
659
+ order: task.order,
660
+ text: task.text,
661
+ type: task.type,
662
+ })
673
663
  const linesBefore = fileContent.slice(0, task.line - 1)
674
664
  if (this.isCodeFile()) {
675
665
  const linesBeforeLength = linesBefore.join(lineEnd).length
@@ -741,9 +731,8 @@ File.prototype.modifyCodeOrHashTask = function (re, task, config, noEmit) {
741
731
  } else text = task.text
742
732
  } else text = task.text
743
733
  if (/[a-z]/.test(task.list)) task.type = Task.Types.HASHTAG
744
- const hash = task.type === Task.Types.HASHTAG ? '#' : ''
745
- const inLineOrder = task.hasColon && !config.orderMeta ? `:${task.order}` : ''
746
- var taskContent = `${task.beforeText || ''}${hash}${task.list}${inLineOrder} ${text}`
734
+ const tokenPrefix = task.type === Task.Types.HASHTAG ? config.tokenPrefix : ''
735
+ var taskContent = getRawTask({tokenPrefix, orderMeta: config.orderMeta, list: task.list, order: task.order, text, type: task.type})
747
736
  task.line = this.getLineNumber(index)
748
737
  task.id = getTaskId(self.getPath(), task.line, task.text)
749
738
  this.setContent(beforeContent + taskContent + afterContent)
@@ -1111,19 +1100,20 @@ File.prototype.removeTask = function (task) {
1111
1100
 
1112
1101
  File.prototype.ignoreCodeBlocks = function () {
1113
1102
  // BACKLOG:-100 This is not used, but we need a way to ignore tasks in code blocks. Maybe save position ranges
1114
- var cleanContent = this.content
1115
- var replacer = function (block) {
1116
- block = block.replace(new XRegExp(LINK_STYLE_REGEX), '**TASK**')
1117
- block = block.replace(new XRegExp(HASH_STYLE_REGEX), '**TASK**')
1118
- return block
1119
- }
1120
-
1121
- if (this.isMarkDownFile()) {
1122
- cleanContent = this.content
1123
- .replace(new RegExp(CODE_BLOCK_REGEX), replacer)
1124
- .replace(new RegExp(INLINE_CODE_REGEX), replacer)
1125
- }
1126
- return cleanContent
1103
+ // ```javascript
1104
+ // var cleanContent = this.content
1105
+ // var replacer = function (block) {
1106
+ // block = block.replace(new XRegExp(LINK_STYLE_REGEX), '**TASK**')
1107
+ // block = block.replace(getHashStyleRegex(config.tokenPrefix), '**TASK**')
1108
+ // return block
1109
+ // }
1110
+ // if (this.isMarkDownFile()) {
1111
+ // cleanContent = this.content
1112
+ // .replace(new RegExp(CODE_BLOCK_REGEX), replacer)
1113
+ // .replace(new RegExp(INLINE_CODE_REGEX), replacer)
1114
+ // }
1115
+ // return cleanContent
1116
+ // ```
1127
1117
  }
1128
1118
 
1129
1119
  File.prototype.isMarkDownFile = function () {
@@ -1261,13 +1251,7 @@ File.prototype.hasCodeStyleTask = function (config, text) {
1261
1251
  }
1262
1252
 
1263
1253
  File.prototype.hasTaskInText = function (config, text) {
1264
- return (
1265
- this.hasCodeStyleTask(config, text) ||
1266
- ((new XRegExp(HASH_STYLE_REGEX).test(text) ||
1267
- new XRegExp(HASH_STYLE_META_ORDER_REGEX).test(text) ||
1268
- new XRegExp(LINK_STYLE_REGEX).test(text)) &&
1269
- config.lists.find((list) => text.includes(`#${list.name}`)))
1270
- )
1254
+ return hasTaskInText(config, text, this.isCodeFile())
1271
1255
  }
1272
1256
 
1273
1257
  File.prototype.isInBlockComment = function (content) {
@@ -255,7 +255,7 @@ function mixin(repo, fs = require('fs')) {
255
255
  cb = tools.cb(cb)
256
256
  repo.loadIgnore()
257
257
  // new
258
- let configData = this.getYamlConfig() || this.getJsonConfig() || {}
258
+ let configData = this.getYamlConfig() || {}
259
259
  repo.updateConfig(configData, cb)
260
260
  }
261
261
 
@@ -263,21 +263,6 @@ function mixin(repo, fs = require('fs')) {
263
263
  return repo.getFullPath(CONFIG_FILE)
264
264
  }
265
265
 
266
- repo.getJsonConfig = function () {
267
- const filePath = repo.getFullPath(CONFIG_FILE)
268
- if (!fs.existsSync(filePath)) return
269
- const configData = fs.readFileSync(filePath)
270
- let configLike = {}
271
- try {
272
- configLike = JSON.parse(configData.toString())
273
- if (configLike.exclude) delete configLike.exclude
274
- if (configLike.watcher) delete configLike.watcher
275
- } catch (e) {
276
- /* noop */
277
- }
278
- return configLike
279
- }
280
-
281
266
  repo.getYamlConfig = function () {
282
267
  const filePath = repo.getFullPath(CONFIG_FILE_YML)
283
268
  if (!fs.existsSync(filePath)) return
@@ -52,7 +52,12 @@ module.exports = class ArchivePlugin extends Plugin {
52
52
  ],
53
53
  task.content
54
54
  )
55
- const taskContent = `${task.beforeText}#${task.list} ${content}\n\n\n`
55
+ // TODO This should use the CardContentParser to get the raw task
56
+ // <!--
57
+ // #imdone-1.47.0
58
+ // order:-110
59
+ // -->
60
+ const taskContent = `${task.beforeText}${config.tokenPrefix}${task.list} ${content}\n\n\n`
56
61
 
57
62
  this.fileGateway.preparePathForWriting(newPath)
58
63
  this.fileGateway.appendFileSync(newPath, taskContent)
@@ -95,48 +95,47 @@ module.exports = class PluginManager extends Emitter {
95
95
  const installPath = _path.join(this.pluginPath, name)
96
96
  await downloadRepo(version, installPath)
97
97
  console.log(`Done installing ${name}`)
98
- this.loadPlugin(installPath)
98
+ await this.loadPlugin(installPath)
99
99
  this.emit('plugin-installed', name)
100
100
  }
101
101
 
102
102
  async loadPlugins() {
103
- return new Promise((resolve, reject) => {
104
- this.defaultPlugins.forEach((pluginPath) => this.loadPlugin(pluginPath))
105
-
106
- this.exists(this.pluginPath).then((path) => {
107
- if (!path) return resolve()
108
- fs.readdir(this.pluginPath, { withFileTypes: true }, (err, paths) => {
109
- if (err) return reject(err)
110
- paths
111
- .filter(
112
- (entry) =>
113
- entry.name !== 'node_modules' &&
114
- (entry.isDirectory() || entry.isSymbolicLink())
115
- )
116
- .map((entry) => _path.join(this.pluginPath, entry.name))
117
- .forEach((path) => {
118
- this.loadPlugin(path)
119
- })
120
- resolve()
121
- })
122
- })
123
- })
124
- }
103
+ for (const pluginPath of this.defaultPlugins) {
104
+ await this.loadPlugin(pluginPath)
105
+ }
125
106
 
126
- loadPlugin(path) {
107
+ const path = await this.exists(this.pluginPath)
108
+ if (!path) return
109
+ const paths = await fs.promises.readdir(this.pluginPath, { withFileTypes: true })
110
+ const pluginPaths = paths
111
+ .filter(
112
+ (entry) =>
113
+ entry.name !== 'node_modules' &&
114
+ (entry.isDirectory() || entry.isSymbolicLink())
115
+ )
116
+ .map((entry) => _path.join(this.pluginPath, entry.name))
117
+
118
+ for (const path of pluginPaths) {
119
+ await this.loadPlugin(path)
120
+ }
121
+
122
+ }
123
+
124
+ async loadPlugin(path) {
127
125
  console.log('Loading plugin: ', path)
128
126
  try {
129
127
  // eslint-disable-next-line
130
128
  delete require.cache[require.resolve(path)]
131
129
  // eslint-disable-next-line
132
130
  const pluginClass = require(path)
133
- this.createPlugin(pluginClass, path)
131
+ const pluginInstance = await this.createPlugin(pluginClass, path)
132
+ if (pluginInstance.init) await pluginInstance.init()
134
133
  } catch (e) {
135
134
  console.error(`Error loading plugin at: ${path}`, e)
136
135
  }
137
136
  }
138
137
 
139
- createPlugin(pluginClass, path) {
138
+ async createPlugin(pluginClass, path) {
140
139
  if (!this.isPlugin(pluginClass))
141
140
  throw new Error(`${pluginClass.name} is not a plugin`)
142
141
  const name = pluginClass.name.toString()
@@ -164,6 +163,8 @@ module.exports = class PluginManager extends Emitter {
164
163
  pluginClass,
165
164
  info,
166
165
  }
166
+
167
+ return pluginInstance
167
168
  }
168
169
 
169
170
  destroyPlugins() {
@@ -268,6 +269,16 @@ module.exports = class PluginManager extends Emitter {
268
269
  })
269
270
  }
270
271
 
272
+ async onTaskFound(task) {
273
+ await this.eachPluginAsync(async ({ pluginInstance }) => {
274
+ try {
275
+ if (pluginInstance.onTaskFound) await pluginInstance.onTaskFound(task)
276
+ } catch (e) {
277
+ this.pluginError('onTaskFound', pluginInstance, e)
278
+ }
279
+ })
280
+ }
281
+
271
282
  async onBeforeAddTask({path, list, content, tags, contexts, meta, useCardTemplate}) {
272
283
  await this.eachPluginAsync(async ({ pluginInstance }) => {
273
284
  try {
package/lib/project.js CHANGED
@@ -62,6 +62,8 @@ module.exports = class WorkerProject extends Project {
62
62
  this.repo.on(event, (data) => onChange(this, event, data))
63
63
  })
64
64
 
65
+ this.repo.on('task.found', (task) => this.pluginManager.onTaskFound(task))
66
+
65
67
  const promise = new Promise((resolve, reject) => {
66
68
  this.repo.init((err, files) => {
67
69
  if (err) {
package/lib/repository.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { isNumber } = require('./task')
4
-
5
3
  var _get = require('lodash.get'),
6
4
  _isObject = require('lodash.isobject'),
7
5
  _isFunction = require('lodash.isfunction'),
@@ -37,9 +35,12 @@ var _get = require('lodash.get'),
37
35
  functionRegex = require('function-regex'),
38
36
  Task = require('./task'),
39
37
  newCard = require('./card'),
40
- { replaceDateLanguage } = require('./adapters/parsers/DateLanguageParser')
38
+ { replaceDateLanguage } = require('./adapters/parsers/DateLanguageParser'),
39
+ { getRawTask, isNumber } = require('./adapters/parsers/task/CardContentParser')
40
+
41
41
 
42
42
  const appContext = require('./context/ApplicationContext')
43
+ const get = require('lodash.get')
43
44
 
44
45
  var ERRORS = constants.ERRORS,
45
46
  DEFAULT_FILE_PATTERN = constants.DEFAULT_FILE_PATTERN,
@@ -1100,8 +1101,8 @@ Repository.prototype.appendTask = function({file, content, list}, cb) {
1100
1101
  const description =
1101
1102
  lines.length > 1 ? Task.padDescription(lines.slice(1), taskPrefix) : []
1102
1103
 
1103
- let appendContent
1104
- const taskContent = config.orderMeta
1104
+ const rawTask = getRawTask({tokenPrefix: config.tokenPrefix, orderMeta: config.orderMeta, list, order, text, type: taskSyntax})
1105
+ const taskContent = config.orderMeta
1105
1106
  ? this.getTaskContent({
1106
1107
  description,
1107
1108
  order,
@@ -1111,18 +1112,14 @@ Repository.prototype.appendTask = function({file, content, list}, cb) {
1111
1112
  })
1112
1113
  : description.join(eol.lf)
1113
1114
 
1114
- if (taskSyntax === Task.Types.MARKDOWN) {
1115
- appendContent = `${taskPrefix}[${text}](#${list}:${
1116
- config.orderMeta ? '' : orderString
1117
- })${eol.lf}${taskContent}`
1118
- } else {
1119
- const inLineOrder = config.orderMeta ? '' : `:${orderString}`
1120
- appendContent = `${taskPrefix}#${list}${inLineOrder} ${text}${eol.lf}${taskContent}`
1121
- }
1122
- appendContent = File.trimBlankLines(appendContent)
1115
+ let appendContent = File.trimBlankLines(
1116
+ `${taskPrefix}${rawTask}${eol.lf}${taskContent}`
1117
+ )
1118
+
1123
1119
  fileContent = `${fileContent}${sep}`
1124
1120
  const cardTerminator = "\n".repeat(2)
1125
1121
  file.setContent(`${fileContent}${appendContent}${cardTerminator}`)
1122
+
1126
1123
  this.writeAndExtract(file, true, (err, file) => {
1127
1124
  if (err) return cb(err)
1128
1125
  const task = file.getTasks().find(task => task.text === text && task.list === list)
@@ -1541,7 +1538,7 @@ Repository.prototype.getTasksInList = function (name, offset, limit) {
1541
1538
  var tasks = _where(this.getTasks(), { list: name })
1542
1539
  if (tasks.length === 0) return []
1543
1540
  var allTasks = fastSort(tasks).by(DEFAULT_SORT)
1544
- if (Task.isNumber(offset) && Task.isNumber(limit))
1541
+ if (isNumber(offset) && isNumber(limit))
1545
1542
  return allTasks.slice(offset, offset + limit)
1546
1543
  return allTasks
1547
1544
  }
package/lib/task.js CHANGED
@@ -16,8 +16,10 @@ var _clone = require('lodash.clone'),
16
16
 
17
17
  const {
18
18
  CHECK_REGEX,
19
+ TASK_TYPES,
19
20
  getCheckedData,
20
- isBeforeTextMarkdownList
21
+ isBeforeTextMarkdownList,
22
+ isNumber
21
23
  } = require('./adapters/parsers/task/CardContentParser.js')
22
24
 
23
25
  /**
@@ -234,11 +236,7 @@ Task.prototype.getCheckedData = function () {
234
236
  return getCheckedData(this.beforeText)
235
237
  }
236
238
 
237
- Task.Types = {
238
- CODE: 'CODE',
239
- HASHTAG: 'HASHTAG',
240
- MARKDOWN: 'MARKDOWN',
241
- }
239
+ Task.Types = TASK_TYPES
242
240
 
243
241
  Task.AnyLanguageGroup =
244
242
  '#\\w:%/.$-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC'
@@ -422,7 +420,7 @@ Task.getMetaOrderRegex = function (config) {
422
420
 
423
421
  Task.prototype.updateOrderMeta = function (config, descContent = this.description.join(lineEnd)) {
424
422
  if (config.orderMeta) {
425
- if (!Task.isNumber(this.order)) return this.order = ''
423
+ if (!isNumber(this.order)) return this.order = ''
426
424
  const addNewLine = config.isMetaNewLine()
427
425
  const metaSep = config.getMetaSep()
428
426
  if (this.meta.order) {
@@ -778,8 +776,4 @@ Task.prototype.equals = function (task) {
778
776
  )
779
777
  }
780
778
 
781
- Task.isNumber = function(n) {
782
- return !isNaN(parseFloat(n)) && isFinite(n);
783
- }
784
-
785
779
  module.exports = Task
@@ -0,0 +1,31 @@
1
+ const Config = require('../config')
2
+ const { getFileParser } = require('../adapters/parsers/file/LocalFileParserFactory')
3
+ const { Readable } = require('stream');
4
+
5
+ // DOING Use task line parsers for vs code extension and obsidian plugin
6
+ // <!--
7
+ // order:-10000030
8
+ // -->
9
+ export async function getTasks({filePath, content}) {
10
+ const projectPath = await Config.findImdonePath(filePath)
11
+ const config = await Config.load(projectPath)
12
+
13
+ // create a readstream from the content and pass it to getFileParser
14
+ const readStream = new Readable({
15
+ read() {
16
+ this.push(content);
17
+ this.push(null); // Signals the end of the stream
18
+ }
19
+ });
20
+
21
+ const parser = await getFileParser(filePath, config, readStream)
22
+
23
+ const tasks = []
24
+ let task = true
25
+ while (task) {
26
+ task = await parser.readTask()
27
+ if (task) tasks.push(task)
28
+ }
29
+ parser.close()
30
+ return tasks
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imdone-core",
3
- "version": "1.46.2",
3
+ "version": "1.47.1",
4
4
  "description": "imdone-core",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -56,10 +56,11 @@
56
56
  "eol": "^0.9.1",
57
57
  "escape-string-regexp": "^1.0.5",
58
58
  "fast-sort": "^2.2.0",
59
+ "find-up": "^5.0.0",
59
60
  "function-regex": "^1.0.2",
60
61
  "gray-matter": "^4.0.2",
61
62
  "ignore": "^5.2.0",
62
- "imdone-api": "^0.0.19",
63
+ "imdone-api": "^1.47.0",
63
64
  "isbinaryfile": "^3.0.2",
64
65
  "js-yaml": "^3.14.1",
65
66
  "json-fns": "^1.0.0",
@@ -98,6 +99,7 @@
98
99
  "multilang-extract-comments": "^0.4.0",
99
100
  "open": "^9.1.0",
100
101
  "ora": "^5.4.1",
102
+ "parse-code-context": "^1.0.0",
101
103
  "prompts": "^2.4.2",
102
104
  "readdirp": "^3.6.0",
103
105
  "remove-markdown": "^0.3.0",
package/tasks.md DELETED
@@ -1,21 +0,0 @@
1
- backlog
2
- ====
3
-
4
- ## Ungrouped Tasks
5
-
6
- ## Phase 1
7
-
8
- ### TODO
9
-
10
- - [ ] Another new task in a new file
11
- <!-- +urgent +important @piascikj group:"Phase 1" -->
12
- <!-- created:2023-09-02T03:48:18.338Z sid: -->
13
-
14
- ## Phase 2
15
-
16
- ### DOING
17
-
18
- - [ ] Another new task in a new files
19
- <!-- +urgent +important @piascikj group:"Phase 2" -->
20
- <!-- created:2023-09-02T04:02:09.680Z sid: -->
21
-