@gesslar/bedoc 1.11.0 → 2.1.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 (88) hide show
  1. package/LICENSE.txt +12 -0
  2. package/README.md +15 -3
  3. package/dist/schema/bedoc.action.json +42 -0
  4. package/dist/types/Action.d.ts +3 -0
  5. package/dist/types/Action.d.ts.map +1 -0
  6. package/dist/types/BeDoc.d.ts +208 -0
  7. package/dist/types/BeDoc.d.ts.map +1 -0
  8. package/dist/types/Configuration.d.ts +11 -0
  9. package/dist/types/Configuration.d.ts.map +1 -0
  10. package/dist/types/ConfigurationParameters.d.ts +3 -0
  11. package/dist/types/ConfigurationParameters.d.ts.map +1 -0
  12. package/dist/types/Conveyor.d.ts +27 -0
  13. package/dist/types/Conveyor.d.ts.map +1 -0
  14. package/dist/types/Discovery.d.ts +215 -0
  15. package/dist/types/Discovery.d.ts.map +1 -0
  16. package/dist/types/Environment.d.ts +3 -0
  17. package/dist/types/Environment.d.ts.map +1 -0
  18. package/dist/types/Logger.d.ts +47 -0
  19. package/dist/types/Logger.d.ts.map +1 -0
  20. package/dist/types/Schema.d.ts +3 -0
  21. package/dist/types/Schema.d.ts.map +1 -0
  22. package/dist/types/cli.d.ts +2 -2
  23. package/dist/types/cli.d.ts.map +1 -10
  24. package/package.json +24 -23
  25. package/src/Action.js +9 -0
  26. package/src/BeDoc.js +304 -0
  27. package/src/CLIOutput.js +198 -0
  28. package/src/{core/Configuration.js → Configuration.js} +73 -58
  29. package/src/{core/ConfigurationParameters.js → ConfigurationParameters.js} +35 -27
  30. package/src/Conveyor.js +256 -0
  31. package/src/Discovery.js +442 -0
  32. package/src/Environment.js +8 -0
  33. package/src/{core/Logger.js → Logger.js} +30 -18
  34. package/src/Schema.js +6 -0
  35. package/src/cli.js +86 -38
  36. package/tsconfig.types.json +42 -0
  37. package/LICENSE +0 -24
  38. package/dist/types/core/ActionManager.d.ts +0 -58
  39. package/dist/types/core/ActionManager.d.ts.map +0 -10
  40. package/dist/types/core/Configuration.d.ts +0 -27
  41. package/dist/types/core/Configuration.d.ts.map +0 -10
  42. package/dist/types/core/ConfigurationParameters.d.ts +0 -38
  43. package/dist/types/core/ConfigurationParameters.d.ts.map +0 -10
  44. package/dist/types/core/Conveyor.d.ts +0 -49
  45. package/dist/types/core/Conveyor.d.ts.map +0 -10
  46. package/dist/types/core/Core.d.ts +0 -48
  47. package/dist/types/core/Core.d.ts.map +0 -10
  48. package/dist/types/core/Discovery.d.ts +0 -73
  49. package/dist/types/core/Discovery.d.ts.map +0 -10
  50. package/dist/types/core/HookManager.d.ts +0 -60
  51. package/dist/types/core/HookManager.d.ts.map +0 -10
  52. package/dist/types/core/Logger.d.ts +0 -63
  53. package/dist/types/core/Logger.d.ts.map +0 -10
  54. package/dist/types/core/action/ParseManager.d.ts +0 -8
  55. package/dist/types/core/action/ParseManager.d.ts.map +0 -10
  56. package/dist/types/core/action/PrintManager.d.ts +0 -8
  57. package/dist/types/core/action/PrintManager.d.ts.map +0 -10
  58. package/dist/types/core/util/ActionUtil.d.ts +0 -35
  59. package/dist/types/core/util/ActionUtil.d.ts.map +0 -10
  60. package/dist/types/core/util/DataUtil.d.ts +0 -52
  61. package/dist/types/core/util/DataUtil.d.ts.map +0 -10
  62. package/dist/types/core/util/FDUtil.d.ts +0 -171
  63. package/dist/types/core/util/FDUtil.d.ts.map +0 -10
  64. package/dist/types/core/util/ModuleUtil.d.ts +0 -27
  65. package/dist/types/core/util/ModuleUtil.d.ts.map +0 -10
  66. package/dist/types/core/util/StringUtil.d.ts +0 -5
  67. package/dist/types/core/util/StringUtil.d.ts.map +0 -10
  68. package/dist/types/core/util/TypeSpec.d.ts +0 -42
  69. package/dist/types/core/util/TypeSpec.d.ts.map +0 -10
  70. package/dist/types/core/util/ValidUtil.d.ts +0 -29
  71. package/dist/types/core/util/ValidUtil.d.ts.map +0 -10
  72. package/src/core/ActionManager.js +0 -147
  73. package/src/core/ContractManager.js +0 -112
  74. package/src/core/Conveyor.js +0 -185
  75. package/src/core/Core.js +0 -166
  76. package/src/core/Discovery.js +0 -403
  77. package/src/core/HookManager.js +0 -143
  78. package/src/core/action/ParseManager.js +0 -7
  79. package/src/core/action/PrintManager.js +0 -7
  80. package/src/core/contract/ParseContract.js +0 -7
  81. package/src/core/contract/PrintContract.js +0 -7
  82. package/src/core/util/ActionUtil.js +0 -62
  83. package/src/core/util/ContractUtil.js +0 -63
  84. package/src/core/util/DataUtil.js +0 -540
  85. package/src/core/util/FDUtil.js +0 -388
  86. package/src/core/util/StringUtil.js +0 -11
  87. package/src/core/util/TypeSpec.js +0 -114
  88. package/src/core/util/ValidUtil.js +0 -50
