@gesslar/bedoc 1.11.0 → 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.
- package/LICENSE.txt +12 -0
- package/README.md +15 -3
- package/dist/schema/bedoc.action.json +42 -0
- package/dist/types/Action.d.ts +3 -0
- package/dist/types/Action.d.ts.map +1 -0
- package/dist/types/BeDoc.d.ts +208 -0
- package/dist/types/BeDoc.d.ts.map +1 -0
- package/dist/types/Configuration.d.ts +11 -0
- package/dist/types/Configuration.d.ts.map +1 -0
- package/dist/types/ConfigurationParameters.d.ts +3 -0
- package/dist/types/ConfigurationParameters.d.ts.map +1 -0
- package/dist/types/Conveyor.d.ts +27 -0
- package/dist/types/Conveyor.d.ts.map +1 -0
- package/dist/types/Discovery.d.ts +215 -0
- package/dist/types/Discovery.d.ts.map +1 -0
- package/dist/types/Environment.d.ts +3 -0
- package/dist/types/Environment.d.ts.map +1 -0
- package/dist/types/Logger.d.ts +47 -0
- package/dist/types/Logger.d.ts.map +1 -0
- package/dist/types/Schema.d.ts +3 -0
- package/dist/types/Schema.d.ts.map +1 -0
- package/dist/types/cli.d.ts +2 -2
- package/dist/types/cli.d.ts.map +1 -10
- package/package.json +24 -23
- package/src/Action.js +9 -0
- package/src/BeDoc.js +276 -0
- package/src/CLIOutput.js +198 -0
- package/src/{core/Configuration.js → Configuration.js} +72 -58
- package/src/{core/ConfigurationParameters.js → ConfigurationParameters.js} +35 -27
- package/src/Conveyor.js +256 -0
- package/src/Discovery.js +442 -0
- package/src/Environment.js +8 -0
- package/src/{core/Logger.js → Logger.js} +30 -18
- package/src/Schema.js +6 -0
- package/src/cli.js +77 -34
- package/tsconfig.types.json +42 -0
- package/LICENSE +0 -24
- package/dist/types/core/ActionManager.d.ts +0 -58
- package/dist/types/core/ActionManager.d.ts.map +0 -10
- package/dist/types/core/Configuration.d.ts +0 -27
- package/dist/types/core/Configuration.d.ts.map +0 -10
- package/dist/types/core/ConfigurationParameters.d.ts +0 -38
- package/dist/types/core/ConfigurationParameters.d.ts.map +0 -10
- package/dist/types/core/Conveyor.d.ts +0 -49
- package/dist/types/core/Conveyor.d.ts.map +0 -10
- package/dist/types/core/Core.d.ts +0 -48
- package/dist/types/core/Core.d.ts.map +0 -10
- package/dist/types/core/Discovery.d.ts +0 -73
- package/dist/types/core/Discovery.d.ts.map +0 -10
- package/dist/types/core/HookManager.d.ts +0 -60
- package/dist/types/core/HookManager.d.ts.map +0 -10
- package/dist/types/core/Logger.d.ts +0 -63
- package/dist/types/core/Logger.d.ts.map +0 -10
- package/dist/types/core/action/ParseManager.d.ts +0 -8
- package/dist/types/core/action/ParseManager.d.ts.map +0 -10
- package/dist/types/core/action/PrintManager.d.ts +0 -8
- package/dist/types/core/action/PrintManager.d.ts.map +0 -10
- package/dist/types/core/util/ActionUtil.d.ts +0 -35
- package/dist/types/core/util/ActionUtil.d.ts.map +0 -10
- package/dist/types/core/util/DataUtil.d.ts +0 -52
- package/dist/types/core/util/DataUtil.d.ts.map +0 -10
- package/dist/types/core/util/FDUtil.d.ts +0 -171
- package/dist/types/core/util/FDUtil.d.ts.map +0 -10
- package/dist/types/core/util/ModuleUtil.d.ts +0 -27
- package/dist/types/core/util/ModuleUtil.d.ts.map +0 -10
- package/dist/types/core/util/StringUtil.d.ts +0 -5
- package/dist/types/core/util/StringUtil.d.ts.map +0 -10
- package/dist/types/core/util/TypeSpec.d.ts +0 -42
- package/dist/types/core/util/TypeSpec.d.ts.map +0 -10
- package/dist/types/core/util/ValidUtil.d.ts +0 -29
- package/dist/types/core/util/ValidUtil.d.ts.map +0 -10
- package/src/core/ActionManager.js +0 -147
- package/src/core/ContractManager.js +0 -112
- package/src/core/Conveyor.js +0 -185
- package/src/core/Core.js +0 -166
- package/src/core/Discovery.js +0 -403
- package/src/core/HookManager.js +0 -143
- package/src/core/action/ParseManager.js +0 -7
- package/src/core/action/PrintManager.js +0 -7
- package/src/core/contract/ParseContract.js +0 -7
- package/src/core/contract/PrintContract.js +0 -7
- package/src/core/util/ActionUtil.js +0 -62
- package/src/core/util/ContractUtil.js +0 -63
- package/src/core/util/DataUtil.js +0 -540
- package/src/core/util/FDUtil.js +0 -388
- package/src/core/util/StringUtil.js +0 -11
- package/src/core/util/TypeSpec.js +0 -114
- package/src/core/util/ValidUtil.js +0 -50
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import {HookPoints} from "./HookManager.js"
|
|
2
|
-
|
|
3
|
-
export default class ActionManager {
|
|
4
|
-
#action = null
|
|
5
|
-
#hookManager = null
|
|
6
|
-
#contract
|
|
7
|
-
#log
|
|
8
|
-
#debug
|
|
9
|
-
#file
|
|
10
|
-
#variables
|
|
11
|
-
|
|
12
|
-
constructor({actionDefinition, logger, variables}) {
|
|
13
|
-
this.#log = logger
|
|
14
|
-
this.#debug = this.#log.newDebug()
|
|
15
|
-
this.#variables = variables
|
|
16
|
-
|
|
17
|
-
this.#initialize(actionDefinition)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
#initialize(actionDefinition) {
|
|
21
|
-
const debug = this.#debug
|
|
22
|
-
|
|
23
|
-
debug("Setting up action", 2)
|
|
24
|
-
|
|
25
|
-
const {action, file, contract} = actionDefinition
|
|
26
|
-
|
|
27
|
-
if(!action)
|
|
28
|
-
throw new Error("Action is required")
|
|
29
|
-
|
|
30
|
-
if(!contract)
|
|
31
|
-
throw new Error("Contract is required")
|
|
32
|
-
|
|
33
|
-
this.#action = action
|
|
34
|
-
this.#contract = contract
|
|
35
|
-
this.#file = file
|
|
36
|
-
|
|
37
|
-
debug("Action setup complete", 2)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get action() {
|
|
41
|
-
return this.#action
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get hookManager() {
|
|
45
|
-
return this.#hookManager
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
set hookManager(hookManager) {
|
|
49
|
-
if(this.hookManager)
|
|
50
|
-
throw new Error("Hooks already set")
|
|
51
|
-
|
|
52
|
-
this.action.hook = hookManager.on.bind(this.action)
|
|
53
|
-
this.action.HOOKS = HookPoints
|
|
54
|
-
this.#hookManager = hookManager
|
|
55
|
-
this.action.hooks = hookManager.hooks
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
get contract() {
|
|
59
|
-
return this.#contract
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
get meta() {
|
|
63
|
-
return this.#action.meta
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
get log() {
|
|
67
|
-
return this.#log
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
get variables() {
|
|
71
|
-
return this.#variables
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async #setupAction() {
|
|
75
|
-
const setup = this.action?.setup
|
|
76
|
-
|
|
77
|
-
if(!setup)
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
await this.action.setup.call(this.action, {log: this.#log})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async #cleanupAction() {
|
|
84
|
-
const cleanup = this.action?.cleanup
|
|
85
|
-
|
|
86
|
-
if(!cleanup)
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
await this.action.cleanup.call(this.action)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async #setupHooks() {
|
|
93
|
-
const setup = this.hookManager?.setup
|
|
94
|
-
|
|
95
|
-
if(!setup)
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
await this.hookManager.setup.call(
|
|
99
|
-
this.hookManager.hooks, {
|
|
100
|
-
action: this.action,
|
|
101
|
-
variables: this.#variables,
|
|
102
|
-
log: this.#log
|
|
103
|
-
}
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async #cleanupHooks() {
|
|
108
|
-
const cleanup = this.hookManager?.cleanup
|
|
109
|
-
|
|
110
|
-
if(!cleanup)
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
await this.hookManager.cleanup.call(this.hookManager.hooks)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async setupAction() {
|
|
117
|
-
this.#debug("Setting up action for %s", 2, this.meta.action)
|
|
118
|
-
|
|
119
|
-
await this.#setupHooks()
|
|
120
|
-
await this.#setupAction()
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async runAction({file,content}) {
|
|
124
|
-
const func = this.action.run
|
|
125
|
-
|
|
126
|
-
if(!func)
|
|
127
|
-
throw new Error(`No \`run\` function found for action \`${this.meta.action}\``)
|
|
128
|
-
|
|
129
|
-
const actionResult = await func.call(
|
|
130
|
-
this.action, {file, moduleContent: content}
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
return actionResult
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async cleanupAction() {
|
|
137
|
-
this.#debug("Post action", 2)
|
|
138
|
-
this.#debug("Cleaning up action for %s", 2, this.meta.action)
|
|
139
|
-
|
|
140
|
-
await this.#cleanupHooks()
|
|
141
|
-
await this.#cleanupAction()
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
toString() {
|
|
145
|
-
return `${this.#file?.module || "UNDEFINED"} (${this.meta?.action || "UNDEFINED"})`
|
|
146
|
-
}
|
|
147
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import yaml from "yaml"
|
|
2
|
-
import JSON5 from "json5"
|
|
3
|
-
|
|
4
|
-
import * as FDUtil from "./util/FDUtil.js"
|
|
5
|
-
import * as ContractUtil from "./util/ContractUtil.js"
|
|
6
|
-
import * as DataUtil from "./util/DataUtil.js"
|
|
7
|
-
|
|
8
|
-
const {resolveFilename, readFile} = FDUtil
|
|
9
|
-
const {loadSchema, getValidator} = ContractUtil
|
|
10
|
-
const {findClosestMatch} = DataUtil
|
|
11
|
-
|
|
12
|
-
const refex = /^ref:\/\/(.*)$/
|
|
13
|
-
|
|
14
|
-
export default class ContractManager {
|
|
15
|
-
static async newContract(actionType, terms) {
|
|
16
|
-
// Load and validate against the BeDoc contract schema
|
|
17
|
-
const schema = await loadSchema()
|
|
18
|
-
const validator = getValidator(schema)
|
|
19
|
-
const valid = validator(terms)
|
|
20
|
-
|
|
21
|
-
if(!valid) {
|
|
22
|
-
const error = ContractManager.reportValidationErrors(validator.errors)
|
|
23
|
-
|
|
24
|
-
throw new Error(`Invalid contract terms:\n${error}`)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const dataValidator = getValidator({
|
|
28
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
29
|
-
"$id": `${actionType} Schema`,
|
|
30
|
-
title: `${actionType} Schema`,
|
|
31
|
-
type: "object",
|
|
32
|
-
properties: terms,
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
return new Contract(dataValidator)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static parse(contractData, directoryObject) {
|
|
39
|
-
if(typeof contractData === "string") {
|
|
40
|
-
const match = refex.exec(contractData)
|
|
41
|
-
|
|
42
|
-
if(match)
|
|
43
|
-
contractData = readFile(resolveFilename(match[1], directoryObject))
|
|
44
|
-
|
|
45
|
-
return yaml.parse(String(contractData))
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
throw new Error(`Invalid contract data: ${JSON5.stringify(contractData)}`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
static reportValidationErrors(errors) {
|
|
52
|
-
return errors.reduce((acc, error) => {
|
|
53
|
-
let msg = `- "${error.instancePath || "(root)"}" ${error.message}`
|
|
54
|
-
|
|
55
|
-
if(error.params) {
|
|
56
|
-
const details = []
|
|
57
|
-
|
|
58
|
-
if(error.params.type)
|
|
59
|
-
details.push(` ➜ Expected type: ${error.params.type}`)
|
|
60
|
-
|
|
61
|
-
if(error.params.missingProperty)
|
|
62
|
-
details.push(` ➜ Missing required field: ${error.params.missingProperty}`)
|
|
63
|
-
|
|
64
|
-
if(error.params.allowedValues) {
|
|
65
|
-
details.push(` ➜ Allowed values: "${error.params.allowedValues.join('", "')}"`)
|
|
66
|
-
details.push(` ➜ Received value: "${error.data}"`)
|
|
67
|
-
const closestMatch =
|
|
68
|
-
findClosestMatch(error.data, error.params.allowedValues)
|
|
69
|
-
if(closestMatch)
|
|
70
|
-
details.push(` ➜ Did you mean: "${closestMatch}"?`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if(error.params.pattern)
|
|
74
|
-
details.push(` ➜ Expected pattern: ${error.params.pattern}`)
|
|
75
|
-
|
|
76
|
-
if(error.params.format)
|
|
77
|
-
details.push(` ➜ Expected format: ${error.params.format}`)
|
|
78
|
-
|
|
79
|
-
if(error.params.additionalProperty)
|
|
80
|
-
details.push(` ➜ Unexpected property: ${error.params.additionalProperty}`)
|
|
81
|
-
|
|
82
|
-
if(details.length)
|
|
83
|
-
msg += `\n${details.join("\n")}`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return acc ? `${acc}\n${msg}` : msg
|
|
87
|
-
}, "")
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
class Contract {
|
|
92
|
-
#validator = null
|
|
93
|
-
|
|
94
|
-
constructor(validator) {
|
|
95
|
-
this.#validator = validator
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
get validator() {
|
|
99
|
-
return this.#validator
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
validate(data) {
|
|
103
|
-
const validator = this.validator
|
|
104
|
-
const valid = validator(data)
|
|
105
|
-
|
|
106
|
-
if(!valid) {
|
|
107
|
-
const error = ContractManager.reportValidationErrors(validator.errors)
|
|
108
|
-
|
|
109
|
-
throw new Error(`This document violates the agreed upon contract:\n${error}`)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
package/src/core/Conveyor.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import {format} from "node:util"
|
|
2
|
-
|
|
3
|
-
import * as FDUtil from "./util/FDUtil.js"
|
|
4
|
-
|
|
5
|
-
const {readFile, writeFile, composeFilename} = FDUtil
|
|
6
|
-
|
|
7
|
-
export default class Conveyor {
|
|
8
|
-
#succeeded = []
|
|
9
|
-
#warned = []
|
|
10
|
-
#errored = []
|
|
11
|
-
|
|
12
|
-
constructor(parse, print, logger, output) {
|
|
13
|
-
this.parse = parse
|
|
14
|
-
this.print = print
|
|
15
|
-
this.logger = logger
|
|
16
|
-
this.output = output
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Processes files with a concurrency limit.
|
|
21
|
-
*
|
|
22
|
-
* @param {Array} files - List of files to process.
|
|
23
|
-
* @param {number} maxConcurrent - Maximum number of concurrent tasks.
|
|
24
|
-
* @returns {Promise<object>} - Resolves when all files are processed.
|
|
25
|
-
*/
|
|
26
|
-
async convey(files, maxConcurrent = 10) {
|
|
27
|
-
const fileQueue = [...files]
|
|
28
|
-
const activePromises = []
|
|
29
|
-
|
|
30
|
-
await Promise.all([
|
|
31
|
-
this.parse.setupAction(),
|
|
32
|
-
this.print.setupAction()
|
|
33
|
-
])
|
|
34
|
-
|
|
35
|
-
const processNextFile = file => {
|
|
36
|
-
return this.#processFile(file).then(processedResult => {
|
|
37
|
-
// Store result
|
|
38
|
-
if(processedResult.status === "success") {
|
|
39
|
-
this.#succeeded.push({input: file, output: processedResult.file})
|
|
40
|
-
} else if(processedResult.status === "warning") {
|
|
41
|
-
this.#warned.push({input: file, warning: processedResult.warning})
|
|
42
|
-
} else {
|
|
43
|
-
this.#errored.push({input: file, error: processedResult.error})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Start next job if queue isn't empty
|
|
47
|
-
if(fileQueue.length > 0) {
|
|
48
|
-
const nextFile = fileQueue.shift()
|
|
49
|
-
return processNextFile(nextFile)
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Initial fill of the worker pool
|
|
55
|
-
while(activePromises.length < maxConcurrent && fileQueue.length > 0) {
|
|
56
|
-
const file = fileQueue.shift()
|
|
57
|
-
activePromises.push(processNextFile(file))
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Wait for all processing to complete
|
|
61
|
-
await Promise.all(activePromises)
|
|
62
|
-
|
|
63
|
-
await Promise.all([
|
|
64
|
-
this.parse.cleanupAction(),
|
|
65
|
-
this.print.cleanupAction()
|
|
66
|
-
])
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
succeeded: this.#succeeded,
|
|
70
|
-
errored: this.#errored,
|
|
71
|
-
warned: this.#warned
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Processes a single file.
|
|
77
|
-
*
|
|
78
|
-
* @param {object} file - FileMap object representing a file.
|
|
79
|
-
* @returns {Promise<object>} - Resolves when the file is processed
|
|
80
|
-
*/
|
|
81
|
-
async #processFile(file) {
|
|
82
|
-
const debug = this.logger.newDebug()
|
|
83
|
-
const {parse, print} = this
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
debug("Processing file: %o", 2, file.path)
|
|
87
|
-
|
|
88
|
-
// Step 1: Read file
|
|
89
|
-
const fileContent = readFile(file)
|
|
90
|
-
debug("Read file content %o (%o bytes)", 2, file.path, fileContent.length)
|
|
91
|
-
|
|
92
|
-
// Step 2: Parse file
|
|
93
|
-
const parseResult = await parse.runAction({
|
|
94
|
-
file,
|
|
95
|
-
content: fileContent
|
|
96
|
-
})
|
|
97
|
-
if(parseResult.status === "error")
|
|
98
|
-
return parseResult
|
|
99
|
-
|
|
100
|
-
if(parseResult.status === "warning")
|
|
101
|
-
debug("Parsed file successfully, but with warnings: %o", 2, file.path)
|
|
102
|
-
else
|
|
103
|
-
debug("Parsed file successfully: %o", 2, file.path)
|
|
104
|
-
|
|
105
|
-
if(!parseResult.result) {
|
|
106
|
-
const mess = format("No content found in %o. No file written.", file.path)
|
|
107
|
-
return {status: "warning", file, warning: mess}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
parse.contract.validate(parseResult)
|
|
111
|
-
print.contract.validate(parseResult)
|
|
112
|
-
|
|
113
|
-
// Step 3: Print file
|
|
114
|
-
const printResult = await print.runAction({
|
|
115
|
-
file,
|
|
116
|
-
content: parseResult.result,
|
|
117
|
-
})
|
|
118
|
-
if(printResult.status === "error")
|
|
119
|
-
return printResult
|
|
120
|
-
|
|
121
|
-
debug("Printed file successfully: %o", 2, file.path)
|
|
122
|
-
|
|
123
|
-
// Step 4: Write output
|
|
124
|
-
const {status: printStatus, destFile, destContent} = printResult
|
|
125
|
-
const isNullish = value => value == null // Checks null or undefined
|
|
126
|
-
|
|
127
|
-
switch(printStatus) {
|
|
128
|
-
case "warning":
|
|
129
|
-
case "error":
|
|
130
|
-
return printResult
|
|
131
|
-
case "success":
|
|
132
|
-
if(isNullish(destFile) || isNullish(destContent))
|
|
133
|
-
return {
|
|
134
|
-
status: "warning",
|
|
135
|
-
warning: format("No content or destination file for %o", file.path)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
break
|
|
139
|
-
default:
|
|
140
|
-
throw new Error(`Invalid status received from printing ${file.module}`)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if(this.output) {
|
|
144
|
-
const writeResult = await this.#writeOutput(destFile, destContent)
|
|
145
|
-
|
|
146
|
-
if(writeResult.status === "success")
|
|
147
|
-
debug("Wrote output %o (%o bytes)", 2, writeResult.file.path, destContent.length)
|
|
148
|
-
else
|
|
149
|
-
debug("Error writing output for: `%s`", 2, file.path)
|
|
150
|
-
|
|
151
|
-
return writeResult
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
debug("Output not specified. Writing skipped.", 2)
|
|
155
|
-
|
|
156
|
-
return {status: "success"}
|
|
157
|
-
|
|
158
|
-
} catch(error) {
|
|
159
|
-
return {status: "error", file, error}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Writes the output to the destination.
|
|
165
|
-
*
|
|
166
|
-
* @param {string} destFile - Destination file path.
|
|
167
|
-
* @param {string} destContent - File content.
|
|
168
|
-
* @returns {Promise<object>} - Resolves when the file is written.
|
|
169
|
-
*/
|
|
170
|
-
async #writeOutput(destFile, destContent) {
|
|
171
|
-
const debug = this.logger.newDebug()
|
|
172
|
-
|
|
173
|
-
const destFileMap = composeFilename(this.output.path, destFile)
|
|
174
|
-
|
|
175
|
-
debug("Writing output to %o => %o", 2, destFile, destFileMap.absolutePath)
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
writeFile(destFileMap, destContent)
|
|
179
|
-
|
|
180
|
-
return {status: "success", file: destFileMap}
|
|
181
|
-
} catch(error) {
|
|
182
|
-
return {status: "error", output: destFileMap, error}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
package/src/core/Core.js
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import {hrtime} from "node:process"
|
|
2
|
-
|
|
3
|
-
import Discovery from "./Discovery.js"
|
|
4
|
-
import HookManager from "./HookManager.js"
|
|
5
|
-
import Logger from "./Logger.js"
|
|
6
|
-
import ParseManager from "./action/ParseManager.js"
|
|
7
|
-
import PrintManager from "./action/PrintManager.js"
|
|
8
|
-
import Conveyor from "./Conveyor.js"
|
|
9
|
-
import Configuration from "./Configuration.js"
|
|
10
|
-
|
|
11
|
-
import * as ActionUtil from "./util/ActionUtil.js"
|
|
12
|
-
import * as DataUtil from "./util/DataUtil.js"
|
|
13
|
-
import * as FDUtil from "./util/FDUtil.js"
|
|
14
|
-
|
|
15
|
-
const {loadPackageJson} = ActionUtil
|
|
16
|
-
const {schemaCompare} = DataUtil
|
|
17
|
-
const {getFiles} = FDUtil
|
|
18
|
-
|
|
19
|
-
export const Environment = Object.freeze({
|
|
20
|
-
EXTENSION: "extension",
|
|
21
|
-
NPM: "npm",
|
|
22
|
-
ACTION: "action",
|
|
23
|
-
CLI: "cli",
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
export default class Core {
|
|
27
|
-
constructor(options) {
|
|
28
|
-
this.options = options
|
|
29
|
-
const {debug: debugMode, debugLevel} = options
|
|
30
|
-
this.logger = new Logger({name: "BeDoc", debugMode, debugLevel})
|
|
31
|
-
this.packageJson = loadPackageJson(options.basePath)?.bedoc ?? {}
|
|
32
|
-
this.debugOptions = this.logger.options
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static async new({options, source}) {
|
|
36
|
-
const config = new Configuration()
|
|
37
|
-
|
|
38
|
-
const validConfig = await config.validate({options, source})
|
|
39
|
-
if(validConfig.status === "error")
|
|
40
|
-
throw new AggregateError(validConfig.errors,"BeDoc configuration failed")
|
|
41
|
-
|
|
42
|
-
const instance = new Core({...validConfig, name: "BeDoc"})
|
|
43
|
-
const debug = instance.logger.newDebug()
|
|
44
|
-
|
|
45
|
-
debug("Creating new BeDoc instance with options: `%o`", 3, validConfig)
|
|
46
|
-
|
|
47
|
-
const discovery = new Discovery(instance)
|
|
48
|
-
const actionDefs = await discovery.discoverActions({
|
|
49
|
-
print: validConfig.printer,
|
|
50
|
-
parse: validConfig.parser
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const validCrit = discovery.satisfyCriteria(actionDefs, validConfig)
|
|
54
|
-
|
|
55
|
-
debug("Actions that met criteria: `%o`", 3, validCrit)
|
|
56
|
-
|
|
57
|
-
if(Object.values(validCrit).some(arr => arr.length === 0))
|
|
58
|
-
throw new Error("No found matching parser and printer")
|
|
59
|
-
|
|
60
|
-
const validSchemas = {print: [], parse: []}
|
|
61
|
-
let printers = validCrit.print.length
|
|
62
|
-
while(printers--) {
|
|
63
|
-
const printer = validCrit.print[printers]
|
|
64
|
-
const printerSchema = printer.contract
|
|
65
|
-
const satisfied = []
|
|
66
|
-
|
|
67
|
-
for(const parser of validCrit.parse) {
|
|
68
|
-
const parserSchema = parser.contract
|
|
69
|
-
const result = schemaCompare(parserSchema, printerSchema)
|
|
70
|
-
if(result.status === "success")
|
|
71
|
-
satisfied.push(parser)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if(satisfied.length > 0) {
|
|
75
|
-
validSchemas.print.push(printer)
|
|
76
|
-
validSchemas.parse.push(...satisfied)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const finalActions = {}
|
|
81
|
-
for(const [key, value] of Object.entries(validSchemas)) {
|
|
82
|
-
if(value.length === 0)
|
|
83
|
-
throw new Error(`No matching ${key} found`)
|
|
84
|
-
|
|
85
|
-
if(value.length > 1)
|
|
86
|
-
throw new Error(`Multiple matching ${key} found`)
|
|
87
|
-
|
|
88
|
-
finalActions[key] = validSchemas[key][0]
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
debug("Contracts satisfied between parser and printer", 2)
|
|
92
|
-
|
|
93
|
-
// Adding to instance
|
|
94
|
-
instance.actions = {}
|
|
95
|
-
const {variables} = validConfig
|
|
96
|
-
const managers = {print: PrintManager, parse: ParseManager}
|
|
97
|
-
for(const [, actionDefinition] of Object.entries(finalActions)) {
|
|
98
|
-
const {action: actionType} = actionDefinition.action.meta
|
|
99
|
-
|
|
100
|
-
debug("Attaching %o action to instance", 2, actionType)
|
|
101
|
-
instance.actions[actionType] =
|
|
102
|
-
new managers[actionType] ({
|
|
103
|
-
actionDefinition,
|
|
104
|
-
logger: instance.logger,
|
|
105
|
-
variables
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
if(validConfig.hooks) {
|
|
109
|
-
const hookManager = await HookManager.new({
|
|
110
|
-
action: actionType,
|
|
111
|
-
hooksFile: validConfig.hooks,
|
|
112
|
-
logger: new Logger(instance.debugOptions),
|
|
113
|
-
timeout: validConfig.hooksTimeout,
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
if(hookManager)
|
|
117
|
-
instance.actions[actionType].hookManager = hookManager
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return instance
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async processFiles(glob) {
|
|
125
|
-
const debug = this.logger.newDebug()
|
|
126
|
-
|
|
127
|
-
debug("Starting file processing with conveyor", 1)
|
|
128
|
-
|
|
129
|
-
const {output} = this.options
|
|
130
|
-
|
|
131
|
-
const input = await getFiles(glob)
|
|
132
|
-
if(!input?.length)
|
|
133
|
-
throw new Error("No input files specified")
|
|
134
|
-
|
|
135
|
-
// Instantiate the conveyor
|
|
136
|
-
const conveyor = new Conveyor(
|
|
137
|
-
this.actions.parse,
|
|
138
|
-
this.actions.print,
|
|
139
|
-
this.logger,
|
|
140
|
-
output,
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
const processStart = hrtime.bigint()
|
|
144
|
-
|
|
145
|
-
// Initiate the conveyor
|
|
146
|
-
const processResult = await conveyor.convey(
|
|
147
|
-
input, this.options.maxConcurrent
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
debug("Conveyor complete", 1)
|
|
151
|
-
|
|
152
|
-
const processEnd = hrtime.bigint()
|
|
153
|
-
|
|
154
|
-
const result = {
|
|
155
|
-
totalFiles: input.length,
|
|
156
|
-
succeeded: processResult.succeeded,
|
|
157
|
-
warned: processResult.warned,
|
|
158
|
-
errored: processResult.errored,
|
|
159
|
-
duration: ((Number(processEnd - processStart)) / 1_000_000).toFixed(2)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
debug("File processing complete", 1)
|
|
163
|
-
|
|
164
|
-
return result
|
|
165
|
-
}
|
|
166
|
-
}
|