@cldmv/slothlet 1.0.3 → 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.
- package/README.md +913 -73
- package/dist/lib/engine/README.md +21 -0
- package/dist/lib/engine/slothlet_child.mjs +58 -0
- package/dist/lib/engine/slothlet_engine.mjs +371 -0
- package/dist/lib/engine/slothlet_esm.mjs +229 -0
- package/dist/lib/engine/slothlet_helpers.mjs +454 -0
- package/dist/lib/engine/slothlet_worker.mjs +148 -0
- package/dist/lib/helpers/resolve-from-caller.mjs +141 -0
- package/dist/lib/helpers/sanitize.mjs +265 -0
- package/dist/lib/modes/slothlet_eager.mjs +80 -0
- package/dist/lib/modes/slothlet_lazy.mjs +342 -0
- package/dist/lib/runtime/runtime.mjs +249 -0
- package/dist/slothlet.mjs +1097 -0
- package/index.cjs +81 -0
- package/index.mjs +76 -0
- package/package.json +132 -20
- package/types/dist/lib/engine/slothlet_child.d.mts +2 -0
- package/types/dist/lib/engine/slothlet_child.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_engine.d.mts +31 -0
- package/types/dist/lib/engine/slothlet_engine.d.mts.map +1 -0
- package/types/{src/lib → dist/lib/engine}/slothlet_esm.d.mts +1 -0
- package/types/dist/lib/engine/slothlet_esm.d.mts.map +1 -0
- package/types/{src/lib → dist/lib/engine}/slothlet_helpers.d.mts +2 -2
- package/types/dist/lib/engine/slothlet_helpers.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_worker.d.mts +2 -0
- package/types/dist/lib/engine/slothlet_worker.d.mts.map +1 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +149 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -0
- package/types/dist/lib/helpers/sanitize.d.mts +79 -0
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -0
- package/types/dist/lib/modes/slothlet_eager.d.mts +66 -0
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +1 -0
- package/types/dist/lib/modes/slothlet_lazy.d.mts +32 -0
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime.d.mts +49 -0
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -0
- package/types/dist/slothlet.d.mts +124 -0
- package/types/dist/slothlet.d.mts.map +1 -0
- package/types/index.d.mts +23 -0
- package/slothlet.mjs +0 -1248
- package/types/debug-slothlet.d.mts +0 -1
- package/types/eslint.config.d.mts +0 -2
- package/types/jest.config.d.mts +0 -6
- package/types/slothlet.d.mts +0 -189
- package/types/src/lib/slothlet_child.d.mts +0 -1
- package/types/src/lib/slothlet_engine.d.mts +0 -6
- package/types/src/lib/slothlet_worker.d.mts +0 -1
- package/types/vitest.config.d.ts +0 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
export const toFsPath = (v) => (v && String(v).startsWith("file://") ? fileURLToPath(String(v)) : v ? String(v) : null);
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export function getStack(skipFn) {
|
|
31
|
+
const orig = Error.prepareStackTrace;
|
|
32
|
+
try {
|
|
33
|
+
Error.prepareStackTrace = (_, s) => s;
|
|
34
|
+
const e = new Error("Stack trace");
|
|
35
|
+
if (skipFn) Error.captureStackTrace(e, skipFn);
|
|
36
|
+
return e.stack || [];
|
|
37
|
+
} finally {
|
|
38
|
+
Error.prepareStackTrace = orig;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const THIS_FILE = fileURLToPath(import.meta.url);
|
|
43
|
+
const THIS_DIR = path.dirname(THIS_FILE);
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
function pickPrimaryBaseFile() {
|
|
53
|
+
const files = [];
|
|
54
|
+
for (const cs of getStack(pickPrimaryBaseFile)) {
|
|
55
|
+
const f = toFsPath(cs?.getFileName?.());
|
|
56
|
+
if (!f) continue;
|
|
57
|
+
if (f.startsWith?.("node:internal")) continue;
|
|
58
|
+
files.push(f);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let iSloth = -1;
|
|
62
|
+
for (let i = 0; i < files.length; i++) {
|
|
63
|
+
if (path.basename(files[i]).toLowerCase() === "slothlet.mjs") iSloth = i;
|
|
64
|
+
}
|
|
65
|
+
if (iSloth !== -1) {
|
|
66
|
+
const j = iSloth + 1;
|
|
67
|
+
if (j < files.length) {
|
|
68
|
+
const b = path.basename(files[j]).toLowerCase();
|
|
69
|
+
if (/^index\.(mjs|cjs|js)$/.test(b) && j + 1 < files.length) return files[j + 1];
|
|
70
|
+
return files[j];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
function pickFallbackBaseFile() {
|
|
78
|
+
for (const cs of getStack(pickFallbackBaseFile)) {
|
|
79
|
+
const f = toFsPath(cs?.getFileName?.());
|
|
80
|
+
if (!f) continue;
|
|
81
|
+
if (f.startsWith?.("node:internal")) continue;
|
|
82
|
+
if (f === THIS_FILE) continue;
|
|
83
|
+
if (f.startsWith(THIS_DIR + path.sep)) continue;
|
|
84
|
+
if (path.basename(f).toLowerCase() === "slothlet.mjs") continue;
|
|
85
|
+
return f;
|
|
86
|
+
}
|
|
87
|
+
return THIS_FILE;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
function resolveWith(rel, makePrimary, exists, makeFallback) {
|
|
94
|
+
if (typeof rel !== "string") throw new TypeError("rel must be a string");
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
const primaryBase = pickPrimaryBaseFile() ?? pickFallbackBaseFile();
|
|
98
|
+
const primary = makePrimary(primaryBase, rel);
|
|
99
|
+
if (exists(primary)) return primary;
|
|
100
|
+
|
|
101
|
+
const fbBase = pickFallbackBaseFile();
|
|
102
|
+
return makeFallback(fbBase, rel);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
export function resolvePathFromCaller(rel) {
|
|
109
|
+
|
|
110
|
+
if (rel.startsWith?.("file://")) return fileURLToPath(rel);
|
|
111
|
+
if (path.isAbsolute(rel)) return rel;
|
|
112
|
+
|
|
113
|
+
return resolveWith(
|
|
114
|
+
rel,
|
|
115
|
+
|
|
116
|
+
(baseFile, r) => path.resolve(path.dirname(baseFile), r),
|
|
117
|
+
|
|
118
|
+
(candidate) => fs.existsSync(candidate),
|
|
119
|
+
|
|
120
|
+
(baseFile, r) => path.resolve(path.dirname(baseFile), r)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
export function resolveUrlFromCaller(rel) {
|
|
126
|
+
|
|
127
|
+
if (rel.startsWith?.("file://")) return rel;
|
|
128
|
+
if (path.isAbsolute(rel)) return pathToFileURL(rel).href;
|
|
129
|
+
|
|
130
|
+
return resolveWith(
|
|
131
|
+
rel,
|
|
132
|
+
|
|
133
|
+
(baseFile, r) => new URL(r, pathToFileURL(baseFile)).href,
|
|
134
|
+
|
|
135
|
+
(href) => fs.existsSync(fileURLToPath(href)),
|
|
136
|
+
|
|
137
|
+
(baseFile, r) => new URL(r, pathToFileURL(baseFile)).href
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
function globToRegex(pattern, caseSensitive = true) {
|
|
21
|
+
try {
|
|
22
|
+
|
|
23
|
+
if (pattern.startsWith("**") && pattern.endsWith("**") && pattern.length > 4) {
|
|
24
|
+
const innerString = pattern.slice(2, -2);
|
|
25
|
+
|
|
26
|
+
const escapedString = innerString.replace(/[.+^${}()|[\]\\*?]/g, "\\$&");
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const flags = caseSensitive ? "" : "i";
|
|
30
|
+
return new RegExp(`(?<=.)${escapedString}(?=.)`, flags);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
let regexPattern = pattern
|
|
36
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
37
|
+
.replace(/\*/g, ".*")
|
|
38
|
+
.replace(/\?/g, ".");
|
|
39
|
+
|
|
40
|
+
const flags = caseSensitive ? "" : "i";
|
|
41
|
+
return new RegExp(`^${regexPattern}$`, flags);
|
|
42
|
+
} catch (_) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
export function sanitizePathName(input, opts = {}) {
|
|
49
|
+
const { lowerFirst = true, rules = {} } = opts;
|
|
50
|
+
|
|
51
|
+
const leaveRules = (rules.leave || []).map((s) => String(s));
|
|
52
|
+
const leaveInsensitiveRules = (rules.leaveInsensitive || []).map((s) => String(s));
|
|
53
|
+
const upperRules = (rules.upper || []).map((s) => String(s));
|
|
54
|
+
const lowerRules = (rules.lower || []).map((s) => String(s));
|
|
55
|
+
|
|
56
|
+
let s = String(input).trim();
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
let parts = s.split(/[^A-Za-z0-9_$]+/).filter(Boolean);
|
|
63
|
+
if (parts.length === 0) return "_";
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
while (parts.length && !/^[A-Za-z_$]/.test(parts[0][0])) {
|
|
67
|
+
parts[0] = parts[0].replace(/^[^A-Za-z_$]+/, "");
|
|
68
|
+
if (!parts[0]) parts.shift();
|
|
69
|
+
}
|
|
70
|
+
if (parts.length === 0) return "_";
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
const segmentMatchesPreSplitPattern = (segment, patterns, caseSensitive = false) => {
|
|
74
|
+
for (const pattern of patterns) {
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
80
|
+
const regex = globToRegex(pattern, caseSensitive);
|
|
81
|
+
if (regex && regex.test(s)) {
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
const literalParts = pattern.split(/[*?]+/).filter(Boolean);
|
|
85
|
+
|
|
86
|
+
for (const literal of literalParts) {
|
|
87
|
+
|
|
88
|
+
const cleanLiteral = literal.replace(/[^A-Za-z0-9_$]/g, "");
|
|
89
|
+
if (cleanLiteral) {
|
|
90
|
+
const match = caseSensitive ? segment === cleanLiteral : segment.toLowerCase() === cleanLiteral.toLowerCase();
|
|
91
|
+
if (match) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
|
|
99
|
+
const match = caseSensitive ? segment === pattern : segment.toLowerCase() === pattern.toLowerCase();
|
|
100
|
+
if (match) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const applyRule = (seg, index) => {
|
|
109
|
+
|
|
110
|
+
if (segmentMatchesPreSplitPattern(seg, leaveRules, true)) {
|
|
111
|
+
return seg;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if (segmentMatchesPreSplitPattern(seg, leaveInsensitiveRules, false)) {
|
|
116
|
+
return seg;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if (segmentMatchesPreSplitPattern(seg, upperRules, false)) {
|
|
121
|
+
return seg.toUpperCase();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if (segmentMatchesPreSplitPattern(seg, lowerRules, false)) {
|
|
126
|
+
return seg.toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
let transformedSeg = seg;
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
for (const pattern of upperRules) {
|
|
134
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
135
|
+
|
|
136
|
+
if (!segmentMatchesPreSplitPattern(seg, [pattern], false)) {
|
|
137
|
+
|
|
138
|
+
if (pattern.startsWith("**") && pattern.endsWith("**") && pattern.length > 4) {
|
|
139
|
+
const innerString = pattern.slice(2, -2);
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
const innerRegex = new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g, "\\$&"), "gi");
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
const matches = [...transformedSeg.matchAll(innerRegex)];
|
|
146
|
+
for (const match of matches) {
|
|
147
|
+
const startPos = match.index;
|
|
148
|
+
const endPos = startPos + match[0].length;
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
const hasCharBefore = startPos > 0;
|
|
152
|
+
const hasCharAfter = endPos < transformedSeg.length;
|
|
153
|
+
|
|
154
|
+
if (hasCharBefore && hasCharAfter) {
|
|
155
|
+
|
|
156
|
+
transformedSeg = transformedSeg.substring(0, startPos) + innerString.toUpperCase() + transformedSeg.substring(endPos);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
|
|
162
|
+
const literalParts = pattern.split(/[*?]+/).filter(Boolean);
|
|
163
|
+
for (const literal of literalParts) {
|
|
164
|
+
if (literal) {
|
|
165
|
+
|
|
166
|
+
const literalRegex = new RegExp(literal.replace(/[.+^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
167
|
+
transformedSeg = transformedSeg.replace(literalRegex, literal.toUpperCase());
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
for (const pattern of lowerRules) {
|
|
177
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
178
|
+
|
|
179
|
+
if (!segmentMatchesPreSplitPattern(seg, [pattern], false)) {
|
|
180
|
+
|
|
181
|
+
if (pattern.startsWith("**") && pattern.endsWith("**") && pattern.length > 4) {
|
|
182
|
+
const innerString = pattern.slice(2, -2);
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
const innerRegex = new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g, "\\$&"), "gi");
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
const matches = [...transformedSeg.matchAll(innerRegex)];
|
|
189
|
+
for (const match of matches) {
|
|
190
|
+
const startPos = match.index;
|
|
191
|
+
const endPos = startPos + match[0].length;
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
const hasCharBefore = startPos > 0;
|
|
195
|
+
const hasCharAfter = endPos < transformedSeg.length;
|
|
196
|
+
|
|
197
|
+
if (hasCharBefore && hasCharAfter) {
|
|
198
|
+
|
|
199
|
+
transformedSeg = transformedSeg.substring(0, startPos) + innerString.toLowerCase() + transformedSeg.substring(endPos);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
|
|
205
|
+
const literalParts = pattern.split(/[*?]+/).filter(Boolean);
|
|
206
|
+
for (const literal of literalParts) {
|
|
207
|
+
if (literal) {
|
|
208
|
+
const literalRegex = new RegExp(literal.replace(/[.+^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
209
|
+
transformedSeg = transformedSeg.replace(literalRegex, literal.toLowerCase());
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
for (const pattern of upperRules) {
|
|
220
|
+
if (!pattern.includes("*") && !pattern.includes("?")) {
|
|
221
|
+
|
|
222
|
+
const match = seg.toLowerCase() === pattern.toLowerCase();
|
|
223
|
+
if (match) {
|
|
224
|
+
return seg.toUpperCase();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
for (const pattern of lowerRules) {
|
|
231
|
+
if (!pattern.includes("*") && !pattern.includes("?")) {
|
|
232
|
+
|
|
233
|
+
const match = seg.toLowerCase() === pattern.toLowerCase();
|
|
234
|
+
if (match) {
|
|
235
|
+
return seg.toLowerCase();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
if (transformedSeg !== seg) {
|
|
242
|
+
return transformedSeg;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
if (index === 0) {
|
|
247
|
+
|
|
248
|
+
return lowerFirst ? seg[0].toLowerCase() + seg.slice(1) : seg;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return seg[0].toUpperCase() + seg.slice(1);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
let out = parts.map((seg, i) => applyRule(seg.replace(/[^A-Za-z0-9_$]/g, ""), i)).join("");
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
out = out.replace(/[^A-Za-z0-9_$]/g, "");
|
|
259
|
+
if (!out || !/^[A-Za-z_$]/.test(out[0])) out = "_" + out;
|
|
260
|
+
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
import fs from "fs/promises";
|
|
22
|
+
import path from "path";
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
export async function create(dir, rootLevel = true, maxDepth = Infinity, currentDepth = 0) {
|
|
30
|
+
|
|
31
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
32
|
+
const api = {};
|
|
33
|
+
|
|
34
|
+
const rootNamedExports = {};
|
|
35
|
+
|
|
36
|
+
let rootDefaultFunction = null;
|
|
37
|
+
|
|
38
|
+
if (rootLevel) {
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
if (this._shouldIncludeFile(entry)) {
|
|
41
|
+
const ext = path.extname(entry.name);
|
|
42
|
+
const fileName = path.basename(entry.name, ext);
|
|
43
|
+
const apiKey = this._toApiKey(fileName);
|
|
44
|
+
const mod = await this._loadSingleModule(path.join(dir, entry.name), true);
|
|
45
|
+
if (mod && typeof mod.default === "function") {
|
|
46
|
+
if (!rootDefaultFunction) rootDefaultFunction = mod.default;
|
|
47
|
+
for (const [key, value] of Object.entries(mod)) {
|
|
48
|
+
if (key !== "default") api[key] = value;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
api[apiKey] = mod;
|
|
52
|
+
for (const [key, value] of Object.entries(mod)) {
|
|
53
|
+
rootNamedExports[key] = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && currentDepth < maxDepth) {
|
|
62
|
+
const categoryPath = path.join(dir, entry.name);
|
|
63
|
+
api[this._toApiKey(entry.name)] = await this._loadCategory(categoryPath, currentDepth + 1, maxDepth);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let finalApi;
|
|
68
|
+
if (rootDefaultFunction) {
|
|
69
|
+
Object.assign(rootDefaultFunction, api);
|
|
70
|
+
finalApi = rootDefaultFunction;
|
|
71
|
+
} else {
|
|
72
|
+
finalApi = api;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
return finalApi;
|
|
80
|
+
}
|