@@ -1,388 +0,0 @@
1
- import fs from "fs"
2
- import {globby} from "globby"
3
- import path from "node:path"
4
- import process from "node:process"
5
- import {fileURLToPath, pathToFileURL} from "node:url"
6
-
7
- import * as DataUtil from "./DataUtil.js"
8
- import * as ValidUtil from "./ValidUtil.js"
9
-
10
- const {isArrayUniform, isType, allocateObject} = DataUtil
11
- const {validType} = ValidUtil
12
-
13
- const freeze = ob => Object.freeze(ob)
14
-
15
- const fdTypes = freeze(["file", "directory"])
16
- const upperFdTypes = freeze(fdTypes.map(type => type.toUpperCase()))
17
- const fdType = freeze(await allocateObject(upperFdTypes, fdTypes))
18
-
19
- /**
20
- * Fix slashes in a path
21
- *
22
- * @param {string} pathName - The path to fix
23
- * @returns {string} The fixed path
24
- */
25
- function fixSlashes(pathName) {
26
- return pathName.replace(/\\/g, "/")
27
- }
28
-
29
- /**
30
- * Convert a path to a URI
31
- *
32
- * @param {string} pathName - The path to convert
33
- * @returns {string} The URI
34
- * @throws {Error} If the path is not a valid file path
35
- */
36
- function pathToUri(pathName) {
37
- try {
38
- return pathToFileURL(pathName).href
39
- } catch(e) {
40
- void e // stfu linter
41
- return pathName
42
- }
43
- }
44
-
45
- /**
46
- * Check if a file can be read. Returns true if the file can be read, false
47
- *
48
- * @param {FileMap} FileMap - The file map to check
49
- * @returns {boolean} Whether the file can be read
50
- */
51
- function canReadFile(FileMap) {
52
- try {
53
- fs.accessSync(FileMap.absolutePath, fs.constants.R_OK)
54
- return true
55
- } catch(_error) {
56
- return false
57
- }
58
- }
59
-
60
- /**
61
- * Check if a file can be written. Returns true if the file can be written,
62
- *
63
- * @param {FileMap} FileMap - The file map to check
64
- * @returns {boolean} Whether the file can be written
65
- */
66
- function canWriteFile(FileMap) {
67
- try {
68
- fs.accessSync(FileMap.absolutePath, fs.constants.W_OK)
69
- return true
70
- } catch(_error) {
71
- return false
72
- }
73
- }
74
-
75
- /**
76
- * Check if a file exists
77
- *
78
- * @param {FileMap} FileMap - The file map to check
79
- * @returns {boolean} Whether the file exists
80
- */
81
- function fileExists(FileMap) {
82
- try {
83
- fs.accessSync(FileMap.absolutePath)
84
- return true
85
- } catch(_error) {
86
- return false
87
- }
88
- }
89
-
90
- /**
91
- * Check if a directory exists
92
- *
93
- * @param {object} DirectoryMap - The directory map to check
94
- * @returns {boolean} Whether the directory exists
95
- */
96
- function directoryExists(DirectoryMap) {
97
- try {
98
- fs.accessSync(DirectoryMap.absolutePath)
99
- return true
100
- } catch(_error) {
101
- return false
102
- }
103
- }
104
-
105
- /**
106
- * Convert a URI to a path
107
- *
108
- * @param {string} pathName - The URI to convert
109
- * @returns {string} The path
110
- * @throws {Error} If the URI is not a valid file URL
111
- */
112
- function uriToPath(pathName) {
113
- try {
114
- return fileURLToPath(pathName)
115
- } catch(e) {
116
- void e // did you hear me?? i said stfu!
117
- return pathName
118
- }
119
- }
120
-
121
- /**
122
- * Resolves a file to an absolute path
123
- *
124
- * @param {string} fileName - The file to resolve
125
- * @param {object} [directoryObject] - The directory object to resolve the
126
- * file in
127
- * @returns {object} A file object (validated)
128
- * @throws {Error}
129
- */
130
- function resolveFilename(fileName, directoryObject = null) {
131
- validType(fileName, "string", {allowEmpty: false}, 1)
132
-
133
- fileName = uriToPath(fileName)
134
- const fixedFileName = fixSlashes(fileName)
135
- const directoryNamePart = fixedFileName.split("/").slice(0, -1).join("/")
136
- const fileNamePart = fixedFileName.split("/").pop()
137
- if(!directoryObject)
138
- directoryObject = resolveDirectory(directoryNamePart)
139
-
140
- const fileObject = composeFilename(directoryObject, fileNamePart)
141
-
142
- if(!fileObject)
143
- throw new Error(
144
- `Failed to resolve file: ${fileName}, looking for file: ${fileNamePart}`,
145
- )
146
-
147
- if(!fileExists(fileObject))
148
- throw new Error(
149
- `Failed to resolve file: ${fileObject.absolutePath}`,
150
- )
151
-
152
- return {
153
- ...fileObject,
154
- directory: directoryObject,
155
- }
156
- }
157
-
158
- /**
159
- * Compose a file path from a directory and a file
160
- *
161
- * @param {string|object} directoryNameorObject - The directory
162
- * @param {string} fileName - The file
163
- * @returns {object} A file object
164
- */
165
- function composeFilename(directoryNameorObject, fileName) {
166
- let dirObject
167
-
168
- if(isType(directoryNameorObject, "string|string[]")) {
169
- dirObject = composeDirectory(directoryNameorObject)
170
- } else {
171
- if(!directoryNameorObject.isDirectory)
172
- throw new Error("Directory object is not a directory")
173
-
174
- dirObject = directoryNameorObject
175
- }
176
-
177
- fileName = path.resolve(dirObject.path, fileName)
178
-
179
- return mapFilename(fileName)
180
- }
181
-
182
- /**
183
- * Map a file to a FileMap
184
- *
185
- * @param {string} fileName - The file to map
186
- * @returns {object} A file object
187
- */
188
- function mapFilename(fileName) {
189
- return {
190
- path: fileName,
191
- uri: pathToUri(fileName),
192
- absolutePath: path.resolve(process.cwd(), fileName),
193
- absoluteUri: pathToUri(path.resolve(process.cwd(), fileName)),
194
- name: path.basename(fileName),
195
- module: path.basename(fileName, path.extname(fileName)),
196
- extension: path.extname(fileName),
197
- isFile: true,
198
- isDirectory: false,
199
- }
200
- }
201
-
202
- /**
203
- * Map a directory to a DirMap
204
- *
205
- * @param {string} directoryName - The directory to map
206
- * @returns {object} A directory object
207
- */
208
- function mapDirectory(directoryName) {
209
- return {
210
- path: directoryName,
211
- uri: pathToUri(directoryName),
212
- absolutePath: path.resolve(process.cwd(), directoryName),
213
- absoluteUri: pathToUri(path.resolve(process.cwd(), directoryName)),
214
- name: path.basename(directoryName),
215
- separator: path.sep,
216
- isFile: false,
217
- isDirectory: true,
218
- }
219
- }
220
-
221
- /**
222
- * Deconstruct a filename into parts
223
- *
224
- * @param {string} fileName - The filename to deconstruct
225
- * @returns {object} The filename parts
226
- */
227
- function deconstructFilenameToParts(fileName) {
228
- const {basename, dirname, extname} = path.parse(fileName)
229
-
230
- return {basename, dirname, extname}
231
- }
232
-
233
- /**
234
- * Retrieve all files matching a specific glob pattern.
235
- *
236
- * @param {string|string[]} globPattern - The glob pattern(s) to search.
237
- * @returns {Promise<object[]>} An array of file objects
238
- * @throws {Error} Throws an error for invalid input or search failure.
239
- */
240
- async function getFiles(globPattern) {
241
- // Validate input
242
- validType(globPattern, "string|string[]", {allowEmpty: false})
243
-
244
- const globbyArray = (
245
- isType(globPattern, "array")
246
- ? globPattern
247
- : globPattern
248
- .split("|")
249
- .map(g => g.trim())
250
- .filter(Boolean)
251
- ).map(g => fixSlashes(g))
252
-
253
- if(
254
- Array.isArray(globbyArray) &&
255
- isArrayUniform(globbyArray, "string", true) &&
256
- !globbyArray.length
257
- )
258
- throw new Error(
259
- `Invalid glob pattern: Array must contain only strings. Got ${JSON.stringify(globPattern)}`,
260
- )
261
-
262
- // Use Globby to fetch matching files
263
- const filesArray = await globby(globbyArray)
264
- const files = filesArray.map(file => mapFilename(file))
265
-
266
- // Flatten the result and remove duplicates
267
- return files
268
- }
269
-
270
- /**
271
- * Resolves a path to an absolute path
272
- *
273
- * @param {string} directoryName - The path to resolve
274
- * @returns {object} The directory object
275
- * @throws {Error}
276
- */
277
- function resolveDirectory(directoryName) {
278
- validType(directoryName, "string", true)
279
-
280
- const directoryObject = mapDirectory(directoryName)
281
-
282
- try {
283
- fs.opendirSync(directoryObject.absolutePath).closeSync()
284
- } catch(e) {
285
- throw new Error(
286
- `Failed to resolve directory: ${directoryObject.absolutePath}, looking for file: ${directoryName}\n${e.message}`,
287
- )
288
- }
289
-
290
- fs.opendirSync(directoryObject.absolutePath).closeSync()
291
-
292
- return directoryObject
293
- }
294
-
295
- /**
296
- * Compose a directory map from a path
297
- *
298
- * @param {string} directory - The directory
299
- * @returns {object} A directory object
300
- */
301
- function composeDirectory(directory) {
302
- return mapDirectory(directory)
303
- }
304
-
305
- /**
306
- * Lists the contents of a directory.
307
- *
308
- * @param {string} directory - The directory to list.
309
- * @returns {Promise<{files: object[], directories: object[]}>} The files and
310
- * directories in the directory.
311
- */
312
- async function ls(directory) {
313
- const found = await fs.promises.readdir(directory, {withFileTypes: true})
314
- const results = await Promise.all(
315
- found.map(async dirent => {
316
- const fullPath = path.join(directory, dirent.name)
317
- const stat = await fs.promises.stat(fullPath)
318
- return {dirent, stat, fullPath}
319
- }),
320
- )
321
-
322
- const files = results
323
- .filter(({stat}) => stat.isFile())
324
- .map(({fullPath}) => mapFilename(fullPath))
325
-
326
- const directories = results
327
- .filter(({stat}) => stat.isDirectory())
328
- .map(({fullPath}) => mapDirectory(fullPath))
329
-
330
- return {files, directories}
331
- }
332
-
333
- /**
334
- * Reads the content of a file synchronously.
335
- *
336
- * @param {object} fileObject - The file map containing the file path
337
- * @returns {string} The file contents
338
- */
339
- function readFile(fileObject) {
340
- const {absolutePath} = fileObject
341
-
342
- if(!absolutePath)
343
- throw new Error("No absolute path in file map")
344
-
345
- const content = fs.readFileSync(absolutePath, "utf8")
346
-
347
- return content
348
- }
349
-
350
- /**
351
- * Writes content to a file synchronously.
352
- *
353
- * @param {object} fileObject - The file map containing the file path
354
- * @param {string} content - The content to write
355
- */
356
- function writeFile(fileObject, content) {
357
- const absolutePath = fileObject.absolutePath
358
-
359
- if(!absolutePath)
360
- throw new Error("No absolute path in file map")
361
-
362
- fs.writeFileSync(absolutePath, content, "utf8")
363
- }
364
-
365
- export {
366
- // Constants
367
- fdType,
368
- fdTypes,
369
- // Functions
370
- canReadFile,
371
- canWriteFile,
372
- composeDirectory,
373
- composeFilename,
374
- deconstructFilenameToParts,
375
- directoryExists,
376
- fileExists,
377
- fixSlashes,
378
- getFiles,
379
- ls,
380
- mapDirectory,
381
- mapFilename,
382
- pathToUri,
383
- readFile,
384
- resolveDirectory,
385
- resolveFilename,
386
- uriToPath,
387
- writeFile,
388
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Capitalizes the first letter of a string
3
- *
4
- * @param {string} str - The string to capitalize
5
- * @returns {string} The capitalized string
6
- */
7
- function capitalize(str) {
8
- return `${str.charAt(0).toUpperCase()}${str.slice(1)}`
9
- }
10
-
11
- export {capitalize}
@@ -1,114 +0,0 @@
1
- import * as DataUtil from "./DataUtil.js"
2
-
3
- const {isEmpty, typeOf, isArrayUniform, isValidType} = DataUtil
4
-
5
- export default class TypeSpec {
6
- #specs
7
-
8
- constructor(string, options) {
9
- this.#specs = []
10
- this.#parse(string, options)
11
- Object.freeze(this.#specs)
12
- this.specs = this.#specs
13
- this.length = this.#specs.length
14
- this.stringRepresentation = this.toString()
15
- Object.freeze(this)
16
- }
17
-
18
- toString() {
19
- return this.#specs
20
- .map(spec => {
21
- return `${spec.typeName}${spec.array ? "[]" : ""}`
22
- })
23
- .join("|")
24
- }
25
-
26
- toJSON() {
27
- // Serialize as a string representation or as raw data
28
- return {
29
- specs: this.#specs,
30
- length: this.length,
31
- stringRepresentation: this.toString(),
32
- }
33
- }
34
-
35
- forEach(callback) {
36
- this.#specs.forEach(callback)
37
- }
38
- every(callback) {
39
- return this.#specs.every(callback)
40
- }
41
- some(callback) {
42
- return this.#specs.some(callback)
43
- }
44
- filter(callback) {
45
- return this.#specs.filter(callback)
46
- }
47
- map(callback) {
48
- return this.#specs.map(callback)
49
- }
50
- reduce(callback, initialValue) {
51
- return this.#specs.reduce(callback, initialValue)
52
- }
53
- find(callback) {
54
- return this.#specs.find(callback)
55
- }
56
-
57
- match(value, options) {
58
- const allowEmpty = options?.allowEmpty ?? true
59
- const empty = isEmpty(value)
60
-
61
- // If we have a list of types, because the string was validly parsed,
62
- // we need to ensure that all of the types that were parsed are valid types
63
- // in JavaScript.
64
- if(this.length && !this.every(t => isValidType(t.typeName)))
65
- return false
66
-
67
- // Now, let's do some checking with the types, respecting the array flag
68
- // with the value
69
- const valueType = typeOf(value)
70
- const isArray = valueType === "array"
71
-
72
- // We need to ensure that we match the type and the consistency of the types
73
- // in an array, if it is an array and an array is allowed.
74
- const matchingTypeSpec = this.filter(spec => {
75
- const {typeName: allowedType, array: allowedArray} = spec
76
-
77
- if(valueType === allowedType && !isArray && !allowedArray)
78
- return !allowEmpty ? !empty : true
79
-
80
- if(isArray) {
81
- if(allowedType === "array")
82
- if(!allowedArray)
83
- return true
84
-
85
- if(empty)
86
- if(allowEmpty)
87
- return true
88
-
89
- return isArrayUniform(value, allowedType)
90
- }
91
- })
92
-
93
- return matchingTypeSpec.length > 0
94
- }
95
-
96
- #parse(string, options) {
97
- const delimiter = options?.delimiter ?? "|"
98
- const parts = string.split(delimiter)
99
-
100
- this.#specs = parts.map(part => {
101
- const typeMatches = /(\w+)(\[\])?/.exec(part)
102
- if(!typeMatches || typeMatches.length !== 3)
103
- throw new TypeError(`Invalid type: ${part}`)
104
-
105
- if(!isValidType(typeMatches[1]))
106
- throw new TypeError(`Invalid type: ${typeMatches[1]}`)
107
-
108
- return {
109
- typeName: typeMatches[1],
110
- array: typeMatches[2] === "[]",
111
- }
112
- })
113
- }
114
- }
@@ -1,50 +0,0 @@
1
- import _assert from "node:assert/strict"
2
-
3
- import * as DataUtil from "./DataUtil.js"
4
-
5
- const {isType} = DataUtil
6
-
7
- /**
8
- * Validates a value against a type
9
- *
10
- * @param {*} value - The value to validate
11
- * @param {string} type - The expected type in the form of "object",
12
- * "object[]", "object|object[]"
13
- * @param {object} [options] - Additional options for validation.
14
- */
15
- function validType(value, type, options) {
16
- assert(
17
- isType(value, type, options),
18
- `Invalid type. Expected ${type}, got ${JSON.stringify(value)}`,
19
- 1,
20
- )
21
- }
22
-
23
- /**
24
- * Asserts a condition
25
- *
26
- * @param {boolean} condition - The condition to assert
27
- * @param {string} message - The message to display if the condition is not
28
- * met
29
- * @param {number} [arg] - The argument to display if the condition is not
30
- * met (optional)
31
- */
32
- function assert(condition, message, arg = null) {
33
- _assert(
34
- isType(condition, "boolean"),
35
- `Condition must be a boolean, got ${condition}`,
36
- )
37
- _assert(
38
- isType(message, "string"),
39
- `Message must be a string, got ${message}`,
40
- )
41
- _assert(
42
- arg !== null && isType(arg, "number"),
43
- `Arg must be a number, got ${arg}`,
44
- )
45
-
46
- if(!condition)
47
- throw new Error(`${message}${arg ? `: ${arg}` : ""}`)
48
- }
49
-
50
- export {assert, validType}