@gesslar/bedoc 1.5.2 → 1.6.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/package.json +5 -16
- package/src/cli.js +1 -0
- package/src/core/ActionManager.js +1 -3
- package/src/core/Configuration.js +20 -8
- package/src/core/Core.js +3 -5
- package/src/core/Discovery.js +43 -32
- package/src/core/HookManager.js +2 -1
- package/src/core/util/ActionUtil.js +5 -3
- package/src/core/util/ModuleUtil.js +3 -2
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gesslar/bedoc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Pluggable documentation engine for any language and format",
|
|
5
5
|
"publisher": "gesslar",
|
|
6
|
+
"author": "gesslar",
|
|
7
|
+
"license": "Unlicense",
|
|
6
8
|
"main": "./src/core/Core.js",
|
|
7
9
|
"repository": {
|
|
8
10
|
"type": "git",
|
|
@@ -39,6 +41,7 @@
|
|
|
39
41
|
"dotenv": "^16.4.7",
|
|
40
42
|
"error-stack-parser": "^2.1.4",
|
|
41
43
|
"globby": "^14.0.2",
|
|
44
|
+
"json5": "^2.2.3",
|
|
42
45
|
"micromatch": "^4.0.8",
|
|
43
46
|
"node-fetch": "^3.3.2",
|
|
44
47
|
"yaml": "^2.7.0"
|
|
@@ -49,8 +52,8 @@
|
|
|
49
52
|
"@typescript-eslint/parser": "^8.22.0",
|
|
50
53
|
"axios": "^1.7.9",
|
|
51
54
|
"chokidar": "^4.0.3",
|
|
52
|
-
"eslint-plugin-jsdoc": "^50.6.3",
|
|
53
55
|
"eslint": "^9.18.0",
|
|
56
|
+
"eslint-plugin-jsdoc": "^50.6.3",
|
|
54
57
|
"form-data": "^4.0.1"
|
|
55
58
|
},
|
|
56
59
|
"keywords": [
|
|
@@ -62,19 +65,5 @@
|
|
|
62
65
|
"language",
|
|
63
66
|
"format",
|
|
64
67
|
"hooks"
|
|
65
|
-
],
|
|
66
|
-
"author": "gesslar",
|
|
67
|
-
"license": "Unlicense",
|
|
68
|
-
"contributes": {
|
|
69
|
-
"commands": [
|
|
70
|
-
{
|
|
71
|
-
"command": "vscode-bedoc.generateDocs",
|
|
72
|
-
"title": "BeDoc: Generate Documentation"
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
"extensionKind": [
|
|
77
|
-
"workspace",
|
|
78
|
-
"ui"
|
|
79
68
|
]
|
|
80
69
|
}
|
package/src/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import process from "node:process"
|
|
2
2
|
import {Environment} from "./Core.js"
|
|
3
|
+
import JSON5 from "json5"
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
ConfigurationParameters,
|
|
@@ -41,7 +42,9 @@ export default class Configuration {
|
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
const allOptions = this.#findAllOptions(options)
|
|
45
|
+
|
|
44
46
|
Object.assign(finalOptions, await this.#mergeOptions(allOptions))
|
|
47
|
+
|
|
45
48
|
this.#fixOptionValues(finalOptions)
|
|
46
49
|
|
|
47
50
|
// Priority keys are those which must be processed first. They are
|
|
@@ -78,6 +81,12 @@ export default class Configuration {
|
|
|
78
81
|
)
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
// Check for mandatory values
|
|
85
|
+
for(const [key, {required}] of Object.entries(ConfigurationParameters)) {
|
|
86
|
+
if(required && !orderedSections.find(s => s.key === key))
|
|
87
|
+
throw new SyntaxError(`Missing mandatory key \`${key}\``)
|
|
88
|
+
}
|
|
89
|
+
|
|
81
90
|
for(const section of orderedSections) {
|
|
82
91
|
const {key} = section
|
|
83
92
|
|
|
@@ -212,12 +221,11 @@ export default class Configuration {
|
|
|
212
221
|
*/
|
|
213
222
|
#findAllOptions(entryOptions) {
|
|
214
223
|
const allOptions = []
|
|
215
|
-
|
|
216
224
|
const environmentVariables = this.#getEnvironmentVariables()
|
|
217
225
|
if(environmentVariables)
|
|
218
226
|
allOptions.push({source: "environment", options: environmentVariables})
|
|
219
227
|
|
|
220
|
-
const packageJson = entryOptions
|
|
228
|
+
const packageJson = entryOptions?.packageJson
|
|
221
229
|
if(packageJson?.bedoc)
|
|
222
230
|
allOptions.push({source: "packageJson", options: packageJson.bedoc})
|
|
223
231
|
|
|
@@ -228,12 +236,16 @@ export default class Configuration {
|
|
|
228
236
|
environmentVariables?.config
|
|
229
237
|
|
|
230
238
|
if(useConfig) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
239
|
+
const configFile =
|
|
240
|
+
packageJson?.bedoc?.config
|
|
241
|
+
? resolveFilename(packageJson?.bedoc?.config)
|
|
242
|
+
: entryOptions.config?.value
|
|
243
|
+
? resolveFilename(entryOptions.config.value)
|
|
244
|
+
: null
|
|
245
|
+
|
|
246
|
+
if(!configFile)
|
|
234
247
|
throw new Error("No config file specified")
|
|
235
248
|
|
|
236
|
-
const configFile = resolveFilename(configFilename)
|
|
237
249
|
const config = loadJson(configFile)
|
|
238
250
|
|
|
239
251
|
allOptions.push({source: "config", options: config})
|
|
@@ -303,7 +315,7 @@ export default class Configuration {
|
|
|
303
315
|
|
|
304
316
|
// Last, but not least, add any defaulted options that are not in the
|
|
305
317
|
// mapped options
|
|
306
|
-
for(const [key, value] of Object.entries(entryOptions)) {
|
|
318
|
+
for(const [key, value] of Object.entries(entryOptions ?? {})) {
|
|
307
319
|
if(!mappedOptions[key]) {
|
|
308
320
|
if(value.source)
|
|
309
321
|
mappedOptions[key] = value.value
|
|
@@ -329,7 +341,7 @@ export default class Configuration {
|
|
|
329
341
|
switch(param.type.toString()) {
|
|
330
342
|
case "boolean":
|
|
331
343
|
case "number":
|
|
332
|
-
options[key] =
|
|
344
|
+
options[key] = JSON5.parse(options[key])
|
|
333
345
|
break
|
|
334
346
|
}
|
|
335
347
|
}
|
package/src/core/Core.js
CHANGED
|
@@ -45,11 +45,9 @@ export default class Core {
|
|
|
45
45
|
debug("Creating new BeDoc instance with options: `%o`", 2, validConfig)
|
|
46
46
|
|
|
47
47
|
const discovery = new Discovery(instance)
|
|
48
|
-
const {printer: validPrint, parser: validParse} = validConfig
|
|
49
|
-
|
|
50
48
|
const actionDefs = await discovery.discoverActions({
|
|
51
|
-
print:
|
|
52
|
-
parse:
|
|
49
|
+
print: validConfig.printer,
|
|
50
|
+
parse: validConfig.parser
|
|
53
51
|
})
|
|
54
52
|
|
|
55
53
|
const validCrit = discovery.satisfyCriteria(actionDefs, validConfig)
|
|
@@ -97,7 +95,7 @@ export default class Core {
|
|
|
97
95
|
for(const [, value] of Object.entries(finalActions)) {
|
|
98
96
|
const {action: actionType} = value.action.meta
|
|
99
97
|
|
|
100
|
-
debug("Attaching
|
|
98
|
+
debug("Attaching %o action to instance", 2, actionType)
|
|
101
99
|
instance.actions[actionType] = new managers[actionType](
|
|
102
100
|
value, instance.logger
|
|
103
101
|
)
|
package/src/core/Discovery.js
CHANGED
|
@@ -34,6 +34,8 @@ export default class Discovery {
|
|
|
34
34
|
|
|
35
35
|
debug("Discovering actions", 2)
|
|
36
36
|
|
|
37
|
+
debug("Specific modules provided: %o", 2, specific)
|
|
38
|
+
|
|
37
39
|
const bucket = []
|
|
38
40
|
const options = this.core.options ?? {}
|
|
39
41
|
|
|
@@ -50,10 +52,10 @@ export default class Discovery {
|
|
|
50
52
|
debug("Mock path not set, discovering actions in node_modules", 1)
|
|
51
53
|
|
|
52
54
|
debug("Looking for actions in project's package.json", 2)
|
|
53
|
-
if(this.core.packageJson?.
|
|
54
|
-
const actions = this.core.packageJson?.
|
|
55
|
+
if(this.core.packageJson?.modules) {
|
|
56
|
+
const actions = this.core.packageJson?.modules
|
|
55
57
|
|
|
56
|
-
debug("Found %
|
|
58
|
+
debug("Found %o actions in package.json", 3, actions)
|
|
57
59
|
debug("Actions found in package.json action in package.json: %o", 3, actions)
|
|
58
60
|
|
|
59
61
|
if(actions && typeof(actions) === "object")
|
|
@@ -70,7 +72,7 @@ export default class Discovery {
|
|
|
70
72
|
execSync("npm root -g").toString().trim(),
|
|
71
73
|
]
|
|
72
74
|
|
|
73
|
-
debug("Found %
|
|
75
|
+
debug("Found %o directories to search for actions", 2, directories.length)
|
|
74
76
|
debug("Directories to search for actions: %o", 3, directories)
|
|
75
77
|
|
|
76
78
|
const moduleDirectories = directories
|
|
@@ -79,15 +81,15 @@ export default class Discovery {
|
|
|
79
81
|
for(const moduleDirectory of moduleDirectories) {
|
|
80
82
|
const {directories: dirs} = await ls(moduleDirectory.absolutePath)
|
|
81
83
|
|
|
82
|
-
debug("Found %
|
|
84
|
+
debug("Found %o directories in `%s`", 2,
|
|
83
85
|
dirs.length, moduleDirectory.absolutePath
|
|
84
86
|
)
|
|
85
87
|
|
|
86
88
|
const bedocDirs = dirs.filter(d => d.name.startsWith("bedoc-"))
|
|
87
|
-
debug("Found %
|
|
89
|
+
debug("Found %o bedoc directories under %s", 2, bedocDirs.length, moduleDirectory.absolutePath)
|
|
88
90
|
|
|
89
91
|
const exports = bedocDirs.map(d => this.#getModuleExports(d))
|
|
90
|
-
debug("Found %
|
|
92
|
+
debug("Found %o module exports under %s", 2, exports.length, moduleDirectory.absolutePath)
|
|
91
93
|
|
|
92
94
|
bucket.push(...exports.flat())
|
|
93
95
|
}
|
|
@@ -127,38 +129,39 @@ export default class Discovery {
|
|
|
127
129
|
* respective contracts.
|
|
128
130
|
*
|
|
129
131
|
* @param {object[]} moduleFiles The module file objects to process
|
|
130
|
-
* @param {object}
|
|
132
|
+
* @param {object} specificModules The specific modules to load
|
|
131
133
|
* @returns {Promise<object>} The discovered action
|
|
132
134
|
*/
|
|
133
|
-
async #loadActionsAndContracts(moduleFiles,
|
|
135
|
+
async #loadActionsAndContracts(moduleFiles, specificModules) {
|
|
134
136
|
const debug = this.#debug
|
|
135
137
|
|
|
136
138
|
debug("Loading actions and contracts", 2)
|
|
137
139
|
debug("Loading %d module files", 2, moduleFiles.length)
|
|
138
|
-
debug("Specific
|
|
140
|
+
debug("Specific modules to load: %o", 2, specificModules)
|
|
139
141
|
|
|
140
142
|
const resultActions = {}
|
|
141
143
|
actionTypes.forEach(actionType => (resultActions[actionType] = []))
|
|
142
144
|
|
|
143
145
|
// Tag the specific actions to load, so we can filter them later
|
|
144
|
-
for(const [type, file] of Object.entries(
|
|
146
|
+
for(const [type, file] of Object.entries(specificModules)) {
|
|
145
147
|
if(file) {
|
|
146
|
-
debug("Tagging specific
|
|
147
|
-
file.specificType =
|
|
148
|
+
debug("Tagging specific module `%s` as `%s`", 3, file.absolutePath, type)
|
|
149
|
+
file.specificType = file.specificType || []
|
|
150
|
+
file.specificType.push(type)
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
const toLoad = [
|
|
152
155
|
...moduleFiles,
|
|
153
|
-
...Object.values(
|
|
156
|
+
...Object.values(specificModules).filter(Boolean),
|
|
154
157
|
]
|
|
155
158
|
|
|
156
|
-
debug("Loading %d
|
|
157
|
-
debug("
|
|
159
|
+
debug("Loading %d discovered modules", 2, toLoad.length)
|
|
160
|
+
debug("Modules to load: %o", 3, toLoad)
|
|
158
161
|
|
|
159
162
|
const loadedActions = []
|
|
160
163
|
for(const file of toLoad) {
|
|
161
|
-
debug("Loading module `%s`", 2, file.
|
|
164
|
+
debug("Loading module `%s`", 2, file.absoluteUri)
|
|
162
165
|
|
|
163
166
|
const loading = await this.#loadModule(file)
|
|
164
167
|
const loaded = loading.actions.map((action, index) => {
|
|
@@ -170,19 +173,21 @@ export default class Discovery {
|
|
|
170
173
|
}
|
|
171
174
|
|
|
172
175
|
debug("Loaded %d actions", 2, loadedActions.length)
|
|
176
|
+
debug("Loaded actions", 3, loadedActions)
|
|
173
177
|
|
|
174
|
-
const
|
|
178
|
+
const filteredActions = []
|
|
175
179
|
for(const actionType of actionTypes) {
|
|
176
|
-
const
|
|
180
|
+
const module = specificModules[actionType]
|
|
177
181
|
const matchingActions = []
|
|
178
|
-
if(
|
|
179
|
-
debug("Filtering actions for specific
|
|
182
|
+
if(module) {
|
|
183
|
+
debug("Filtering actions for specific: %o", 2, actionType)
|
|
180
184
|
const found = loadedActions.find(
|
|
181
|
-
e => e.file.
|
|
185
|
+
e => e.file.specificType?.includes(actionType) &&
|
|
186
|
+
e.action.meta?.action === actionType
|
|
182
187
|
)
|
|
183
188
|
|
|
184
189
|
if(!found)
|
|
185
|
-
throw new Error(`Could not find specific action: ${
|
|
190
|
+
throw new Error(`Could not find specific action: ${module.absolutePath}`)
|
|
186
191
|
|
|
187
192
|
matchingActions.push(found)
|
|
188
193
|
} else {
|
|
@@ -198,15 +203,17 @@ export default class Discovery {
|
|
|
198
203
|
matchingActions.length, actionType
|
|
199
204
|
)
|
|
200
205
|
|
|
201
|
-
|
|
206
|
+
filteredActions.push(...matchingActions)
|
|
202
207
|
}
|
|
203
208
|
|
|
204
|
-
debug("Filtered %d actions", 2,
|
|
209
|
+
debug("Filtered %d actions", 2, filteredActions.length)
|
|
210
|
+
debug("Filtered actions %o", 3, filteredActions)
|
|
205
211
|
|
|
206
212
|
// Now check the metas for validity
|
|
207
|
-
for(const
|
|
208
|
-
const {action, contract, file: moduleFile} =
|
|
213
|
+
for(const filtered of filteredActions) {
|
|
214
|
+
const {action, contract, file: moduleFile} = filtered
|
|
209
215
|
const meta = action.meta
|
|
216
|
+
|
|
210
217
|
if(!meta)
|
|
211
218
|
throw new TypeError("Action has no meta object:\n" +
|
|
212
219
|
JSON.stringify(moduleFile, null, 2) + "\n" +
|
|
@@ -222,7 +229,7 @@ export default class Discovery {
|
|
|
222
229
|
|
|
223
230
|
const isValid = this.#validMeta(metaAction, {action, contract})
|
|
224
231
|
|
|
225
|
-
debug("
|
|
232
|
+
debug("Meta in action %o in %o is %o", 3,
|
|
226
233
|
metaAction, moduleFile.module, isValid ? "valid" : "invalid"
|
|
227
234
|
)
|
|
228
235
|
|
|
@@ -239,7 +246,7 @@ export default class Discovery {
|
|
|
239
246
|
|
|
240
247
|
for(const actionType of actionTypes) {
|
|
241
248
|
const total = resultActions[actionType].length
|
|
242
|
-
debug("Found %
|
|
249
|
+
debug("Found %o `%o` actions", 2, total, actionType)
|
|
243
250
|
}
|
|
244
251
|
|
|
245
252
|
const total = Object.keys(resultActions).reduce((acc, curr) => {
|
|
@@ -255,6 +262,9 @@ export default class Discovery {
|
|
|
255
262
|
|
|
256
263
|
satisfyCriteria(actions, validatedConfig) {
|
|
257
264
|
const debug = this.#debug
|
|
265
|
+
|
|
266
|
+
debug("Available actions to check %o", 3, actions)
|
|
267
|
+
|
|
258
268
|
const satisfied = {parse: [], print: []}
|
|
259
269
|
const toMatch = {
|
|
260
270
|
parse: {criterion: "language", config: "parser"},
|
|
@@ -272,10 +282,10 @@ export default class Discovery {
|
|
|
272
282
|
if(validatedConfig[config]) {
|
|
273
283
|
debug("Checking for specific `%s` action", 3, actionType)
|
|
274
284
|
const found = actions[actionType].find(
|
|
275
|
-
a => a.file.specificType
|
|
285
|
+
a => a.file.specificType.includes(actionType)
|
|
276
286
|
)
|
|
277
287
|
if(found) {
|
|
278
|
-
debug("Found specific
|
|
288
|
+
debug("Found specific %o action", 3, actionType)
|
|
279
289
|
satisfied[actionType].push(found)
|
|
280
290
|
continue
|
|
281
291
|
}
|
|
@@ -285,13 +295,14 @@ export default class Discovery {
|
|
|
285
295
|
|
|
286
296
|
// Hmm! We didn't find anything specific. Let's check the criterion
|
|
287
297
|
debug("Checking for `%s` actions with criterion `%s`", 3, actionType, criterion)
|
|
298
|
+
debug("Validated config to check against: %o", 3, validatedConfig)
|
|
288
299
|
const found = actions[actionType].filter(a => {
|
|
289
300
|
debug("Meta criterion value: %o", 4, a.action.meta[criterion])
|
|
290
301
|
debug("Config criterion value: %o", 4, validatedConfig[criterion])
|
|
291
302
|
return a.action.meta[criterion] === validatedConfig[criterion]
|
|
292
303
|
})
|
|
293
304
|
|
|
294
|
-
debug("Found %
|
|
305
|
+
debug("Found %o %o actions with criterion %o", 3,
|
|
295
306
|
found.length, actionType, criterion
|
|
296
307
|
)
|
|
297
308
|
|
package/src/core/HookManager.js
CHANGED
|
@@ -90,6 +90,7 @@ export default class HookManager {
|
|
|
90
90
|
return null
|
|
91
91
|
|
|
92
92
|
hooksObj.log = instance.log
|
|
93
|
+
hooksObj.timeout = this.timeout
|
|
93
94
|
instance.#hooks = hooksObj
|
|
94
95
|
|
|
95
96
|
debug("Hooks loaded successfully for `%s`", 2, instance.action)
|
|
@@ -121,7 +122,7 @@ export default class HookManager {
|
|
|
121
122
|
assert(isType(hook, "function"), `Hook "${event}" is not a function`, 1)
|
|
122
123
|
|
|
123
124
|
const hookExecution = await hook.call(this.hooks, args)
|
|
124
|
-
const hookTimeout = this.
|
|
125
|
+
const hookTimeout = this.timeout
|
|
125
126
|
const expireAsync = () =>
|
|
126
127
|
timeoutPromise(
|
|
127
128
|
hookTimeout,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as FDUtil from "./FDUtil.js"
|
|
2
|
+
import process from "node:process"
|
|
3
|
+
import JSON5 from "json5"
|
|
2
4
|
|
|
3
5
|
const {readFile, fileExists, composeFilename} = FDUtil
|
|
4
6
|
|
|
@@ -20,7 +22,7 @@ const actionMetaRequirements = freeze({
|
|
|
20
22
|
function loadJson(jsonFileObject) {
|
|
21
23
|
// Read the file
|
|
22
24
|
const jsonContent = readFile(jsonFileObject)
|
|
23
|
-
const json =
|
|
25
|
+
const json = JSON5.parse(jsonContent)
|
|
24
26
|
return json
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -31,11 +33,11 @@ function loadJson(jsonFileObject) {
|
|
|
31
33
|
* @returns {object?} The parsed package.json content or null if the file does
|
|
32
34
|
* not exist
|
|
33
35
|
*/
|
|
34
|
-
function loadPackageJson(basePath =
|
|
36
|
+
function loadPackageJson(basePath = process.cwd()) {
|
|
35
37
|
const packageJsonFileObject = composeFilename(basePath, "./package.json")
|
|
36
38
|
if(fileExists(packageJsonFileObject)) {
|
|
37
39
|
const jsonContent = readFile(packageJsonFileObject)
|
|
38
|
-
const json =
|
|
40
|
+
const json = JSON5.parse(jsonContent)
|
|
39
41
|
return json
|
|
40
42
|
} else
|
|
41
43
|
return null
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {createRequire} from "module"
|
|
2
2
|
import FDUtil from "./FDUtil.js"
|
|
3
|
+
import JSON5 from "json5"
|
|
3
4
|
|
|
4
5
|
export default class ModuleUtil {
|
|
5
6
|
/**
|
|
@@ -21,7 +22,7 @@ export default class ModuleUtil {
|
|
|
21
22
|
static async loadJson(jsonFileObject) {
|
|
22
23
|
// Read the file
|
|
23
24
|
const jsonContent = await FDUtil.readFile(jsonFileObject)
|
|
24
|
-
const json =
|
|
25
|
+
const json = JSON5.parse(jsonContent)
|
|
25
26
|
return json
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -33,7 +34,7 @@ export default class ModuleUtil {
|
|
|
33
34
|
static async loadPackageJson() {
|
|
34
35
|
const packageJsonFileObject = FDUtil.resolveFilename("./package.json")
|
|
35
36
|
const jsonContent = await FDUtil.readFile(packageJsonFileObject)
|
|
36
|
-
const json =
|
|
37
|
+
const json = JSON5.parse(jsonContent)
|
|
37
38
|
return json
|
|
38
39
|
}
|
|
39
40
|
}
|