imdone-core 1.54.8 → 1.54.9
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/README.md +3 -2
- package/lib/adapters/file-gateway.js +9 -8
- package/lib/context/ApplicationContext.js +1 -0
- package/lib/plugins/plugin-manager.js +28 -18
- package/lib/plugins/plugin-registry.js +61 -0
- package/lib/project-factory.js +27 -3
- package/lib/project.js +90 -91
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -199,8 +199,9 @@ License
|
|
|
199
199
|
|
|
200
200
|
<!-- # #NOTE Notes
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
{{branch}} :deciduous_tree: :hammer_and_wrench: Current Branch
|
|
203
|
+
{{version}} :package: :hammer_and_wrench: Code Version
|
|
204
|
+
{{publishedVersion}} :package: :passenger_ship: Published Version
|
|
204
205
|
|
|
205
206
|
[Focus]({{getFilterURL('list = DOING or tags = focus')}})
|
|
206
207
|
[Plan]({{getFilterURL(' ')}})
|
|
@@ -3,6 +3,14 @@ const _path = require('path')
|
|
|
3
3
|
let fs = require('fs')
|
|
4
4
|
const sanitize = require('sanitize-filename')
|
|
5
5
|
|
|
6
|
+
async function exists(path) {
|
|
7
|
+
try {
|
|
8
|
+
await fs.promises.access(path)
|
|
9
|
+
return path
|
|
10
|
+
} catch {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
}
|
|
6
14
|
|
|
7
15
|
function mkdirpSync(path) {
|
|
8
16
|
console.warn('sync call')
|
|
@@ -29,14 +37,7 @@ const gateway = {
|
|
|
29
37
|
return fs.existsSync.apply({}, args)
|
|
30
38
|
},
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
await fs.promises.access(path)
|
|
35
|
-
return path
|
|
36
|
-
} catch {
|
|
37
|
-
return false
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
+
exists,
|
|
40
41
|
|
|
41
42
|
async stat(path, opts) {
|
|
42
43
|
try {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const Emitter = require('events')
|
|
2
2
|
const Plugin = require('imdone-api')
|
|
3
|
-
const fs = require('fs')
|
|
4
3
|
const _path = require('path')
|
|
5
4
|
const downloadRepo = require('../adapters/git-download')
|
|
6
5
|
const rimraf = require('rimraf')
|
|
7
6
|
const sane = require('sane')
|
|
8
7
|
const debounce = require('lodash.debounce')
|
|
8
|
+
const { exists, mkdir, readdir } = require('../adapters/file-gateway')
|
|
9
|
+
const appContext = require('../context/ApplicationContext')
|
|
9
10
|
|
|
10
11
|
module.exports = class PluginManager extends Emitter {
|
|
11
12
|
constructor(project) {
|
|
@@ -26,8 +27,8 @@ module.exports = class PluginManager extends Emitter {
|
|
|
26
27
|
|
|
27
28
|
async startDevMode() {
|
|
28
29
|
if (this.project && this.project.config.devMode && !this.watcher) {
|
|
29
|
-
if (!(await
|
|
30
|
-
await
|
|
30
|
+
if (!(await exists(this.pluginPath)))
|
|
31
|
+
await mkdir(this.pluginPath)
|
|
31
32
|
this.watcher = sane(this.pluginPath, {
|
|
32
33
|
ignored(path) {
|
|
33
34
|
return /node_modules/.test(path)
|
|
@@ -92,8 +93,8 @@ module.exports = class PluginManager extends Emitter {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
async installPlugin({ name, version }) {
|
|
95
|
-
if (!(await
|
|
96
|
-
await
|
|
96
|
+
if (!(await exists(this.pluginPath)))
|
|
97
|
+
await mkdir(this.pluginPath)
|
|
97
98
|
const installPath = _path.join(this.pluginPath, name)
|
|
98
99
|
await downloadRepo(version, installPath)
|
|
99
100
|
console.log(`Done installing ${name}`)
|
|
@@ -106,9 +107,16 @@ module.exports = class PluginManager extends Emitter {
|
|
|
106
107
|
await this.loadPlugin(pluginPath)
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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 })
|
|
112
120
|
const pluginPaths = paths
|
|
113
121
|
.filter(
|
|
114
122
|
(entry) =>
|
|
@@ -120,9 +128,20 @@ module.exports = class PluginManager extends Emitter {
|
|
|
120
128
|
for (const path of pluginPaths) {
|
|
121
129
|
await this.loadPlugin(path)
|
|
122
130
|
}
|
|
123
|
-
|
|
124
131
|
}
|
|
125
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
|
+
await this.installPlugin(plugin)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
126
145
|
async loadPlugin(path) {
|
|
127
146
|
console.log('Loading plugin: ', path)
|
|
128
147
|
try {
|
|
@@ -380,15 +399,6 @@ module.exports = class PluginManager extends Emitter {
|
|
|
380
399
|
return actions
|
|
381
400
|
}
|
|
382
401
|
|
|
383
|
-
async exists(path) {
|
|
384
|
-
try {
|
|
385
|
-
await fs.promises.access(path)
|
|
386
|
-
return path
|
|
387
|
-
} catch {
|
|
388
|
-
return false
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
402
|
performCardAction(action, task) {
|
|
393
403
|
const plugin = this.getPluginInstance(action.plugin)
|
|
394
404
|
try {
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
}
|
package/lib/project-factory.js
CHANGED
|
@@ -5,16 +5,40 @@ const ProjectContext = require('./ProjectContext')
|
|
|
5
5
|
const Project = require('./project')
|
|
6
6
|
const context = require('./context/ApplicationContext')
|
|
7
7
|
|
|
8
|
-
function createFileSystemProject({
|
|
8
|
+
function createFileSystemProject({
|
|
9
|
+
path,
|
|
10
|
+
config,
|
|
11
|
+
repo = fsStore(new Repository(path, config)),
|
|
12
|
+
loadInstalledPlugins,
|
|
13
|
+
loadPluginsNotInstalled
|
|
14
|
+
}) {
|
|
9
15
|
context().repo = repo
|
|
10
16
|
context().projectContext = new ProjectContext(repo)
|
|
11
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
|
+
}
|
|
12
24
|
return context().project
|
|
13
25
|
}
|
|
14
26
|
|
|
15
27
|
module.exports = {
|
|
16
|
-
createWatchedFileSystemProject: function({
|
|
17
|
-
|
|
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
|
+
})
|
|
18
42
|
},
|
|
19
43
|
|
|
20
44
|
createFileSystemProject
|
package/lib/project.js
CHANGED
|
@@ -54,13 +54,100 @@ module.exports = class WorkerProject extends Project {
|
|
|
54
54
|
this._updatedAt = undefined
|
|
55
55
|
this.data = {}
|
|
56
56
|
this.dataKeys = []
|
|
57
|
+
this.repo.project = this
|
|
58
|
+
this.pluginManager = new PluginManager(this)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get configDir() {
|
|
62
|
+
return _path.join(this.path, CONFIG_DIR)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get allTopics() {
|
|
66
|
+
return [...this.repo.allTopics]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get allTags() {
|
|
70
|
+
return [...this.repo.allTags]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get allContexts() {
|
|
74
|
+
return [...this.repo.allContexts]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get allMeta() {
|
|
78
|
+
return this.repo.allMeta
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get lists() {
|
|
82
|
+
return this.getLists({
|
|
83
|
+
tasks: this.filteredCards,
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get allLists() {
|
|
88
|
+
return this.getLists()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get filteredCards() {
|
|
92
|
+
return this.getCards(this.filter)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get isoDateWithOffset() {
|
|
96
|
+
return getIsoDateWithOffset()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get updatedAt() {
|
|
100
|
+
return this._updatedAt
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get files() {
|
|
104
|
+
return this.repo.getFilePaths()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get config() {
|
|
108
|
+
return this.repo.config
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get defaultFilter() {
|
|
112
|
+
return this.config && this.config.defaultFilter
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
set defaultFilter(filter) {
|
|
116
|
+
this.config.defaultFilter = filter
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get totals() {
|
|
120
|
+
return calculateTotals(this.lists)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
get path() {
|
|
124
|
+
return this.repo.path
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get name() {
|
|
128
|
+
return this.repo.getDisplayName()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get doneList() {
|
|
132
|
+
return this.config.getDoneList()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get boardActions() {
|
|
136
|
+
return [
|
|
137
|
+
...this.pluginManager.getBoardActions(),
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get filter() {
|
|
142
|
+
return this.innerFilter
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
set filter(filter) {
|
|
146
|
+
this.innerFilter = filter
|
|
57
147
|
}
|
|
58
148
|
|
|
59
149
|
async init(cb) {
|
|
60
150
|
const promise = new Promise(async (resolve, reject) => {
|
|
61
|
-
this.repo.project = this
|
|
62
|
-
|
|
63
|
-
this.pluginManager = new PluginManager(this)
|
|
64
151
|
this.pluginManager.on('plugin-installed', () => this.emitUpdate())
|
|
65
152
|
this.pluginManager.on('plugin-uninstalled', () => this.emitUpdate())
|
|
66
153
|
this.pluginManager.on('plugins-reloaded', () => this.emitUpdate())
|
|
@@ -226,48 +313,6 @@ module.exports = class WorkerProject extends Project {
|
|
|
226
313
|
if (this.pluginManager) this.pluginManager.destroyPlugins()
|
|
227
314
|
}
|
|
228
315
|
|
|
229
|
-
get configDir() {
|
|
230
|
-
return _path.join(this.path, CONFIG_DIR)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
get allTopics() {
|
|
234
|
-
return [...this.repo.allTopics]
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
get allTags() {
|
|
238
|
-
return [...this.repo.allTags]
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
get allContexts() {
|
|
242
|
-
return [...this.repo.allContexts]
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
get allMeta() {
|
|
246
|
-
return this.repo.allMeta
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
get lists() {
|
|
250
|
-
return this.getLists({
|
|
251
|
-
tasks: this.filteredCards,
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
get allLists() {
|
|
256
|
-
return this.getLists()
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
get filteredCards() {
|
|
260
|
-
return this.getCards(this.filter)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
get isoDateWithOffset() {
|
|
264
|
-
return getIsoDateWithOffset()
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
get updatedAt() {
|
|
268
|
-
return this._updatedAt
|
|
269
|
-
}
|
|
270
|
-
|
|
271
316
|
getDataKeys(data) {
|
|
272
317
|
const keys = Object.keys(data).map((key) => {
|
|
273
318
|
const value = data[key]
|
|
@@ -372,52 +417,6 @@ module.exports = class WorkerProject extends Project {
|
|
|
372
417
|
return result
|
|
373
418
|
}
|
|
374
419
|
|
|
375
|
-
get files() {
|
|
376
|
-
return this.repo.getFilePaths()
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
get config() {
|
|
380
|
-
return this.repo.config
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
get defaultFilter() {
|
|
384
|
-
return this.config && this.config.defaultFilter
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
set defaultFilter(filter) {
|
|
388
|
-
this.config.defaultFilter = filter
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
get totals() {
|
|
392
|
-
return calculateTotals(this.lists)
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
get path() {
|
|
396
|
-
return this.repo.path
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
get name() {
|
|
400
|
-
return this.repo.getDisplayName()
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
get doneList() {
|
|
404
|
-
return this.config.getDoneList()
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
get filter() {
|
|
408
|
-
return this.innerFilter
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
get boardActions() {
|
|
412
|
-
return [
|
|
413
|
-
...this.pluginManager.getBoardActions(),
|
|
414
|
-
]
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
set filter(filter) {
|
|
418
|
-
this.innerFilter = filter
|
|
419
|
-
}
|
|
420
|
-
|
|
421
420
|
async addMetadata(task, key, value) {
|
|
422
421
|
if (task.hasMetaData(key, value)) return
|
|
423
422
|
if (!task.allMeta[key]) task.allMeta[key] = []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imdone-core",
|
|
3
|
-
"version": "1.54.
|
|
3
|
+
"version": "1.54.9",
|
|
4
4
|
"description": "imdone-core",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"fs-extra": "^11.1.0",
|
|
119
119
|
"jshint": "^2.9.4",
|
|
120
120
|
"json-stringify-safe": "~5.0.0",
|
|
121
|
-
"mocha": "^
|
|
121
|
+
"mocha": "^11.1.0",
|
|
122
122
|
"mocha-each": "^2.0.1",
|
|
123
123
|
"nyc": "^15.1.0",
|
|
124
124
|
"prettier": "^2.5.1",
|