@gesslar/bedoc 1.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.
@@ -0,0 +1,191 @@
1
+ /*
2
+ For formatting console info, see:
3
+ https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args
4
+
5
+ * %s: String will be used to convert all values except BigInt, Object and -0.
6
+ BigInt values will be represented with an n and Objects that have no
7
+ user defined toString function are inspected using util.inspect() with
8
+ options { depth: 0, colors: false, compact: 3 }.
9
+ * %d: Number will be used to convert all values except BigInt and Symbol.
10
+ * %i: parseInt(value, 10) is used for all values except BigInt and Symbol.
11
+ * %f: parseFloat(value) is used for all values expect Symbol.
12
+ * %j: JSON. Replaced with the string '[Circular]' if the argument contains
13
+ circular references.
14
+ * %o: Object. A string representation of an object with generic JavaScript
15
+ object formatting. Similar to util.inspect() with options { showHidden:
16
+ true, showProxy: true }. This will show the full object including non-
17
+ enumerable properties and proxies.
18
+ * %O: Object. A string representation of an object with generic JavaScript
19
+ object formatting. Similar to util.inspect() without options. This will
20
+ show the full object not including non-enumerable properties and
21
+ proxies.
22
+ * %%: single percent sign ('%'). This does not consume an argument.
23
+
24
+ */
25
+
26
+ import console from "node:console"
27
+ import ErrorStackParser from "error-stack-parser"
28
+
29
+ import {Environment} from "./Core.js"
30
+
31
+ import * as FDUtil from "./util/FDUtil.js"
32
+ import * as StringUtil from "./util/StringUtil.js"
33
+
34
+ const {resolveFilename} = FDUtil
35
+ const {capitalize} = StringUtil
36
+
37
+ const loggerColours = {
38
+ debug: [
39
+ "\x1b[38;5;19m", // Debug level 0: Dark blue
40
+ "\x1b[38;5;27m", // Debug level 1: Medium blue
41
+ "\x1b[38;5;33m", // Debug level 2: Light blue
42
+ "\x1b[38;5;39m", // Debug level 3: Teal
43
+ "\x1b[38;5;44m", // Debug level 4: Blue-tinted cyan
44
+ ],
45
+ info: "\x1b[38;5;36m", // Medium Spring Green
46
+ warn: "\x1b[38;5;214m", // Orange1
47
+ error: "\x1b[38;5;196m", // Red1
48
+ reset: "\x1b[0m", // Reset
49
+ }
50
+
51
+ /**
52
+ * Logger class
53
+ *
54
+ * Log levels:
55
+ * - debug: Debugging information
56
+ * - Debug levels
57
+ * - 0: No/critical debug information, not error level, but, should be
58
+ * logged
59
+ * - 1: Basic debug information, startup, shutdown, etc
60
+ * - 2: Intermediate debug information, discovery, starting to get more
61
+ * detailed
62
+ * - 3: Detailed debug information, parsing, processing, etc
63
+ * - 4: Very detailed debug information, nerd mode!
64
+ * - warn: Warning information
65
+ * - info: Informational information
66
+ * - error: Error information
67
+ */
68
+
69
+ export default class Logger {
70
+ #name = null
71
+ #debugMode = false
72
+ #debugLevel = 0
73
+
74
+ constructor(options) {
75
+ this.#name = "BeDoc"
76
+ if(options) {
77
+ this.setOptions(options)
78
+ if(options.env === Environment.EXTENSION) {
79
+ const vscode = import("vscode")
80
+ this.vscodeError = vscode.window.showErrorMessage
81
+ this.vscodeWarn = vscode.window.showWarningMessage
82
+ this.vscodeInfo = vscode.window.showInformationMessage
83
+ }
84
+ }
85
+ }
86
+
87
+ get name() {
88
+ return this.#name
89
+ }
90
+
91
+ get debugMode() {
92
+ return this.#debugMode
93
+ }
94
+
95
+ get debugLevel() {
96
+ return this.#debugLevel
97
+ }
98
+
99
+ get options() {
100
+ return {
101
+ name: this.#name,
102
+ debugMode: this.#debugMode,
103
+ debugLevel: this.#debugLevel,
104
+ }
105
+ }
106
+
107
+ setOptions(options) {
108
+ this.#name = options.name ?? this.#name
109
+ this.#debugMode = options.debugMode
110
+ this.#debugLevel = options.debugLevel
111
+ }
112
+
113
+ #compose(level, message, debugLevel = 0) {
114
+ const tag = capitalize(level)
115
+
116
+ if(level === "debug")
117
+ return `[${this.#name}] ${loggerColours[level][debugLevel]}${tag}${loggerColours.reset}: ${message}`
118
+
119
+ return `[${this.#name}] ${loggerColours[level]}${tag}${loggerColours.reset}: ${message}`
120
+ }
121
+
122
+ lastStackLine(stepsRemoved = 3) {
123
+ const stack = ErrorStackParser.parse(new Error())
124
+ return stack[stepsRemoved]
125
+ }
126
+
127
+ extractFileFunction(level = 0) {
128
+ const frame = this.lastStackLine()
129
+ const {
130
+ functionName: func,
131
+ fileName: file,
132
+ lineNumber: line,
133
+ columnNumber: col,
134
+ } = frame
135
+
136
+ const {module, absoluteUri} = resolveFilename(file)
137
+
138
+ let functionName = func ?? "anonymous"
139
+ if(functionName.startsWith("#"))
140
+ functionName = `${module}.${functionName}`
141
+
142
+ const methodName = /\[as \w+\]$/.test(functionName)
143
+ ? /\[as (\w+)\]/.exec(functionName)[1]
144
+ : null
145
+
146
+ if(methodName) {
147
+ functionName = functionName.replace(/\[as \w+\]$/, "")
148
+ functionName = `${functionName}{${methodName}}`
149
+ }
150
+
151
+ if(/^async /.test(functionName))
152
+ functionName = functionName.replace(/^async /, "(async)")
153
+
154
+ let result = functionName
155
+
156
+ if(level >= 2)
157
+ result = `${result}:${line}:${col}`
158
+
159
+ if(level >= 3)
160
+ result = `${absoluteUri} ${result}`
161
+
162
+ return result
163
+ }
164
+
165
+ newDebug(tag) {
166
+ return function(message, level, ...arg) {
167
+ tag = this.extractFileFunction(this.#debugLevel)
168
+ this.debug(`[${tag}] ${message}`, level, ...arg)
169
+ }.bind(this)
170
+ }
171
+
172
+ debug(message, level = 0, ...arg) {
173
+ if(this.debugMode === true && level <= (this.debugLevel ?? 4))
174
+ console.debug(this.#compose("debug", message, level), ...arg)
175
+ }
176
+
177
+ warn(message, ...arg) {
178
+ console.warn(this.#compose("warn", message), ...arg)
179
+ this.vscodeWarn?.(JSON.stringify(message))
180
+ }
181
+
182
+ info(message, ...arg) {
183
+ console.info(this.#compose("info", message), ...arg)
184
+ this.vscodeInfo?.(JSON.stringify(message))
185
+ }
186
+
187
+ error(message, ...arg) {
188
+ console.error(this.#compose("error", message), ...arg)
189
+ this.vscodeError?.(JSON.stringify(message))
190
+ }
191
+ }
@@ -0,0 +1,26 @@
1
+ import ActionManager from "../ActionManager.js"
2
+
3
+ export default class ParseManager extends ActionManager {
4
+ constructor(actionDefinition, logger) {
5
+ super(actionDefinition, logger)
6
+ }
7
+
8
+ async parse(fileMap, content) {
9
+ const log = this.log
10
+ const debug = log.newDebug()
11
+
12
+ debug("Parsing file `%j`", 3, fileMap)
13
+
14
+ if(this.action.init)
15
+ this.action.init({parent: this, log})
16
+
17
+ if(!this.action.parse)
18
+ throw new Error(`No parse function found for action: ${this.module}`)
19
+
20
+ const result = await this.action.parse(fileMap.path, content)
21
+
22
+ debug("Parse complete of file `%j`", 3, fileMap)
23
+
24
+ return result
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ import ActionManager from "../ActionManager.js"
2
+
3
+ export default class PrintManager extends ActionManager {
4
+ constructor(actionDefinition, logger) {
5
+ super(actionDefinition, logger)
6
+ }
7
+
8
+ async print(fileMap, content) {
9
+ const log = this.log
10
+ const debug = log.newDebug()
11
+
12
+ debug("Printing data for `%s`", 3, fileMap.module)
13
+
14
+ if(this.action.init)
15
+ this.action.init({parent: this, log})
16
+
17
+ if(!this.action.print)
18
+ throw new Error(`No print function found for action: ${this.module}`)
19
+
20
+ const result = await this.action.print(fileMap.module, content)
21
+
22
+ debug("Print complete for `%s`", 3, fileMap.module)
23
+
24
+ return result
25
+ }
26
+ }
@@ -0,0 +1,47 @@
1
+ import * as FDUtil from "./FDUtil.js"
2
+
3
+ const {readFile, resolveFilename} = FDUtil
4
+
5
+ const freeze = Object.freeze
6
+
7
+ const actionTypes = freeze(["parse", "print"])
8
+
9
+ const actionMetaRequirements = freeze({
10
+ parse: [{action: "parse"}, "language"],
11
+ print: [{action: "print"}, "format"],
12
+ })
13
+
14
+ /**
15
+ * Loads a JSON file asynchronously
16
+ *
17
+ * @param {object} jsonFileObject - The JSON file to load
18
+ * @returns {object} The parsed JSON content
19
+ */
20
+ function loadJson(jsonFileObject) {
21
+ // Read the file
22
+ const jsonContent = readFile(jsonFileObject)
23
+ const json = JSON.parse(jsonContent)
24
+ return json
25
+ }
26
+
27
+ /**
28
+ * Loads the package.json file asynchronously
29
+ *
30
+ * @param {string|object} basePath - The base path to use
31
+ * @returns {object} The parsed package.json content
32
+ */
33
+ function loadPackageJson(basePath = null) {
34
+ const packageJsonFileObject = resolveFilename("./package.json", basePath)
35
+ const jsonContent = readFile(packageJsonFileObject)
36
+ const json = JSON.parse(jsonContent)
37
+ return json
38
+ }
39
+
40
+ export {
41
+ // Constants
42
+ actionMetaRequirements,
43
+ actionTypes,
44
+ // Functions
45
+ loadJson,
46
+ loadPackageJson,
47
+ }