@reliverse/dler 1.7.26 → 1.7.28

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 (136) hide show
  1. package/README.md +7 -3
  2. package/bin/app/agg/cmd.d.ts +5 -2
  3. package/bin/app/agg/cmd.js +56 -20
  4. package/bin/app/agg/impl.js +1 -0
  5. package/bin/app/build/cmd.js +5 -10
  6. package/bin/app/build/impl.d.ts +6 -3
  7. package/bin/app/build/impl.js +20 -28
  8. package/bin/app/build/postbuild.d.ts +1 -0
  9. package/bin/app/build/postbuild.js +109 -0
  10. package/bin/app/build/ppb-utils.d.ts +16 -0
  11. package/bin/app/build/ppb-utils.js +99 -0
  12. package/bin/app/build/prebuild.d.ts +2 -0
  13. package/bin/app/build/prebuild.js +112 -0
  14. package/bin/app/check/cmd.d.ts +8 -0
  15. package/bin/app/check/cmd.js +63 -53
  16. package/bin/app/magic/cmd.d.ts +4 -0
  17. package/bin/app/magic/cmd.js +37 -26
  18. package/bin/app/pub/cmd.js +2 -9
  19. package/bin/app/pub/impl.js +17 -71
  20. package/bin/app/remdn/cmd.d.ts +35 -0
  21. package/bin/app/remdn/cmd.js +732 -0
  22. package/bin/cli.js +36 -25
  23. package/bin/libs/cfg/{constants.d.ts → cfg-impl/cfg-consts.d.ts} +15 -11
  24. package/bin/libs/cfg/{constants.js → cfg-impl/cfg-consts.js} +16 -0
  25. package/bin/libs/cfg/{types.d.ts → cfg-impl/cfg-types.d.ts} +58 -0
  26. package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-define.d.ts +10 -10
  27. package/bin/libs/cfg/cfg-mod.d.ts +24 -24
  28. package/bin/libs/cfg/cfg-mod.js +35 -21
  29. package/bin/libs/sdk/sdk-impl/build/build-library.d.ts +1 -1
  30. package/bin/libs/sdk/sdk-impl/build/build-regular.d.ts +1 -1
  31. package/bin/libs/sdk/sdk-impl/build/build-regular.js +1 -17
  32. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/auto.d.ts +1 -1
  33. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/build.d.ts +1 -1
  34. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/copy/copy-mod.d.ts +1 -1
  35. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loader.d.ts +1 -1
  36. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loaders/js.d.ts +1 -1
  37. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loaders/loaders-mod.d.ts +1 -1
  38. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loaders/postcss.d.ts +1 -1
  39. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loaders/sass.d.ts +1 -1
  40. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/loaders/vue.d.ts +1 -1
  41. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/make.d.ts +1 -1
  42. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/make.js +1 -1
  43. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/dts.d.ts +1 -1
  44. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/vue-dts.d.ts +1 -1
  45. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist-mod.d.ts +1 -1
  46. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/build.d.ts +1 -1
  47. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/config.d.ts +1 -1
  48. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/cjs.d.ts +1 -1
  49. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/esbuild.d.ts +1 -1
  50. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/stub.d.ts +1 -1
  51. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/utils.d.ts +1 -1
  52. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/watch.d.ts +1 -1
  53. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/untyped/untyped-mod.d.ts +1 -1
  54. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/utils.d.ts +1 -1
  55. package/bin/libs/sdk/sdk-impl/build/bundlers/unified/validate.d.ts +1 -1
  56. package/bin/libs/sdk/sdk-impl/config/default.js +18 -1
  57. package/bin/libs/sdk/sdk-impl/config/info.js +1 -1
  58. package/bin/libs/sdk/sdk-impl/config/init.js +16 -0
  59. package/bin/libs/sdk/sdk-impl/config/types.d.ts +71 -0
  60. package/bin/libs/sdk/sdk-impl/library-flow.d.ts +14 -7
  61. package/bin/libs/sdk/sdk-impl/library-flow.js +61 -13
  62. package/bin/libs/sdk/sdk-impl/pub/pub-library.d.ts +1 -1
  63. package/bin/libs/sdk/sdk-impl/pub/pub-regular.d.ts +1 -1
  64. package/bin/libs/sdk/sdk-impl/regular-flow.d.ts +7 -3
  65. package/bin/libs/sdk/sdk-impl/regular-flow.js +42 -19
  66. package/bin/libs/sdk/sdk-impl/rules/reliverse/dler-config-health/dler-config-health.d.ts +1 -1
  67. package/bin/libs/sdk/sdk-impl/rules/reliverse/file-extensions/file-extensions.d.ts +1 -1
  68. package/bin/libs/sdk/sdk-impl/rules/reliverse/missing-deps/deps-mod.d.ts +1 -1
  69. package/bin/libs/sdk/sdk-impl/rules/reliverse/no-dynamic-imports/no-dynamic-imports.d.ts +8 -2
  70. package/bin/libs/sdk/sdk-impl/rules/reliverse/no-dynamic-imports/no-dynamic-imports.js +50 -2
  71. package/bin/libs/sdk/sdk-impl/rules/reliverse/no-index-files/no-index-files.d.ts +1 -1
  72. package/bin/libs/sdk/sdk-impl/rules/reliverse/package-json-health/package-json-health.d.ts +1 -1
  73. package/bin/libs/sdk/sdk-impl/rules/reliverse/path-extensions/path-extensions.d.ts +1 -1
  74. package/bin/libs/sdk/sdk-impl/rules/reliverse/self-include/self-include.d.ts +1 -1
  75. package/bin/libs/sdk/sdk-impl/rules/reliverse/tsconfig-health/tsconfig-health.d.ts +1 -1
  76. package/bin/libs/sdk/sdk-impl/rules/rules-mod.d.ts +1 -1
  77. package/bin/libs/sdk/sdk-impl/rules/rules-utils.d.ts +0 -1
  78. package/bin/libs/sdk/sdk-impl/rules/rules-utils.js +1 -8
  79. package/bin/libs/sdk/{sdk-types.d.ts → sdk-impl/sdk-types.d.ts} +1 -1
  80. package/bin/libs/sdk/sdk-impl/utils/finalize.d.ts +6 -2
  81. package/bin/libs/sdk/sdk-impl/utils/finalize.js +25 -17
  82. package/bin/libs/sdk/sdk-impl/utils/pack-unpack/pu-file-utils.d.ts +1 -1
  83. package/bin/libs/sdk/sdk-impl/utils/pack-unpack/pu-file-utils.js +2 -2
  84. package/bin/libs/sdk/sdk-impl/utils/utils-fs.d.ts +1 -36
  85. package/bin/libs/sdk/sdk-impl/utils/utils-fs.js +6 -113
  86. package/bin/libs/sdk/sdk-impl/utils/utils-perf.d.ts +1 -1
  87. package/bin/libs/sdk/sdk-impl/utils/utils-security.d.ts +0 -1
  88. package/bin/libs/sdk/sdk-impl/utils/utils-security.js +0 -8
  89. package/bin/libs/sdk/sdk-mod.d.ts +16 -11
  90. package/bin/libs/sdk/sdk-mod.js +52 -7
  91. package/package.json +5 -4
  92. /package/bin/libs/cfg/{rse/rse-impl/rse-types.js → cfg-impl/cfg-types.js} +0 -0
  93. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-biome.d.ts +0 -0
  94. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-biome.js +0 -0
  95. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-comments.d.ts +0 -0
  96. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-comments.js +0 -0
  97. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-consts.d.ts +0 -0
  98. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-consts.js +0 -0
  99. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-content.d.ts +0 -0
  100. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-content.js +0 -0
  101. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-core.d.ts +0 -0
  102. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-core.js +0 -0
  103. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-create.d.ts +0 -0
  104. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-create.js +0 -0
  105. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-def-utils.d.ts +0 -0
  106. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-def-utils.js +0 -0
  107. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-default.d.ts +0 -0
  108. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-default.js +0 -0
  109. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-define.js +0 -0
  110. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-detect.d.ts +0 -0
  111. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-detect.js +0 -0
  112. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-gen-cfg.d.ts +0 -0
  113. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-gen-cfg.js +0 -0
  114. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-migrate.d.ts +0 -0
  115. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-migrate.js +0 -0
  116. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-path.d.ts +0 -0
  117. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-path.js +0 -0
  118. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-prompts.d.ts +0 -0
  119. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-prompts.js +0 -0
  120. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-read.d.ts +0 -0
  121. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-read.js +0 -0
  122. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-repair.d.ts +0 -0
  123. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-repair.js +0 -0
  124. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-schema.d.ts +0 -0
  125. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-schema.js +0 -0
  126. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-types.d.ts +0 -0
  127. /package/bin/libs/cfg/{types.js → cfg-impl/rse-config/rse-impl/rse-types.js} +0 -0
  128. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-unstable.d.ts +0 -0
  129. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-unstable.js +0 -0
  130. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-update.d.ts +0 -0
  131. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-update.js +0 -0
  132. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-utils.d.ts +0 -0
  133. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-impl/rse-utils.js +0 -0
  134. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-mod.d.ts +0 -0
  135. /package/bin/libs/cfg/{rse → cfg-impl/rse-config}/rse-mod.js +0 -0
  136. /package/bin/libs/sdk/{sdk-types.js → sdk-impl/sdk-types.js} +0 -0
