imdone-core 1.54.10 → 2.0.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.
Files changed (71) hide show
  1. package/README.md +2 -2
  2. package/lib/cli.js +114 -0
  3. package/lib/index.js +23 -0
  4. package/package.json +48 -66
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
  6. package/.github/workflows/ci.yml +0 -24
  7. package/.imdoneignore +0 -12
  8. package/.mocharc.json +0 -10
  9. package/.prettierrc +0 -6
  10. package/CHANGELOG.md +0 -160
  11. package/_navbar.md +0 -1
  12. package/cli.js +0 -74
  13. package/index-markdown.js +0 -55
  14. package/index.html +0 -184
  15. package/index.js +0 -1
  16. package/lib/ProjectContext.js +0 -42
  17. package/lib/adapters/date-time.js +0 -20
  18. package/lib/adapters/file-gateway.js +0 -127
  19. package/lib/adapters/git-download.js +0 -35
  20. package/lib/adapters/markdown.js +0 -168
  21. package/lib/adapters/parsers/DateLanguageParser.js +0 -10
  22. package/lib/adapters/parsers/content-transformer.js +0 -111
  23. package/lib/adapters/parsers/file/LocalFileParserFactory.js +0 -37
  24. package/lib/adapters/parsers/file/ReadStreamCodeParser.js +0 -126
  25. package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +0 -17
  26. package/lib/adapters/parsers/file/ReadStreamTaskParser.js +0 -104
  27. package/lib/adapters/parsers/function-parser.js +0 -29
  28. package/lib/adapters/parsers/task/CardContentParser.js +0 -376
  29. package/lib/adapters/parsers/task/CheckStyleTaskParser.js +0 -28
  30. package/lib/adapters/parsers/task/CodeStyleTaskParser.js +0 -24
  31. package/lib/adapters/parsers/task/HashStyleTaskParser.js +0 -27
  32. package/lib/adapters/parsers/task/MarkdownStyleTaskParser.js +0 -24
  33. package/lib/adapters/parsers/task/TaskParser.js +0 -38
  34. package/lib/adapters/readers/FileSystemProjectReader.js +0 -45
  35. package/lib/adapters/storage/config.js +0 -49
  36. package/lib/adapters/storage/tags.js +0 -30
  37. package/lib/adapters/yaml.js +0 -6
  38. package/lib/card.js +0 -300
  39. package/lib/config.js +0 -214
  40. package/lib/constants.js +0 -97
  41. package/lib/context/ApplicationContext.js +0 -32
  42. package/lib/context/StreamingApplicationContext.js +0 -31
  43. package/lib/controlers/SaveViewController.js +0 -10
  44. package/lib/default-settings.js +0 -37
  45. package/lib/domain/entities/FileProjectContext.js +0 -10
  46. package/lib/domain/entities/View.js +0 -30
  47. package/lib/domain/usecases/GetViewsUsecase.js +0 -50
  48. package/lib/domain/usecases/OpenProjectUsecase.js +0 -13
  49. package/lib/domain/usecases/SaveViewUsecase.js +0 -57
  50. package/lib/file.js +0 -1395
  51. package/lib/languages.js +0 -114
  52. package/lib/list.js +0 -105
  53. package/lib/migrate-config.js +0 -165
  54. package/lib/mixins/repo-fs-store.js +0 -424
  55. package/lib/mixins/repo-watched-fs-store.js +0 -195
  56. package/lib/plugins/archive-plugin.js +0 -70
  57. package/lib/plugins/default-board-actions-plugin.js +0 -56
  58. package/lib/plugins/default-board-properties-plugin.js +0 -101
  59. package/lib/plugins/epic-plugin.js +0 -176
  60. package/lib/plugins/extension-plugin.js +0 -87
  61. package/lib/plugins/persist-tags-plugin.js +0 -13
  62. package/lib/plugins/plugin-manager.js +0 -421
  63. package/lib/plugins/plugin-registry.js +0 -61
  64. package/lib/project-factory.js +0 -45
  65. package/lib/project.js +0 -911
  66. package/lib/repository.js +0 -1746
  67. package/lib/task.js +0 -798
  68. package/lib/tools.js +0 -250
  69. package/lib/usecases/get-imdone-url.js +0 -6
  70. package/lib/usecases/get-project-tags.js +0 -16
  71. package/lib/usecases/get-tasks-in-file.js +0 -29
