@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
package/src/core/util/FDUtil.js
DELETED
|
@@ -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}
|