@@ -0,0 +1,732 @@
1
+ import { selectPrompt } from "@reliverse/rempts";
2
+ import { defineArgs, defineCommand } from "@reliverse/rempts";
3
+ import { createJiti } from "jiti";
4
+ import { writeFile } from "node:fs/promises";
5
+ import { readdir } from "node:fs/promises";
6
+ import { join, resolve, basename } from "node:path";
7
+ import pMap from "p-map";
8
+ const DEFAULT_CONFIG = {
9
+ output: "table.html",
10
+ dirs: {
11
+ src: {},
12
+ "dist-npm/bin": {},
13
+ "dist-jsr/bin": {},
14
+ "dist-libs": {}
15
+ },
16
+ "ext-map": {
17
+ ts: ["ts", "js-d.ts", "ts"]
18
+ // [<main>, <dist-npm/bin | dist-libs's * npm/bin>, <dist-jsr | dist-libs's * jsr/bin>]
19
+ }
20
+ };
21
+ const DEFAULT_CONFIG_PATH = ".config/remdn.ts";
22
+ const resolvePath = (path) => {
23
+ return resolve(process.cwd(), path);
24
+ };
25
+ const validateConfigPath = (filePath) => {
26
+ const parts = filePath.split(".");
27
+ if (parts.length <= 1 || parts.length === 2 && parts[1] === "") {
28
+ throw new Error(
29
+ `Invalid config file: "${filePath}". Config file must have .json or .ts extension.`
30
+ );
31
+ }
32
+ const ext = parts.pop()?.toLowerCase();
33
+ if (ext !== "json" && ext !== "ts") {
34
+ throw new Error(
35
+ `Invalid config file extension: "${ext}". Only .json and .ts extensions are supported for config files.`
36
+ );
37
+ }
38
+ };
39
+ const validateOutputPath = (filePath) => {
40
+ const parts = filePath.split(".");
41
+ if (parts.length <= 1 || parts.length === 2 && parts[1] === "") {
42
+ throw new Error(
43
+ `Invalid output file: "${filePath}". Output file must have either .md or .html extension.`
44
+ );
45
+ }
46
+ const ext = parts.pop()?.toLowerCase();
47
+ if (ext !== "md" && ext !== "html") {
48
+ throw new Error(
49
+ `Invalid output file extension: "${ext}". Only .md and .html extensions are supported for output files.`
50
+ );
51
+ }
52
+ };
53
+ const evaluateTsConfig = async (filePath) => {
54
+ try {
55
+ const jiti = createJiti(import.meta.url, {
56
+ fsCache: true,
57
+ moduleCache: true,
58
+ interopDefault: true
59
+ });
60
+ const config = await jiti.import(filePath, { default: true });
61
+ if (!config || typeof config !== "object") {
62
+ throw new Error("Config file must export a default object");
63
+ }
64
+ const typedConfig = config;
65
+ if (!typedConfig.dirs || typeof typedConfig.dirs !== "object") {
66
+ throw new Error("Config file must export an object with a 'dirs' property");
67
+ }
68
+ return typedConfig;
69
+ } catch (error) {
70
+ throw new Error(
71
+ `Failed to evaluate TypeScript config file: ${error instanceof Error ? error.message : String(error)}`
72
+ );
73
+ }
74
+ };
75
+ const expandDistLibs = async (dirs) => {
76
+ const expanded = {};
77
+ for (const [dir, opts] of Object.entries(dirs)) {
78
+ if (dir === "dist-libs" || dir.endsWith("/dist-libs")) {
79
+ const resolvedDistLibs = resolvePath(dir);
80
+ if (await Bun.file(resolvedDistLibs).exists()) {
81
+ try {
82
+ const libDirs = await readdir(resolvedDistLibs, { withFileTypes: true });
83
+ for (const libDir of libDirs) {
84
+ if (libDir.isDirectory()) {
85
+ const libName = libDir.name;
86
+ const libPath = join(resolvedDistLibs, libName);
87
+ const npmBinPath = join(libPath, "npm", "bin");
88
+ if (await Bun.file(npmBinPath).exists()) {
89
+ expanded[npmBinPath] = opts;
90
+ }
91
+ const jsrBinPath = join(libPath, "jsr", "bin");
92
+ if (await Bun.file(jsrBinPath).exists()) {
93
+ expanded[jsrBinPath] = opts;
94
+ }
95
+ }
96
+ }
97
+ } catch (error) {
98
+ console.warn(
99
+ `Warning: Could not read dist-libs directory "${resolvedDistLibs}": ${error instanceof Error ? error.message : String(error)}`
100
+ );
101
+ }
102
+ } else {
103
+ console.warn(`Warning: dist-libs directory "${resolvedDistLibs}" not found. Skipping.`);
104
+ }
105
+ } else {
106
+ expanded[dir] = opts;
107
+ }
108
+ }
109
+ return expanded;
110
+ };
111
+ const readConfig = async (path) => {
112
+ if (!path) {
113
+ try {
114
+ const defaultConfigPath = resolvePath(DEFAULT_CONFIG_PATH);
115
+ if (await Bun.file(defaultConfigPath).exists()) {
116
+ const cfg = await evaluateTsConfig(defaultConfigPath);
117
+ const expandedDirs2 = await expandDistLibs(cfg.dirs);
118
+ return { ...cfg, dirs: expandedDirs2 };
119
+ }
120
+ } catch (error) {
121
+ console.warn(
122
+ `Warning: Could not read default config at ${DEFAULT_CONFIG_PATH}: ${error instanceof Error ? error.message : String(error)}`
123
+ );
124
+ }
125
+ const dirs = {};
126
+ const possibleDirs = ["src", "dist-npm/bin", "dist-jsr/bin", "dist-libs"];
127
+ for (const dir of possibleDirs) {
128
+ const resolvedPath = resolvePath(dir);
129
+ if (await Bun.file(resolvedPath).exists()) {
130
+ dirs[dir] = {};
131
+ }
132
+ }
133
+ const expandedDirs = await expandDistLibs(dirs);
134
+ if (Object.keys(expandedDirs).length === 0) {
135
+ throw new Error(
136
+ "No valid directories found. Please create at least one of: src, dist-npm/bin, dist-jsr/bin, dist-libs"
137
+ );
138
+ }
139
+ const mainPath = Object.keys(expandedDirs)[0];
140
+ console.log(`Using "${mainPath}" as main directory`);
141
+ const resolvedConfig = {
142
+ ...DEFAULT_CONFIG,
143
+ dirs: Object.fromEntries(
144
+ Object.entries(expandedDirs).map(([key, value]) => [resolvePath(key), value])
145
+ )
146
+ };
147
+ return resolvedConfig;
148
+ }
149
+ try {
150
+ const resolvedConfigPath = resolvePath(path);
151
+ const ext = path.split(".").pop()?.toLowerCase();
152
+ let config;
153
+ if (ext === "json") {
154
+ const raw = await Bun.file(resolvedConfigPath).text();
155
+ config = JSON.parse(raw);
156
+ } else if (ext === "ts") {
157
+ config = await evaluateTsConfig(resolvedConfigPath);
158
+ } else {
159
+ throw new Error(`Unsupported config file extension: ${ext}`);
160
+ }
161
+ const expandedDirs = await expandDistLibs(config.dirs);
162
+ config.dirs = expandedDirs;
163
+ const mainPath = Object.keys(config.dirs)[0];
164
+ if (!mainPath) {
165
+ throw new Error("No main directory found in configuration");
166
+ }
167
+ const resolvedMainPath = resolvePath(mainPath);
168
+ if (!await Bun.file(resolvedMainPath).exists()) {
169
+ throw new Error(
170
+ `Main directory "${resolvedMainPath}" not found. Cannot proceed without main directory.`
171
+ );
172
+ }
173
+ const existingDirs = {};
174
+ const mainOpts = config.dirs[mainPath];
175
+ if (!mainOpts) {
176
+ throw new Error(`No options found for main directory "${mainPath}"`);
177
+ }
178
+ existingDirs[resolvedMainPath] = mainOpts;
179
+ for (const [dir, opts] of Object.entries(config.dirs)) {
180
+ if (dir === mainPath) continue;
181
+ const resolvedDir = resolvePath(dir);
182
+ if (await Bun.file(resolvedDir).exists()) {
183
+ existingDirs[resolvedDir] = opts;
184
+ } else {
185
+ console.warn(`Warning: Directory "${resolvedDir}" not found. Skipping.`);
186
+ }
187
+ }
188
+ config.dirs = existingDirs;
189
+ return config;
190
+ } catch (error) {
191
+ throw new Error(
192
+ `Failed to read or parse config file at ${path}: ${error instanceof Error ? error.message : String(error)}`
193
+ );
194
+ }
195
+ };
196
+ const validateFilters = ({ includeExt, excludeExt }) => {
197
+ if (includeExt && excludeExt) {
198
+ for (const ex of excludeExt) {
199
+ if (!includeExt.includes(ex)) {
200
+ throw new Error(
201
+ `Invalid configuration: excludeExt value "${ex}" was not present in includeExt list`
202
+ );
203
+ }
204
+ }
205
+ }
206
+ };
207
+ const shouldInclude = (file, opts) => {
208
+ const ext = `.${file.split(".").pop()}`;
209
+ if (!opts.includeExt && !opts.excludeExt) return true;
210
+ if (opts.includeExt && !opts.includeExt.includes(ext)) return false;
211
+ if (opts.excludeExt?.includes(ext)) return false;
212
+ return true;
213
+ };
214
+ const getCanonicalFilename = (filename, extMap, dirPath) => {
215
+ if (!extMap) return filename;
216
+ let name = filename;
217
+ if (typeof dirPath === "string" && dirPath.includes("dist-libs")) {
218
+ const match = dirPath.match(/dist-libs\/(.*?)\/(npm|jsr)\/bin/);
219
+ const libName = match?.[1];
220
+ if (libName && name.startsWith(`${libName}-`)) {
221
+ name = name.slice(libName.length + 1);
222
+ }
223
+ }
224
+ const parts = name.split(".");
225
+ if (parts.length < 2) return name;
226
+ const ext = parts[parts.length - 1];
227
+ const baseName = parts.slice(0, -1).join(".");
228
+ if (!ext) return name;
229
+ if (parts.length >= 3 && parts[parts.length - 2] === "d" && ext === "ts") {
230
+ const baseNameWithoutCompound = parts.slice(0, -2).join(".");
231
+ const canonicalExt = extMap.ts ? extMap.ts[0] : "ts";
232
+ return `${baseNameWithoutCompound}.${canonicalExt}`;
233
+ }
234
+ for (const [, [mainExt, npmExt, jsrExt]] of Object.entries(extMap)) {
235
+ const npmParts = npmExt.split("-");
236
+ const expectedNpmExt = npmParts[0];
237
+ if (ext === mainExt || ext === expectedNpmExt || ext === jsrExt) {
238
+ return `${baseName}.${mainExt}`;
239
+ }
240
+ }
241
+ return name;
242
+ };
243
+ const getExpectedFilenames = (canonicalFilename, dirPath, extMap) => {
244
+ if (!extMap) return [canonicalFilename];
245
+ let baseName = canonicalFilename.split(".").slice(0, -1).join(".");
246
+ const ext = canonicalFilename.split(".").pop();
247
+ if (typeof dirPath === "string" && dirPath.includes("dist-libs")) {
248
+ const match = dirPath.match(/dist-libs\/(.*?)\/(npm|jsr)\/bin/);
249
+ const libName = match?.[1];
250
+ if (libName && !baseName.startsWith(`${libName}-`)) {
251
+ baseName = `${libName}-${baseName}`;
252
+ }
253
+ }
254
+ const mapEntry = extMap[ext];
255
+ if (!mapEntry) return [canonicalFilename];
256
+ const [, npmExt, jsrExt] = mapEntry;
257
+ const isNpmDir = dirPath.includes("dist-npm") || dirPath.includes("/npm/bin") || dirPath.includes("dist-libs") && dirPath.includes("/npm/bin");
258
+ const isJsrDir = dirPath.includes("dist-jsr") || dirPath.includes("/jsr/bin") || dirPath.includes("dist-libs") && dirPath.includes("/jsr/bin");
259
+ const isLibsDir = dirPath.includes("/libs/");
260
+ if (isNpmDir) {
261
+ const npmParts = npmExt.split("-");
262
+ if (npmParts.length === 2) {
263
+ const [primaryExt, secondaryExt] = npmParts;
264
+ if (ext === primaryExt) {
265
+ return [`${baseName}.${primaryExt}`, `${baseName}.${secondaryExt}`];
266
+ } else if (ext === secondaryExt) {
267
+ return [`${baseName}.${secondaryExt}`, `${baseName}.${primaryExt}`];
268
+ }
269
+ return [`${baseName}.${primaryExt}`, `${baseName}.${secondaryExt}`];
270
+ }
271
+ return [`${baseName}.${npmExt}`];
272
+ }
273
+ if (isJsrDir) {
274
+ return [`${baseName}.${jsrExt}`];
275
+ }
276
+ if (isLibsDir) {
277
+ if (dirPath.includes("dist-libs")) {
278
+ const isJsrBin = dirPath.includes("/jsr/bin");
279
+ return isJsrBin ? [`${baseName}.${jsrExt}`] : [`${baseName}.${npmExt}`];
280
+ }
281
+ return [canonicalFilename];
282
+ }
283
+ return [canonicalFilename];
284
+ };
285
+ const scanDir = async (base, opts) => {
286
+ validateFilters(opts);
287
+ const folders = /* @__PURE__ */ new Map();
288
+ const walk = async (rel = "") => {
289
+ const abs = join(base, rel);
290
+ const entries = await readdir(abs, { withFileTypes: true });
291
+ const fileSet = folders.get(rel) ?? /* @__PURE__ */ new Set();
292
+ folders.set(rel, fileSet);
293
+ for (const entry of entries) {
294
+ const nextRel = join(rel, entry.name);
295
+ if (entry.isDirectory()) {
296
+ await walk(nextRel);
297
+ } else if (entry.isFile() && shouldInclude(entry.name, opts)) {
298
+ fileSet.add(entry.name);
299
+ }
300
+ }
301
+ };
302
+ await walk();
303
+ return { folders };
304
+ };
305
+ const normalizePath = (path) => {
306
+ return path.replace(/[\\/]+/g, "/");
307
+ };
308
+ const generateAnchor = (path) => {
309
+ return path.toLowerCase().replace(/[^a-z0-9-]+/g, "");
310
+ };
311
+ const buildTableHeader = (paths) => {
312
+ return [
313
+ "| " + paths.map(normalizePath).join(" | ") + " |",
314
+ "| " + paths.map(() => "---").join(" | ") + " |"
315
+ ];
316
+ };
317
+ function mapDistLibsFolderToLibs(folder, colPath, allPaths) {
318
+ const distLibsMatch = colPath.match(/dist-libs\/(.*?)\/(npm|jsr)\/bin/);
319
+ if (distLibsMatch) {
320
+ const [, libName, type] = distLibsMatch;
321
+ let subfolder = folder.replace(/^\.?\/?/, "");
322
+ subfolder = subfolder.replace(/^.*?\/bin\/?/, "");
323
+ let mappedBase = "";
324
+ if (colPath.includes("dist-libs")) {
325
+ for (const p of allPaths) {
326
+ if (p.includes("src")) mappedBase = `src/libs/${libName}`;
327
+ if (type === "npm" && p.includes("dist-npm")) mappedBase = `dist-npm/bin/libs/${libName}`;
328
+ if (type === "jsr" && p.includes("dist-jsr")) mappedBase = `dist-jsr/bin/libs/${libName}`;
329
+ }
330
+ }
331
+ return mappedBase + (subfolder ? `/${subfolder}` : "");
332
+ }
333
+ return folder;
334
+ }
335
+ const isDistLibsPath = (p) => p.includes("dist-libs");
336
+ const buildTableRow = (canonicalFilename, paths, trees, folder, extMap) => {
337
+ const row = paths.map((path, i) => {
338
+ const tree = trees[i];
339
+ if (!tree) return "";
340
+ let mappedFolder = folder;
341
+ if (!isDistLibsPath(path) && isDistLibsPath(folder)) {
342
+ mappedFolder = mapDistLibsFolderToLibs(folder, path, paths) || folder;
343
+ }
344
+ const folderFiles = tree.folders.get(mappedFolder ?? "");
345
+ if (!folderFiles || !folderFiles.size) return "";
346
+ const matched = Array.from(folderFiles).filter(
347
+ (f) => getCanonicalFilename(f, extMap, mappedFolder ?? "") === canonicalFilename
348
+ );
349
+ return matched.join(", ");
350
+ }).join(" | ");
351
+ return "| " + row + " |";
352
+ };
353
+ const buildMarkdown = (title, paths, trees, extMap) => {
354
+ const lines = ["# " + title, ""];
355
+ lines.push("**Table of Contents**:");
356
+ lines.push("");
357
+ lines.push(`- [${title}](#${title.toLowerCase().replace(/\s+/g, "-")})`);
358
+ const mainTree = trees[0];
359
+ if (!mainTree) {
360
+ throw new Error("No trees provided for markdown generation");
361
+ }
362
+ const folderList = [...mainTree.folders.keys()].sort();
363
+ const mainPath = paths[0];
364
+ if (!mainPath) {
365
+ throw new Error("No main path provided for markdown generation");
366
+ }
367
+ for (const folder of folderList) {
368
+ const header = folder === "" ? basename(mainPath) : normalizePath(folder);
369
+ const anchor = folder === "" ? basename(mainPath) : generateAnchor(folder);
370
+ lines.push(` - [${header}](#${anchor})`);
371
+ }
372
+ lines.push("");
373
+ for (const folder of folderList) {
374
+ const header = folder === "" ? basename(mainPath) : normalizePath(folder);
375
+ lines.push(`## ${header}`, "");
376
+ lines.push(...buildTableHeader(paths));
377
+ const canonicalFiles = /* @__PURE__ */ new Set();
378
+ for (let i = 0; i < trees.length; i++) {
379
+ const tree = trees[i];
380
+ if (!tree) continue;
381
+ const mappedFolder = paths[i]?.includes("dist-libs") ? mapDistLibsFolderToLibs(folder, paths[i], paths) || folder : folder;
382
+ const folderFiles = tree.folders.get(mappedFolder ?? "");
383
+ if (folderFiles?.size) {
384
+ for (const filename of folderFiles) {
385
+ const canonical = getCanonicalFilename(filename, extMap, mappedFolder ?? "");
386
+ canonicalFiles.add(canonical);
387
+ }
388
+ }
389
+ }
390
+ for (const canonicalFilename of [...canonicalFiles].sort()) {
391
+ lines.push(buildTableRow(canonicalFilename, paths, trees, folder, extMap));
392
+ }
393
+ lines.push("");
394
+ }
395
+ return lines.join("\n");
396
+ };
397
+ const findMissingFiles = (mainTree, otherTrees, paths, extMap) => {
398
+ if (!extMap) return [];
399
+ const notifications = [];
400
+ const mainFolders = mainTree.folders;
401
+ for (let i = 0; i < otherTrees.length; i++) {
402
+ const otherTree = otherTrees[i];
403
+ const otherPath = paths[i + 1];
404
+ if (!otherTree || !otherPath) continue;
405
+ for (const [folder, files] of otherTree.folders.entries()) {
406
+ let mainFolderToCheck = folder;
407
+ if (otherPath.includes("dist-libs")) {
408
+ mainFolderToCheck = mapDistLibsFolderToLibs(folder, otherPath, paths) || folder;
409
+ } else if (otherPath === "dist-npm/bin") {
410
+ mainFolderToCheck = folder.replace(/^[/\\]+/, "").replace(/[/\\]+/g, "/");
411
+ if (mainFolderToCheck === "") {
412
+ mainFolderToCheck = "src";
413
+ } else {
414
+ mainFolderToCheck = `src/${mainFolderToCheck}`;
415
+ }
416
+ }
417
+ const mainFiles = mainFolders.get(mainFolderToCheck ?? "");
418
+ if (!mainFiles || !mainFiles.size) continue;
419
+ for (const file of files) {
420
+ const canonicalFile = getCanonicalFilename(file, extMap, folder?.toString() ?? "");
421
+ const expectedFilenames = getExpectedFilenames(canonicalFile, otherPath ?? "", extMap);
422
+ const hasAnyExpectedFile = expectedFilenames.some(
423
+ (expectedFile) => mainFiles.has(expectedFile)
424
+ );
425
+ if (!hasAnyExpectedFile) {
426
+ notifications.push(
427
+ `\u26A0\uFE0F File "${file}" in "${otherPath ?? ""}" should have a corresponding file in "${mainFolderToCheck}"`
428
+ );
429
+ }
430
+ }
431
+ }
432
+ }
433
+ return notifications;
434
+ };
435
+ const ensureOutputPath = (path) => {
436
+ if (!path.includes("/") && !path.includes("\\")) {
437
+ return path;
438
+ }
439
+ const dir = path.substring(0, path.lastIndexOf("/"));
440
+ if (!Bun.file(dir).exists()) {
441
+ throw new Error(
442
+ `Output directory "${dir}" does not exist. Please provide a valid directory path.`
443
+ );
444
+ }
445
+ return path;
446
+ };
447
+ const ensureConfigPath = async (path) => {
448
+ if (!await Bun.file(path).exists()) {
449
+ throw new Error(
450
+ `Configuration file "${path}" does not exist. Please provide a valid path to a JSON configuration file.`
451
+ );
452
+ }
453
+ return path;
454
+ };
455
+ const buildHtml = (title, paths, trees, extMap) => {
456
+ const lines = [
457
+ "<!DOCTYPE html>",
458
+ "<html lang='en'>",
459
+ "<head>",
460
+ " <meta charset='UTF-8'>",
461
+ " <meta name='viewport' content='width=device-width, initial-scale=1.0'>",
462
+ " <title>" + title + "</title>",
463
+ " <style>",
464
+ " body { font-family: system-ui, -apple-system, sans-serif; line-height: 1.5; max-width: 1200px; margin: 0 auto; padding: 2rem; }",
465
+ " table { border-collapse: collapse; width: 100%; margin: 1rem 0; }",
466
+ " th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }",
467
+ " th { background-color: #f5f5f5; }",
468
+ " tr:nth-child(even) { background-color: #f9f9f9; }",
469
+ " .toc { margin: 2rem 0; }",
470
+ " .toc a { color: #0366d6; text-decoration: none; }",
471
+ " .toc a:hover { text-decoration: underline; }",
472
+ " h1 { border-bottom: 2px solid #eaecef; padding-bottom: 0.3em; }",
473
+ " h2 { margin-top: 2rem; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }",
474
+ " .has-diff { color: #dc2626; }",
475
+ " .has-diff::before { content: '\u2022 '; }",
476
+ " .diff-row { background-color: #fee2e2 !important; }",
477
+ " </style>",
478
+ "</head>",
479
+ "<body>",
480
+ " <h1>" + title + "</h1>",
481
+ " <div class='toc'>",
482
+ " <h2>Table of Contents</h2>"
483
+ ];
484
+ const mainTree = trees[0];
485
+ if (!mainTree) {
486
+ throw new Error("No trees provided for HTML generation");
487
+ }
488
+ const folderList = [...mainTree.folders.keys()].sort();
489
+ const mainPath = paths[0];
490
+ if (!mainPath) {
491
+ throw new Error("No main path provided for HTML generation");
492
+ }
493
+ const hasFolderDifferences = (folder) => {
494
+ const canonicalFiles = /* @__PURE__ */ new Set();
495
+ for (let i = 0; i < trees.length; i++) {
496
+ const tree = trees[i];
497
+ if (!tree) continue;
498
+ const mappedFolder = paths[i]?.includes("dist-libs") ? mapDistLibsFolderToLibs(folder, paths[i], paths) || folder : folder;
499
+ const folderFiles = tree.folders.get(mappedFolder ?? "");
500
+ if (folderFiles?.size) {
501
+ for (const filename of folderFiles) {
502
+ const canonical = getCanonicalFilename(filename, extMap, mappedFolder ?? "");
503
+ canonicalFiles.add(canonical);
504
+ }
505
+ }
506
+ }
507
+ const mainFiles = mainTree.folders.get(folder);
508
+ if (!mainFiles) return canonicalFiles.size > 0;
509
+ for (const canonicalFile of canonicalFiles) {
510
+ const expectedFilenames = getExpectedFilenames(canonicalFile, paths[0] ?? "", extMap);
511
+ for (const expectedFilename of expectedFilenames) {
512
+ if (!mainFiles.has(expectedFilename)) {
513
+ return true;
514
+ }
515
+ }
516
+ }
517
+ return false;
518
+ };
519
+ for (const folder of folderList) {
520
+ const header = folder === "" ? basename(mainPath) : normalizePath(folder);
521
+ const anchor = folder === "" ? basename(mainPath) : generateAnchor(folder);
522
+ const hasDiff = hasFolderDifferences(folder);
523
+ const diffClass = hasDiff ? " has-diff" : "";
524
+ lines.push(` <a href="#${anchor}" class="${diffClass}">${header}</a><br>`);
525
+ }
526
+ for (const folder of folderList) {
527
+ const header = folder === "" ? basename(mainPath) : normalizePath(folder);
528
+ const anchor = folder === "" ? basename(mainPath) : generateAnchor(folder);
529
+ lines.push(` <h2 id="${anchor}">${header}</h2>`);
530
+ lines.push(" <table>");
531
+ lines.push(" <thead>");
532
+ lines.push(" <tr>");
533
+ for (const path of paths) {
534
+ lines.push(` <th>${normalizePath(path)}</th>`);
535
+ }
536
+ lines.push(" </tr>");
537
+ lines.push(" </thead>");
538
+ lines.push(" <tbody>");
539
+ const canonicalFiles = /* @__PURE__ */ new Set();
540
+ for (let i = 0; i < trees.length; i++) {
541
+ const tree = trees[i];
542
+ if (!tree) continue;
543
+ const mappedFolder = paths[i]?.includes("dist-libs") ? mapDistLibsFolderToLibs(folder, paths[i], paths) || folder : folder;
544
+ const folderFiles = tree.folders.get(mappedFolder ?? "");
545
+ if (folderFiles?.size) {
546
+ for (const filename of folderFiles) {
547
+ const canonical = getCanonicalFilename(filename, extMap, mappedFolder ?? "");
548
+ canonicalFiles.add(canonical);
549
+ }
550
+ }
551
+ }
552
+ for (const canonicalFilename of [...canonicalFiles].sort()) {
553
+ const mainFiles = mainTree.folders.get(folder);
554
+ const expectedFilenames = getExpectedFilenames(canonicalFilename, paths[0] ?? "", extMap);
555
+ const hasDiff = mainFiles && expectedFilenames.some((f) => !mainFiles.has(f));
556
+ const diffClass = hasDiff ? " class='diff-row'" : "";
557
+ lines.push(` <tr${diffClass}>`);
558
+ for (let i = 0; i < paths.length; i++) {
559
+ const tree = trees[i];
560
+ if (!tree) {
561
+ lines.push(" <td></td>");
562
+ continue;
563
+ }
564
+ const mappedFolder = paths[i]?.includes("dist-libs") ? mapDistLibsFolderToLibs(folder, paths[i], paths) || folder : folder;
565
+ const folderFiles = tree.folders.get(mappedFolder ?? "");
566
+ const matched = folderFiles?.size ? Array.from(folderFiles).filter(
567
+ (f) => getCanonicalFilename(f, extMap, mappedFolder ?? "") === canonicalFilename
568
+ ) : [];
569
+ lines.push(` <td>${matched.length ? matched.join(", ") : ""}</td>`);
570
+ }
571
+ lines.push(" </tr>");
572
+ }
573
+ lines.push(" </tbody>");
574
+ lines.push(" </table>");
575
+ }
576
+ lines.push("</body>");
577
+ lines.push("</html>");
578
+ return lines.join("\n");
579
+ };
580
+ const getFormatFromExtension = (filePath) => {
581
+ const parts = filePath.split(".");
582
+ if (parts.length <= 1 || parts.length === 2 && parts[1] === "") {
583
+ throw new Error(
584
+ `Invalid output file: "${filePath}". File must have either .md or .html extension.`
585
+ );
586
+ }
587
+ const ext = parts.pop()?.toLowerCase();
588
+ if (ext === "md") return "markdown";
589
+ if (ext === "html") return "html";
590
+ throw new Error(
591
+ `Invalid output file extension: "${ext}". Only .md and .html extensions are supported.`
592
+ );
593
+ };
594
+ const createDefaultConfig = async (path) => {
595
+ const ext = path.split(".").pop()?.toLowerCase();
596
+ const isTs = ext === "ts";
597
+ const config = {
598
+ title: "Directory Comparison",
599
+ dirs: {
600
+ src: {},
601
+ "dist-npm/bin": {},
602
+ "dist-jsr/bin": {},
603
+ "dist-libs": {}
604
+ }
605
+ };
606
+ let content;
607
+ if (isTs) {
608
+ content = `import type { ConfigRemdn } from "@reliverse/remdn";
609
+ const config: ConfigRemdn = ${JSON.stringify(config, null, 2)};
610
+ export default config;
611
+ `;
612
+ } else {
613
+ content = JSON.stringify(config, null, 2);
614
+ }
615
+ const dir = path.substring(0, path.lastIndexOf("/"));
616
+ if (dir && !await Bun.file(dir).exists()) {
617
+ await Bun.write(dir, "");
618
+ }
619
+ await writeFile(path, content);
620
+ console.log(`\u2705 Created new configuration file at ${path}`);
621
+ };
622
+ export async function scanDirectories(config, configPath, outputPath) {
623
+ const resolvedConfig = config ?? await readConfig(configPath);
624
+ const resolvedOutputPath = outputPath ?? resolvedConfig.output ?? "table.html";
625
+ validateOutputPath(resolvedOutputPath);
626
+ const outFile = ensureOutputPath(resolvedOutputPath);
627
+ const format = getFormatFromExtension(outFile);
628
+ const dirPaths = Object.keys(resolvedConfig.dirs);
629
+ if (dirPaths.length === 0) {
630
+ throw new Error("No directories specified in configuration");
631
+ }
632
+ const trees = await pMap(
633
+ dirPaths,
634
+ (dir) => {
635
+ const options = resolvedConfig.dirs[dir];
636
+ if (!options) {
637
+ throw new Error(`No options found for directory: ${dir}`);
638
+ }
639
+ return scanDir(dir, options);
640
+ },
641
+ { concurrency: 4 }
642
+ );
643
+ const [mainTree, ...otherTrees] = trees;
644
+ if (!mainTree) {
645
+ throw new Error("Failed to scan main directory");
646
+ }
647
+ const missingFiles = resolvedConfig["ext-map"] ? findMissingFiles(mainTree, otherTrees, dirPaths, resolvedConfig["ext-map"]) : [];
648
+ if (missingFiles.length > 0) {
649
+ console.log("\nFile comparison notifications:");
650
+ for (const msg of missingFiles) {
651
+ console.log(msg);
652
+ }
653
+ console.log("");
654
+ }
655
+ const title = resolvedConfig.title ?? "File Comparison";
656
+ const content = format === "html" ? buildHtml(title, dirPaths, [mainTree, ...otherTrees], resolvedConfig["ext-map"]) : buildMarkdown(title, dirPaths, [mainTree, ...otherTrees], resolvedConfig["ext-map"]);
657
+ await writeFile(outFile, content, { flag: "w" });
658
+ console.log("\u2705 Generated " + outFile);
659
+ }
660
+ export default defineCommand({
661
+ meta: {
662
+ name: "remdn",
663
+ description: "Run remdn (undocs alternative)"
664
+ },
665
+ args: defineArgs({
666
+ mode: {
667
+ type: "string",
668
+ // - dirs-scan-only: scan directories and generate a table of files
669
+ // - dirs-scan-compare: compare directories and generate a table of files with extension checks
670
+ allowed: ["dirs-scan-only", "dirs-scan-compare"],
671
+ description: "Operation mode"
672
+ },
673
+ configPath: {
674
+ type: "string",
675
+ description: `Path to the configuration file. Can be:
676
+ - Just filename with .json or .ts extension (e.g. 'config.json', 'config.ts') - will look in current directory
677
+ - Full path with .json or .ts extension (e.g. '/path/to/config.json', '/path/to/config.ts') - must exist
678
+ If not provided, will use default configuration at ${DEFAULT_CONFIG_PATH}`
679
+ },
680
+ outputFilePath: {
681
+ type: "string",
682
+ description: "Path to the output file. Can be:\n- Just filename with .md or .html extension (e.g. 'output.md', 'output.html') - will be created in current directory\n- Full path with .md or .html extension (e.g. '/path/to/output.md', '/path/to/output.html') - directory must exist\nIf not provided, will use default: table.html"
683
+ },
684
+ initConfig: {
685
+ type: "string",
686
+ description: `Initialize a new configuration file. Can be:
687
+ - Just filename with .json or .ts extension (e.g. 'config.json', 'config.ts') - will be created in current directory
688
+ - Full path with .json or .ts extension (e.g. '/path/to/config.json', '/path/to/config.ts') - directory must exist
689
+ If not provided, will create at ${DEFAULT_CONFIG_PATH}`
690
+ }
691
+ }),
692
+ async run({ args }) {
693
+ let { configPath, outputFilePath, mode, initConfig } = args;
694
+ if (initConfig) {
695
+ initConfig = ensureOutputPath(initConfig);
696
+ validateConfigPath(initConfig);
697
+ await createDefaultConfig(initConfig);
698
+ return;
699
+ }
700
+ const config = configPath ? await readConfig(configPath) : await readConfig();
701
+ if (!outputFilePath) {
702
+ outputFilePath = config.output ?? "table.html";
703
+ } else {
704
+ outputFilePath = ensureOutputPath(outputFilePath);
705
+ validateOutputPath(outputFilePath);
706
+ }
707
+ if (configPath) {
708
+ configPath = await ensureConfigPath(configPath);
709
+ validateConfigPath(configPath);
710
+ }
711
+ if (!mode) {
712
+ mode = await selectPrompt({
713
+ title: "Select operation mode",
714
+ options: [
715
+ {
716
+ label: "Only scan directories and generate a table of files (recommended for most cases)",
717
+ value: "dirs-scan-only"
718
+ },
719
+ {
720
+ label: "Scan directories and generate a table of files + do extension checks",
721
+ value: "dirs-scan-compare"
722
+ }
723
+ ]
724
+ });
725
+ }
726
+ const finalConfig = mode === "dirs-scan-compare" ? config : {
727
+ ...config,
728
+ "ext-map": void 0
729
+ };
730
+ await scanDirectories(finalConfig, configPath, outputFilePath);
731
+ }
732
+ });