@@ -1,421 +0,0 @@
1
- const Emitter = require('events')
2
- const Plugin = require('imdone-api')
3
- const _path = require('path')
4
- const downloadRepo = require('../adapters/git-download')
5
- const rimraf = require('rimraf')
6
- const sane = require('sane')
7
- const debounce = require('lodash.debounce')
8
- const { exists, mkdir, readdir } = require('../adapters/file-gateway')
9
- const appContext = require('../context/ApplicationContext')
10
-
11
- module.exports = class PluginManager extends Emitter {
12
- constructor(project) {
13
- super()
14
- this.project = project
15
- this.defaultPlugins = [
16
- './persist-tags-plugin',
17
- './default-board-properties-plugin',
18
- './default-board-actions-plugin',
19
- './archive-plugin',
20
- './epic-plugin',
21
- './extension-plugin',
22
- ]
23
- this.pluginsMap = {}
24
- this.pluginPath = _path.join(project.path, '.imdone', 'plugins')
25
- this.onDevChange = debounce(this.onDevChange.bind(this), 1000)
26
- }
27
-
28
- async startDevMode() {
29
- if (this.project && this.project.config.devMode && !this.watcher) {
30
- if (!(await exists(this.pluginPath)))
31
- await mkdir(this.pluginPath)
32
- this.watcher = sane(this.pluginPath, {
33
- ignored(path) {
34
- return /node_modules/.test(path)
35
- },
36
- })
37
- this.watcher.on('change', (path, root, stat) => {
38
- this.onDevChange()
39
- })
40
- this.watcher.on('add', (path, root, stat) => {
41
- this.onDevChange()
42
- })
43
- }
44
- }
45
-
46
- stopDevMode() {
47
- this.watcher && this.watcher.close()
48
- this.watcher = null
49
- }
50
-
51
- initDevMode() {
52
- if (!this.project.config.devMode) this.stopDevMode()
53
- this.startDevMode()
54
- }
55
-
56
- async onDevChange() {
57
- try {
58
- await this.reloadPlugins()
59
- this.emit('plugins-reloaded')
60
- } catch {
61
- console.error('Error reloading plugins.', err)
62
- throw err
63
- }
64
- }
65
-
66
- async reloadPlugins() {
67
- this.destroyPlugins()
68
- await this.loadPlugins()
69
- await this.startDevMode()
70
- }
71
-
72
- async uninstallPlugin(pluginName) {
73
- return new Promise((resolve, reject) => {
74
- console.log('Preparing to uninstall plugin:', pluginName)
75
- const pluginClassName = Object.keys(this.pluginsMap).find((key) => {
76
- return this.getPlugin(key).info.name === pluginName
77
- })
78
- if (!pluginClassName) {
79
- return reject(new Error('Unable to find plugin:' + pluginName))
80
- }
81
- const { info } = this.getPlugin(pluginClassName)
82
- const { path } = info
83
- // const pkg = { version, name }
84
- console.log('Uninstalling:', info)
85
-
86
- rimraf(path, (err) => {
87
- if (err) return reject(err)
88
- delete this.pluginsMap[pluginClassName]
89
- this.emit('plugin-uninstalled', pluginName)
90
- resolve()
91
- })
92
- })
93
- }
94
-
95
- async installPlugin({ name, version }) {
96
- if (!(await exists(this.pluginPath)))
97
- await mkdir(this.pluginPath)
98
- const installPath = _path.join(this.pluginPath, name)
99
- await downloadRepo(version, installPath)
100
- console.log(`Done installing ${name}`)
101
- await this.loadPlugin(installPath)
102
- this.emit('plugin-installed', name)
103
- }
104
-
105
- async loadPlugins() {
106
- for (const pluginPath of this.defaultPlugins) {
107
- await this.loadPlugin(pluginPath)
108
- }
109
-
110
- await this.loadInstalledPlugins()
111
- await this.loadPluginsNotInstalled()
112
- }
113
-
114
- async loadInstalledPlugins() {
115
- const path = await exists(this.pluginPath)
116
- if (!path) {
117
- await mkdir(this.pluginPath)
118
- }
119
- const paths = await readdir(this.pluginPath, { withFileTypes: true })
120
- const pluginPaths = paths
121
- .filter(
122
- (entry) =>
123
- entry.name !== 'node_modules' &&
124
- (entry.isDirectory() || entry.isSymbolicLink())
125
- )
126
- .map((entry) => _path.join(this.pluginPath, entry.name))
127
-
128
- for (const path of pluginPaths) {
129
- await this.loadPlugin(path)
130
- }
131
- }
132
-
133
- async loadPluginsNotInstalled() {
134
- const availablePlugins = await appContext().pluginRegistry.getAvailablePlugins()
135
- const configPluginNames = Object.keys(this.project.config.plugins)
136
- if (!configPluginNames) return
137
- const installedPluginNames = Object.keys(this.pluginsMap)
138
- const pluginsNotInstalled = configPluginNames.filter(name => !installedPluginNames.includes(name))
139
- for (const pluginName of pluginsNotInstalled) {
140
- const plugin = availablePlugins.find(p => p.name === pluginName)
141
- if (plugin && plugin.name) await this.installPlugin(plugin)
142
- }
143
- }
144
-
145
- async loadPlugin(path) {
146
- console.log('Loading plugin: ', path)
147
- try {
148
- // eslint-disable-next-line
149
- delete require.cache[require.resolve(path)]
150
- // eslint-disable-next-line
151
- const pluginClass = require(path)
152
- const pluginInstance = await this.createPlugin(pluginClass, path)
153
- if (pluginInstance.init) await pluginInstance.init()
154
- } catch (e) {
155
- console.error(`Error loading plugin at: ${path}`, e)
156
- }
157
- }
158
-
159
- async createPlugin(pluginClass, path) {
160
- if (!this.isPlugin(pluginClass))
161
- throw new Error(`${pluginClass.name} is not a plugin`)
162
- const name = pluginClass.name.toString()
163
- const pluginInstance = new pluginClass(this.project)
164
- let info = {}
165
- try {
166
- info = require(`${path}/package.json`)
167
- delete info.dependencies
168
- delete info.devDependencies
169
- delete info.scripts
170
- delete info.main
171
- } catch (e) {
172
- console.info('No info on plugin:', path)
173
- } finally {
174
- info.path = path
175
- info.name = name
176
- }
177
-
178
- pluginInstance.getSettings = () => {
179
- return this.getPluginSettings(info.name)
180
- }
181
-
182
- this.pluginsMap[name] = {
183
- pluginInstance,
184
- pluginClass,
185
- info,
186
- }
187
-
188
- return pluginInstance
189
- }
190
-
191
- destroyPlugins() {
192
- this.stopDevMode()
193
- this.eachPlugin(({ pluginInstance }) => {
194
- try {
195
- pluginInstance.destroy()
196
- } catch (e) {
197
- this.pluginError('destroy', pluginInstance, e)
198
- }
199
- })
200
- }
201
-
202
- isPlugin(pluginClass) {
203
- return Object.getPrototypeOf(pluginClass).name === Plugin.name
204
- }
205
-
206
- eachPlugin(cb) {
207
- Object.keys(this.pluginsMap).forEach((key) => {
208
- cb(this.getPlugin(key))
209
- })
210
- }
211
-
212
- async eachPluginAsync(cb) {
213
- for (const key of Object.keys(this.pluginsMap)) {
214
- await cb(this.getPlugin(key))
215
- }
216
- }
217
-
218
- getPlugins() {
219
- return Object.keys(this.pluginsMap).map((key) => {
220
- const { info, pluginInstance } = this.getPlugin(key)
221
- const schema = pluginInstance.getSettingsSchema()
222
- if (schema) {
223
- schema.id = info.name
224
- schema.title = `${info.name} settings`
225
- }
226
- return { ...info, schema }
227
- })
228
- }
229
-
230
- getPluginName(pluginInstance) {
231
- return Object.keys(this.pluginsMap).find(
232
- (pluginName) =>
233
- this.getPlugin(pluginName).pluginInstance === pluginInstance
234
- )
235
- }
236
-
237
- getPluginInstance(name) {
238
- const plugin = this.getPlugin(name)
239
- if (!plugin) throw new Error(`Plugin ${name} not found`)
240
- return plugin.pluginInstance
241
- }
242
-
243
- getPlugin(name) {
244
- return this.pluginsMap[name]
245
- }
246
-
247
- getPluginSettings(name) {
248
- return this.project.config.plugins[name] || {}
249
- }
250
-
251
- pluginError(method, pluginInstance, error) {
252
- console.warn(
253
- `Plugin: ${this.getPluginName(
254
- pluginInstance
255
- )} threw an error on ${method}: `,
256
- error
257
- )
258
- }
259
-
260
- async onBoardUpdate(lists) {
261
- if (!lists || lists.length == 0) return
262
- await this.eachPluginAsync(async ({ pluginInstance }) => {
263
- // const timeLabel = `${this.getPluginName(pluginInstance)} onBoardUpdate time`
264
- // console.time(timeLabel)
265
- try {
266
- await pluginInstance.onBoardUpdate(lists)
267
- } catch (e) {
268
- this.pluginError('onBoardUpdate', pluginInstance, e)
269
- }
270
- // console.timeEnd(timeLabel)
271
- })
272
- return lists
273
- }
274
-
275
- async onBeforeBoardUpdate() {
276
- await this.eachPluginAsync(async ({ pluginInstance }) => {
277
- try {
278
- await pluginInstance.onBeforeBoardUpdate()
279
- } catch (e) {
280
- this.pluginError('onBeforeBoardUpdate', pluginInstance, e)
281
- }
282
- })
283
- }
284
-
285
- onTaskUpdate(task) {
286
- this.eachPlugin(({ pluginInstance }) => {
287
- try {
288
- pluginInstance.onTaskUpdate(task)
289
- } catch (e) {
290
- this.pluginError('onTaskUpdate', pluginInstance, e)
291
- }
292
- })
293
- }
294
-
295
- async onTaskFound(task) {
296
- await this.eachPluginAsync(async ({ pluginInstance }) => {
297
- try {
298
- if (pluginInstance.onTaskFound) await pluginInstance.onTaskFound(task)
299
- } catch (e) {
300
- this.pluginError('onTaskFound', pluginInstance, e)
301
- }
302
- })
303
- }
304
-
305
- async onBeforeAddTask({path, list, content, tags, contexts, meta, useCardTemplate}) {
306
- await this.eachPluginAsync(async ({ pluginInstance }) => {
307
- try {
308
- const pluginMods = await pluginInstance.onBeforeAddTask({path, list, content, tags, contexts, meta, useCardTemplate})
309
- path = pluginMods.path
310
- content = pluginMods.content
311
- tags = pluginMods.tags
312
- contexts = pluginMods.contexts
313
- meta = pluginMods.meta
314
- } catch (e) {
315
- this.pluginError('onBeforeAddTask', pluginInstance, e)
316
- }
317
- })
318
- return {path, content, tags, contexts, meta}
319
- }
320
-
321
- async onAfterDeleteTask(task) {
322
- await this.eachPluginAsync(async ({ pluginInstance }) => {
323
- try {
324
- await pluginInstance.onAfterDeleteTask(task)
325
- } catch (e) {
326
- this.pluginError('onAfterDeleteTask', pluginInstance, e)
327
- }
328
- })
329
- }
330
-
331
- getCardProperties(props) {
332
- let cardProps = {}
333
- this.eachPlugin(({ pluginInstance }) => {
334
- try {
335
- cardProps = { ...cardProps, ...pluginInstance.getCardProperties(props) }
336
- } catch (e) {
337
- this.pluginError('getCardProperties', pluginInstance, e)
338
- }
339
- })
340
- return cardProps
341
- }
342
-
343
- // READY Make getBoardProperties async
344
- // <!--
345
- // order:-10
346
- // -->
347
- async getBoardProperties() {
348
- let boardProps = {}
349
- await this.eachPluginAsync(async ({ pluginInstance }) => {
350
- try {
351
- const pluginProps = pluginInstance.getBoardProperties ? await pluginInstance.getBoardProperties() : {}
352
- boardProps = { ...boardProps, ...pluginProps }
353
- } catch (e) {
354
- this.pluginError('getBoardProperties', pluginInstance, e)
355
- }
356
- })
357
- return boardProps
358
- }
359
-
360
- getCardActions(task) {
361
- let cardLinks = []
362
- this.eachPlugin(({ pluginInstance }) => {
363
- try {
364
- cardLinks = [
365
- ...cardLinks,
366
- ...pluginInstance.getCardActions(task).map((link, index) => {
367
- return {
368
- ...link,
369
- action: { plugin: this.getPluginName(pluginInstance), index },
370
- }
371
- }),
372
- ]
373
- } catch (e) {
374
- this.pluginError('getCardActions', pluginInstance, e)
375
- }
376
- })
377
- return cardLinks
378
- }
379
-
380
- getBoardActions() {
381
- let actions = []
382
- this.eachPlugin(({ pluginInstance }) => {
383
- try {
384
- actions = [
385
- ...actions,
386
- ...pluginInstance.getBoardActions().map((item, index) => {
387
- if (item.title) item.name = item.title
388
- return {
389
- ...item,
390
- plugin: this.getPluginName(pluginInstance),
391
- index,
392
- }
393
- }),
394
- ]
395
- } catch (e) {
396
- this.pluginError('getBoardActions', pluginInstance, e)
397
- }
398
- })
399
- return actions
400
- }
401
-
402
- performCardAction(action, task) {
403
- const plugin = this.getPluginInstance(action.plugin)
404
- try {
405
- return plugin.getCardActions(task)[action.index].action()
406
- } catch (e) {
407
- this.pluginError('getCardActions', plugin, e)
408
- }
409
- }
410
-
411
- async performBoardAction(action, task) {
412
- const plugin = this.getPluginInstance(action.plugin)
413
- try {
414
- return action.index
415
- ? await plugin.getBoardActions()[action.index].action(task)
416
- : await plugin.getBoardActions().find(a => a.title === action.title).action(task)
417
- } catch (e) {
418
- this.pluginError('getBoardActions', plugin, e)
419
- }
420
- }
421
- }
@@ -1,61 +0,0 @@
1
- const {
2
- renderMarkdown,
3
- } = require('../adapters/markdown')
4
-
5
- module.exports = {
6
-
7
- getAvailablePlugins: async function () {
8
- const response = await fetch('https://raw.githubusercontent.com/imdone/imdone-plugins/main/index.json')
9
- const plugins = response.body
10
- for (const plugin of plugins) {
11
- plugin.content = renderMarkdown(await getReadmeContent(plugin))
12
- }
13
- return plugins
14
- },
15
-
16
- }
17
-
18
- async function getReadmeContent({version}) {
19
- const response = await fetch(`https://api.github.com/repos/${version}/readme`)
20
- const { content } = response.body
21
- const buffer = Buffer.from(content, 'base64');
22
- return buffer.toString('utf-8');
23
- }
24
-
25
- const https = require('https')
26
-
27
- async function fetch(url, opts = { method: 'GET', headers: {} }) {
28
- const { method, headers, body, debug = () => { } } = opts
29
- if (body) headers['Content-Length'] = body.length
30
- headers['Cache-Control'] = 'no-cache'; // Add Cache-Control header
31
- url = new URL(url)
32
- const port = url.protocol === 'https:' ? 443 : 80
33
- const options = {
34
- hostname: url.hostname,
35
- port: port,
36
- path: url.pathname,
37
- method,
38
- headers: {
39
- 'User-Agent': 'imdone',
40
- ...headers,
41
- },
42
- }
43
-
44
- debug("Fetch request:", JSON.stringify({ method, url, body }))
45
-
46
- return new Promise((resolve, reject) => {
47
- let result = []
48
-
49
- const req = https.request(options, (res) => {
50
- res.on('data', (chunk) => result.push(chunk))
51
- res.on('end', () => {
52
- const data = Buffer.concat(result).toString()
53
- debug("Fetch response:", JSON.stringify({ data, status: res.statusCode }))
54
- resolve({ body: data && JSON.parse(data), status: res.statusCode })
55
- })
56
- })
57
- req.on('error', reject)
58
- if (body) req.write(body)
59
- req.end()
60
- })
61
- }
@@ -1,45 +0,0 @@
1
- const Repository = require('./repository')
2
- const watchedFsStore = require('./mixins/repo-watched-fs-store')
3
- const fsStore = require('./mixins/repo-fs-store')
4
- const ProjectContext = require('./ProjectContext')
5
- const Project = require('./project')
6
- const context = require('./context/ApplicationContext')
7
-
8
- function createFileSystemProject({
9
- path,
10
- config,
11
- repo = fsStore(new Repository(path, config)),
12
- loadInstalledPlugins,
13
- loadPluginsNotInstalled
14
- }) {
15
- context().repo = repo
16
- context().projectContext = new ProjectContext(repo)
17
- context().project = new Project(repo)
18
- if (loadInstalledPlugins) {
19
- context().project.pluginManager.loadInstalledPlugins = loadInstalledPlugins
20
- }
21
- if (loadPluginsNotInstalled) {
22
- context().project.pluginManager.loadPluginsNotInstalled = loadPluginsNotInstalled
23
- }
24
- return context().project
25
- }
26
-
27
- module.exports = {
28
- createWatchedFileSystemProject: function({
29
- path,
30
- config,
31
- repo = watchedFsStore(new Repository(path, config)),
32
- loadInstalledPlugins,
33
- loadPluginsNotInstalled
34
- }) {
35
- return createFileSystemProject({
36
- path,
37
- config,
38
- repo,
39
- loadInstalledPlugins,
40
- loadPluginsNotInstalled
41
- })
42
- },
43
-
44
- createFileSystemProject
45
- }