@gajae-code/utils 0.8.1 → 0.8.2
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/package.json +2 -2
- package/src/env.ts +5 -2
- package/src/frontmatter.ts +14 -2
- package/src/glob.ts +25 -13
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/utils",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.2",
|
|
5
5
|
"description": "Shared utilities for pi packages",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@gajae-code/natives": "0.8.
|
|
34
|
+
"@gajae-code/natives": "0.8.2",
|
|
35
35
|
"beautiful-mermaid": "^1.1.3",
|
|
36
36
|
"handlebars": "^4.7.9",
|
|
37
37
|
"winston": "^3.19.0",
|
package/src/env.ts
CHANGED
|
@@ -272,7 +272,10 @@ export function isCompiledBinary(): boolean {
|
|
|
272
272
|
|
|
273
273
|
const TRUTHY: Dict<boolean> = { "1": true, Y: true, TRUE: true, YES: true, ON: true };
|
|
274
274
|
export function $flag(name: string, def: boolean = false): boolean {
|
|
275
|
-
const value = $env[name];
|
|
275
|
+
const value = $env[name]?.trim();
|
|
276
276
|
if (!value) return def;
|
|
277
|
-
|
|
277
|
+
// Boolean-like env values are documented as case-insensitive (`1`/`true`/`yes`/`on`),
|
|
278
|
+
// so normalize before the lookup — otherwise `FOO=true` (the common lowercase spelling)
|
|
279
|
+
// would silently read as false while only `FOO=TRUE`/`FOO=1` worked.
|
|
280
|
+
return TRUTHY[value.toUpperCase()] === true;
|
|
278
281
|
}
|
package/src/frontmatter.ts
CHANGED
|
@@ -17,15 +17,27 @@ function stripLooseScalarTrailingCommas(metadata: string): string {
|
|
|
17
17
|
.join("\n");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function asFrontmatterRecord(parsed: unknown): Record<string, unknown> | null {
|
|
21
|
+
if (parsed === null) return null;
|
|
22
|
+
if (typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
23
|
+
throw new Error("YAML frontmatter root must be an object");
|
|
24
|
+
}
|
|
25
|
+
const prototype = Object.getPrototypeOf(parsed);
|
|
26
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
27
|
+
throw new Error("YAML frontmatter root must be an object");
|
|
28
|
+
}
|
|
29
|
+
return parsed as Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
function parseYamlMetadata(metadata: string): Record<string, unknown> | null {
|
|
21
33
|
const normalized = metadata.replaceAll("\t", " ");
|
|
22
34
|
try {
|
|
23
|
-
return YAML.parse(normalized)
|
|
35
|
+
return asFrontmatterRecord(YAML.parse(normalized));
|
|
24
36
|
} catch (strictError) {
|
|
25
37
|
const loose = stripLooseScalarTrailingCommas(normalized);
|
|
26
38
|
if (loose === normalized) throw strictError;
|
|
27
39
|
try {
|
|
28
|
-
return YAML.parse(loose)
|
|
40
|
+
return asFrontmatterRecord(YAML.parse(loose));
|
|
29
41
|
} catch {
|
|
30
42
|
throw strictError;
|
|
31
43
|
}
|
package/src/glob.ts
CHANGED
|
@@ -70,20 +70,25 @@ function parseGitignorePatterns(content: string, gitignoreDir: string, baseDir:
|
|
|
70
70
|
} else {
|
|
71
71
|
patterns.push(pattern);
|
|
72
72
|
}
|
|
73
|
+
} else if (pattern.includes("/") && !pattern.startsWith("**/")) {
|
|
74
|
+
// Separator in the middle: git anchors these to the .gitignore's
|
|
75
|
+
// directory, same as rooted patterns
|
|
76
|
+
const absolutePattern = path.join(gitignoreDir, pattern);
|
|
77
|
+
const relativeToBase = path.relative(baseDir, absolutePattern);
|
|
78
|
+
if (relativeToBase.startsWith("..")) {
|
|
79
|
+
// Pattern is outside the search directory, skip
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
pattern = relativeToBase.replace(/\\/g, "/");
|
|
83
|
+
patterns.push(pattern);
|
|
84
|
+
if (isDirectoryOnly) {
|
|
85
|
+
patterns.push(`${pattern}/**`);
|
|
86
|
+
}
|
|
73
87
|
} else {
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
patterns.push(`**/${pattern}
|
|
78
|
-
if (isDirectoryOnly) {
|
|
79
|
-
patterns.push(`**/${pattern}/**`);
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
// No slash: match file/dir name anywhere
|
|
83
|
-
patterns.push(`**/${pattern}`);
|
|
84
|
-
if (isDirectoryOnly) {
|
|
85
|
-
patterns.push(`**/${pattern}/**`);
|
|
86
|
-
}
|
|
88
|
+
// No middle separator: match file/dir name anywhere in the tree
|
|
89
|
+
patterns.push(`**/${pattern}`);
|
|
90
|
+
if (isDirectoryOnly) {
|
|
91
|
+
patterns.push(`**/${pattern}/**`);
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
}
|
|
@@ -149,6 +154,9 @@ export async function globPaths(patterns: string | string[], options: GlobPathsO
|
|
|
149
154
|
|
|
150
155
|
const base = cwd ?? getProjectDir();
|
|
151
156
|
const allResults: string[] = [];
|
|
157
|
+
// Overlapping patterns (e.g. `["**/*.ts", "src/*.ts"]`) can both match the same
|
|
158
|
+
// file; dedupe so a path is returned at most once regardless of pattern overlap.
|
|
159
|
+
const seen = new Set<string>();
|
|
152
160
|
|
|
153
161
|
// Combine timeout and abort signals
|
|
154
162
|
const timeoutSignal = timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined;
|
|
@@ -176,6 +184,10 @@ export async function globPaths(patterns: string | string[], options: GlobPathsO
|
|
|
176
184
|
if (excludeGlobs.some(excludeGlob => excludeGlob.match(normalized))) {
|
|
177
185
|
continue;
|
|
178
186
|
}
|
|
187
|
+
if (seen.has(normalized)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
seen.add(normalized);
|
|
179
191
|
allResults.push(normalized);
|
|
180
192
|
}
|
|
181
193
|
}
|