typed-settings 0.1.4 → 0.2.1

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 (81) hide show
  1. package/README.md +14 -7
  2. package/bin/typed-settings.mjs +5 -0
  3. package/dist/adapters/joi.cjs +1 -26
  4. package/dist/adapters/joi.d.cts +2 -1
  5. package/dist/adapters/joi.d.ts +2 -1
  6. package/dist/adapters/joi.js +1 -1
  7. package/dist/adapters/superstruct.cjs +1 -26
  8. package/dist/adapters/superstruct.js +1 -1
  9. package/dist/adapters/yup.cjs +1 -25
  10. package/dist/adapters/yup.js +1 -1
  11. package/dist/adapters/zod.cjs +3 -36
  12. package/dist/adapters/zod.js +1 -33
  13. package/dist/check-XVFZEVNV.js +1 -0
  14. package/dist/chunk-4EAMKDNK.js +3 -0
  15. package/dist/chunk-5D2AQWDG.js +1 -0
  16. package/dist/chunk-C6CG2D4B.js +2 -0
  17. package/dist/chunk-FQYD5ZKE.js +1 -0
  18. package/dist/chunk-NQDE3WLR.js +3 -0
  19. package/dist/chunk-RURPDXIJ.js +1 -0
  20. package/dist/cli/main.cjs +36 -2225
  21. package/dist/cli/main.js +32 -806
  22. package/dist/errors-JkkOM0u-.d.cts +25 -0
  23. package/dist/errors-JkkOM0u-.d.ts +25 -0
  24. package/dist/framework/next.cjs +5 -1158
  25. package/dist/framework/next.d.cts +3 -3
  26. package/dist/framework/next.d.ts +3 -3
  27. package/dist/framework/next.js +1 -15
  28. package/dist/framework/vite.cjs +5 -1156
  29. package/dist/framework/vite.d.cts +8 -3
  30. package/dist/framework/vite.d.ts +8 -3
  31. package/dist/framework/vite.js +1 -14
  32. package/dist/index.cjs +5 -1181
  33. package/dist/index.d.cts +38 -7
  34. package/dist/index.d.ts +38 -7
  35. package/dist/index.js +1 -6
  36. package/dist/node.cjs +6 -1241
  37. package/dist/node.d.cts +23 -9
  38. package/dist/node.d.ts +23 -9
  39. package/dist/node.js +1 -7
  40. package/dist/{types-B_Dc2L4T.d.cts → types-CcsYDAdO.d.cts} +23 -1
  41. package/dist/{types-B_Dc2L4T.d.ts → types-CcsYDAdO.d.ts} +23 -1
  42. package/dist/vault/aws.cjs +4 -217
  43. package/dist/vault/aws.d.cts +1 -1
  44. package/dist/vault/aws.d.ts +1 -1
  45. package/dist/vault/aws.js +2 -167
  46. package/dist/vault/hashicorp.cjs +4 -183
  47. package/dist/vault/hashicorp.d.cts +1 -1
  48. package/dist/vault/hashicorp.d.ts +1 -1
  49. package/dist/vault/hashicorp.js +2 -77
  50. package/dist/vault/http.cjs +4 -185
  51. package/dist/vault/http.d.cts +1 -1
  52. package/dist/vault/http.d.ts +1 -1
  53. package/dist/vault/http.js +2 -79
  54. package/package.json +2 -3
  55. package/dist/chunk-33M5GIKQ.js +0 -13
  56. package/dist/chunk-A5TCQJ7L.js +0 -65
  57. package/dist/chunk-DEP5SD4J.js +0 -233
  58. package/dist/chunk-EE6LXNJV.js +0 -34
  59. package/dist/chunk-F6DX3HXZ.js +0 -101
  60. package/dist/chunk-OVFMKC2O.js +0 -15
  61. package/dist/chunk-RQC6OMVV.js +0 -86
  62. package/dist/chunk-UFUHHR2J.js +0 -38
  63. package/dist/chunk-YVJEZPPZ.js +0 -989
  64. package/dist/errors-itGaU4Q8.d.cts +0 -17
  65. package/dist/errors-itGaU4Q8.d.ts +0 -17
  66. package/dist/formats/env.cjs +0 -103
  67. package/dist/formats/env.d.cts +0 -8
  68. package/dist/formats/env.d.ts +0 -8
  69. package/dist/formats/env.js +0 -1
  70. package/dist/formats/json.cjs +0 -15
  71. package/dist/formats/json.d.cts +0 -7
  72. package/dist/formats/json.d.ts +0 -7
  73. package/dist/formats/json.js +0 -1
  74. package/dist/formats/toml.cjs +0 -17
  75. package/dist/formats/toml.d.cts +0 -7
  76. package/dist/formats/toml.d.ts +0 -7
  77. package/dist/formats/toml.js +0 -1
  78. package/dist/formats/yaml.cjs +0 -40
  79. package/dist/formats/yaml.d.cts +0 -8
  80. package/dist/formats/yaml.d.ts +0 -8
  81. package/dist/formats/yaml.js +0 -1
@@ -1,65 +0,0 @@
1
- // src/adapters/legacy.ts
2
- function yupAdapter(schema) {
3
- return {
4
- "~standard": {
5
- version: 1,
6
- vendor: "typed-settings.yup",
7
- validate: (input) => {
8
- try {
9
- const value = schema.validateSync(input, { stripUnknown: true, abortEarly: false });
10
- return { value };
11
- } catch (e) {
12
- const err = e;
13
- const issues = (err.inner?.length ? err.inner : [{ path: "<root>", message: err.message ?? String(e) }]).map(
14
- (i) => ({ message: String(i.message ?? String(e)), path: i.path ? [i.path] : void 0 })
15
- );
16
- return { issues };
17
- }
18
- }
19
- }
20
- };
21
- }
22
- function joiAdapter(schema) {
23
- return {
24
- "~standard": {
25
- version: 1,
26
- vendor: "typed-settings.joi",
27
- validate: (input) => {
28
- let res;
29
- try {
30
- res = schema.validate(input, { abortEarly: false, convert: true, allowUnknown: true, stripUnknown: true });
31
- } catch (e) {
32
- const err = e;
33
- return { issues: [{ message: err?.message ?? String(e) }] };
34
- }
35
- if (!res.error) return { value: res.value };
36
- const issues = (res.error.details ?? []).map((d) => ({ message: d.message, path: d.path.map(String) }));
37
- if (issues.length === 0) return { issues: [{ message: res.error.message ?? "Invalid input" }] };
38
- return { issues };
39
- }
40
- }
41
- };
42
- }
43
- function superstructAdapter(schema) {
44
- return {
45
- "~standard": {
46
- version: 1,
47
- vendor: "typed-settings.superstruct",
48
- validate: (input) => {
49
- try {
50
- const value = schema.create(input);
51
- return { value };
52
- } catch (e) {
53
- const err = e;
54
- if (typeof err.failures === "function") {
55
- const issues = err.failures().map((f) => ({ message: f.message, path: f.path.map(String) }));
56
- if (issues.length > 0) return { issues };
57
- }
58
- return { issues: [{ message: err.message ?? String(e) }] };
59
- }
60
- }
61
- }
62
- };
63
- }
64
-
65
- export { joiAdapter, superstructAdapter, yupAdapter };
@@ -1,233 +0,0 @@
1
- import { settings } from './chunk-YVJEZPPZ.js';
2
- import { parseEnvText } from './chunk-F6DX3HXZ.js';
3
- import { readFileSync, readdirSync, statSync, watch } from 'fs';
4
- import { join, dirname, basename, resolve } from 'path';
5
-
6
- globalThis.__typedSettingsFs ??= {
7
- readFileSync: (p, e) => readFileSync(p, e)
8
- };
9
- function loadEnvFiles(paths) {
10
- const parts = [];
11
- for (const p of paths) {
12
- try {
13
- parts.push(readFileSync(p, "utf8"));
14
- } catch (e) {
15
- const err = e;
16
- if (err?.code === "ENOENT") continue;
17
- throw e;
18
- }
19
- }
20
- return { text: parts.join("\n") };
21
- }
22
- function loadSecretsDir(dir) {
23
- const out = {};
24
- let entries;
25
- try {
26
- entries = readdirSync(dir);
27
- } catch (e) {
28
- const err = e;
29
- if (err?.code === "ENOENT") return out;
30
- throw e;
31
- }
32
- for (const name of entries) {
33
- const full = join(dir, name);
34
- try {
35
- const st = statSync(full);
36
- if (!st.isFile()) continue;
37
- } catch (e) {
38
- const err = e;
39
- if (err?.code === "ENOENT") continue;
40
- throw e;
41
- }
42
- if (name.startsWith("..")) continue;
43
- let v;
44
- try {
45
- v = readFileSync(full, "utf8").replace(/\r?\n$/, "");
46
- } catch (e) {
47
- const err = e;
48
- if (err?.code === "ENOENT") continue;
49
- throw e;
50
- }
51
- if (!v) continue;
52
- out[name.toUpperCase()] = v;
53
- }
54
- return out;
55
- }
56
- function parseEnvFile(path) {
57
- try {
58
- const text = readFileSync(path, "utf8");
59
- return parseEnvText(text);
60
- } catch (e) {
61
- const err = e;
62
- if (err?.code === "ENOENT") return {};
63
- throw e;
64
- }
65
- }
66
- function extractWatchFiles(sources) {
67
- const out = [];
68
- for (const s of sources ?? []) {
69
- if (s === "env") continue;
70
- if (s === ".env" || s === ".env.local") out.push(resolve(s));
71
- else if (typeof s === "string") {
72
- const lower = s.toLowerCase();
73
- if (lower.endsWith(".env") || s === ".env.local" || lower.endsWith(".json") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".toml")) {
74
- out.push(resolve(s));
75
- } else if (!lower.endsWith(".env")) {
76
- out.push(resolve(s));
77
- }
78
- } else if (s && typeof s === "object" && "file" in s) {
79
- out.push(resolve(s.file));
80
- }
81
- }
82
- return [...new Set(out)];
83
- }
84
- function hasPollSources(sources) {
85
- return (sources ?? []).some(
86
- (s) => s && typeof s === "object" && ("dir" in s || "provider" in s || "load" in s)
87
- );
88
- }
89
- function diffLeafPaths(a, b, prefix = "") {
90
- if (Array.isArray(a) && Array.isArray(b)) {
91
- const out = [];
92
- const len = Math.max(a.length, b.length);
93
- for (let i = 0; i < len; i++) {
94
- const p = prefix ? `${prefix}[${i}]` : `[${i}]`;
95
- if (i >= a.length || i >= b.length) out.push(p);
96
- else out.push(...diffLeafPaths(a[i], b[i], p));
97
- }
98
- return out;
99
- }
100
- if (a && typeof a === "object" && b && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b)) {
101
- const out = [];
102
- const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
103
- for (const k of keys) {
104
- const p = prefix ? `${prefix}.${k}` : k;
105
- if (!(k in a) || !(k in b)) out.push(p);
106
- else out.push(...diffLeafPaths(a[k], b[k], p));
107
- }
108
- return out;
109
- }
110
- return JSON.stringify(a) === JSON.stringify(b) ? [] : [prefix || "<root>"];
111
- }
112
- async function stableSize(path, retries = 3) {
113
- for (let i = 0; i < retries; i++) {
114
- let s1 = null;
115
- let s2 = null;
116
- try {
117
- const st = statSync(path);
118
- s1 = { size: st.size, mtimeMs: st.mtimeMs };
119
- } catch {
120
- return;
121
- }
122
- await new Promise((r) => setTimeout(r, 20));
123
- try {
124
- const st = statSync(path);
125
- s2 = { size: st.size, mtimeMs: st.mtimeMs };
126
- } catch {
127
- return;
128
- }
129
- if (s1.size === s2.size && s1.mtimeMs === s2.mtimeMs) return;
130
- }
131
- }
132
- function watchSettings(opts, cb = {}) {
133
- const debounceMs = cb.debounceMs ?? 100;
134
- const refreshMs = cb.refreshMs ?? (hasPollSources(opts.sources) ? 6e4 : 0);
135
- const pollMs = cb.pollMs ?? 0;
136
- let current = settings(opts);
137
- let version = 0;
138
- let reloadId = 0;
139
- let disposed = false;
140
- let timer = null;
141
- const watchers = [];
142
- const intervals = [];
143
- const watchedDirs = /* @__PURE__ */ new Set();
144
- const handle = {
145
- get: () => current,
146
- reload: async () => {
147
- await doReload();
148
- },
149
- dispose: async () => {
150
- if (disposed) return;
151
- disposed = true;
152
- if (timer) clearTimeout(timer);
153
- for (const iv of intervals) clearInterval(iv);
154
- for (const w of watchers) {
155
- try {
156
- w.close();
157
- } catch {
158
- }
159
- }
160
- },
161
- get version() {
162
- return version;
163
- }
164
- };
165
- async function doReload() {
166
- const myId = ++reloadId;
167
- ensureWatchers();
168
- const files = extractWatchFiles(opts.sources);
169
- await Promise.all(
170
- files.map(
171
- (f) => stableSize(f).catch(() => {
172
- })
173
- )
174
- );
175
- if (disposed || myId !== reloadId) return;
176
- let next;
177
- try {
178
- next = settings(opts);
179
- } catch (e) {
180
- try {
181
- cb.onError?.(e, { version });
182
- } catch {
183
- }
184
- return;
185
- }
186
- if (disposed || myId !== reloadId) return;
187
- const changed = diffLeafPaths(current, next);
188
- current = next;
189
- version++;
190
- try {
191
- cb.onUpdate?.(current, changed);
192
- } catch {
193
- }
194
- }
195
- function scheduleReload() {
196
- if (disposed) return;
197
- if (timer) clearTimeout(timer);
198
- timer = setTimeout(() => {
199
- timer = null;
200
- void doReload();
201
- }, debounceMs);
202
- }
203
- function ensureWatchers() {
204
- for (const file of extractWatchFiles(opts.sources)) {
205
- const dir = dirname(file);
206
- const base = basename(file);
207
- const key = dir + "\0" + base;
208
- if (watchedDirs.has(key)) continue;
209
- try {
210
- const w = watch(dir, (_event, filename) => {
211
- const name = typeof filename === "string" ? filename : filename ? String(filename) : null;
212
- if (name && name !== base) return;
213
- scheduleReload();
214
- });
215
- w.on("error", () => {
216
- });
217
- watchers.push(w);
218
- watchedDirs.add(key);
219
- } catch {
220
- }
221
- }
222
- }
223
- ensureWatchers();
224
- if (pollMs > 0) {
225
- intervals.push(setInterval(scheduleReload, pollMs));
226
- }
227
- if (refreshMs > 0) {
228
- intervals.push(setInterval(scheduleReload, refreshMs));
229
- }
230
- return handle;
231
- }
232
-
233
- export { loadEnvFiles, loadSecretsDir, parseEnvFile, watchSettings };
@@ -1,34 +0,0 @@
1
- // src/errors.ts
2
- var SECRET_RE = /key|secret|token|password|private/i;
3
- function redactValue(key, value) {
4
- if (SECRET_RE.test(key) && typeof value === "string" && value.length > 0) {
5
- if (value.length <= 8) return "(redacted)";
6
- return `${value.slice(0, 3)}-*** (${value.length} chars)`;
7
- }
8
- return String(value);
9
- }
10
- function byteLengthUtf8(text) {
11
- try {
12
- const g = globalThis;
13
- if (g.TextEncoder) return new g.TextEncoder().encode(text).length;
14
- if (g.Buffer) return g.Buffer.byteLength(text, "utf8");
15
- } catch {
16
- }
17
- return text.length;
18
- }
19
- var ConfigError = class extends Error {
20
- code = "E_INVALID_CONFIG";
21
- issues;
22
- constructor(issues, code = "E_INVALID_CONFIG") {
23
- const lines = issues.map(
24
- (i) => `- ${i.path} (from ${i.from}): ${i.message}`
25
- );
26
- super(`Invalid config (${issues.length} issue${issues.length === 1 ? "" : "s"}):
27
- ${lines.join("\n")}`);
28
- this.name = "ConfigError";
29
- this.code = code;
30
- this.issues = issues;
31
- }
32
- };
33
-
34
- export { ConfigError, byteLengthUtf8, redactValue };
@@ -1,101 +0,0 @@
1
- // src/formats/env.ts
2
- function parseEnvText(text) {
3
- const out = {};
4
- if (text.charCodeAt(0) === 65279) text = text.slice(1);
5
- const lines = splitLogicalLines(text);
6
- for (const rawLine of lines) {
7
- let line = rawLine.trim();
8
- if (!line || line.startsWith("#")) continue;
9
- if (line.startsWith("export ")) line = line.slice(7).trimStart();
10
- const eq = line.indexOf("=");
11
- if (eq === -1) {
12
- throw new Error(`ParseError: bare key without '=': ${JSON.stringify(line)}`);
13
- }
14
- const key = line.slice(0, eq).trim();
15
- let rest = line.slice(eq + 1).trimStart();
16
- if (!key) throw new Error("ParseError: empty key");
17
- out[key] = parseValue(rest);
18
- }
19
- return out;
20
- }
21
- function splitLogicalLines(text) {
22
- const physical = text.split(/\r?\n/);
23
- const out = [];
24
- let buf = "";
25
- let inDouble = false;
26
- for (const pl of physical) {
27
- if (!inDouble) {
28
- const opens = countUnescapedQuotes(pl);
29
- if (opens % 2 === 1 && isValueStartDoubleQuoted(pl)) {
30
- buf = pl;
31
- inDouble = true;
32
- } else {
33
- out.push(pl);
34
- }
35
- } else {
36
- buf += "\n" + pl;
37
- const opens = countUnescapedQuotes(buf.split("=").slice(1).join("="));
38
- if (opens % 2 === 0) {
39
- inDouble = false;
40
- out.push(buf);
41
- buf = "";
42
- }
43
- }
44
- }
45
- if (inDouble) throw new Error("ParseError: unterminated double-quoted value");
46
- return out;
47
- }
48
- function isValueStartDoubleQuoted(line) {
49
- const eq = line.indexOf("=");
50
- if (eq === -1) return false;
51
- const rest = line.slice(eq + 1).trimStart();
52
- return rest.startsWith('"') && !rest.endsWith('"');
53
- }
54
- function countUnescapedQuotes(s) {
55
- let n = 0;
56
- for (let i = 0; i < s.length; i++) {
57
- if (s[i] === '"' && s[i - 1] !== "\\") n++;
58
- }
59
- return n;
60
- }
61
- function parseValue(rest) {
62
- if (!rest) return "";
63
- if (rest.startsWith("'")) {
64
- const end = rest.indexOf("'", 1);
65
- if (end === -1) throw new Error("ParseError: unterminated single-quoted value");
66
- return rest.slice(1, end);
67
- }
68
- if (rest.startsWith('"')) {
69
- let i = 1;
70
- let val = "";
71
- while (i < rest.length) {
72
- const c = rest[i];
73
- if (c === "\\" && i + 1 < rest.length) {
74
- const n = rest[i + 1];
75
- if (n === "n") val += "\n";
76
- else if (n === "r") val += "\r";
77
- else if (n === "t") val += " ";
78
- else val += n;
79
- i += 2;
80
- continue;
81
- }
82
- if (c === '"') break;
83
- val += c;
84
- i++;
85
- }
86
- if (rest[i] !== '"') throw new Error("ParseError: unterminated double-quoted value");
87
- return val;
88
- }
89
- if (rest.startsWith("`")) throw new Error("ParseError: backtick values not supported");
90
- const hash = findCommentStart(rest);
91
- const v = (hash === -1 ? rest : rest.slice(0, hash)).trim();
92
- return v;
93
- }
94
- function findCommentStart(s) {
95
- for (let i = 0; i < s.length; i++) {
96
- if (s[i] === "#" && (i === 0 || /\s/.test(s[i - 1]))) return i;
97
- }
98
- return -1;
99
- }
100
-
101
- export { parseEnvText };
@@ -1,15 +0,0 @@
1
- import { parse } from 'smol-toml';
2
-
3
- // src/formats/toml.ts
4
- function parseTomlText(text, from = "toml") {
5
- const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
6
- if (!stripped.trim()) return {};
7
- try {
8
- return parse(stripped);
9
- } catch (e) {
10
- const err = e;
11
- throw new Error(`ParseError (${from}): ${err.message}`);
12
- }
13
- }
14
-
15
- export { parseTomlText };
@@ -1,86 +0,0 @@
1
- import { ConfigError } from './chunk-EE6LXNJV.js';
2
-
3
- // src/vault/shared.ts
4
- function getFetch(fetchFn) {
5
- if (fetchFn) return fetchFn;
6
- const g = globalThis;
7
- if (g.fetch) return g.fetch.bind(globalThis);
8
- throw new ConfigError(
9
- [{ path: "<provider>", from: "vault", message: "E_NO_FETCH: global fetch unavailable" }],
10
- "E_NO_FETCH"
11
- );
12
- }
13
- function sameHost(a, b) {
14
- return new URL(a).host === new URL(b).host;
15
- }
16
- var SENSITIVE_HEADER_RE = /authorization|token|secret|api[-_]?key|cookie|auth/i;
17
- function stripSensitiveForCrossHost(headers) {
18
- const next = new Headers();
19
- headers.forEach((value, key) => {
20
- if (!SENSITIVE_HEADER_RE.test(key)) next.set(key, value);
21
- });
22
- return next;
23
- }
24
- async function fetchWithRedirectGuard(url, init, fetchFn, maxRedirects = 2) {
25
- let current = url;
26
- let headers = new Headers(init.headers);
27
- for (let i = 0; i <= maxRedirects; i++) {
28
- const res = await fetchFn(current, { ...init, headers, redirect: "manual" });
29
- const status = res.status;
30
- if (![301, 302, 303, 307, 308].includes(status)) return res;
31
- const loc = res.headers.get("location");
32
- if (!loc) return res;
33
- let next;
34
- try {
35
- next = new URL(loc, current).toString();
36
- } catch {
37
- throw new ConfigError(
38
- [{ path: current, from: "vault", message: "E_REDIRECT: invalid Location header" }],
39
- "E_REDIRECT"
40
- );
41
- }
42
- if (i === maxRedirects) {
43
- throw new ConfigError(
44
- [{ path: next, from: "vault", message: "E_REDIRECT: too many redirects" }],
45
- "E_REDIRECT"
46
- );
47
- }
48
- if (!sameHost(current, next)) headers = stripSensitiveForCrossHost(headers);
49
- current = next;
50
- }
51
- throw new ConfigError([{ path: url, from: "vault", message: "E_REDIRECT" }], "E_REDIRECT");
52
- }
53
- function normalizeSecretMap(raw, providerName, opts) {
54
- const trim = opts?.trimNewline !== false;
55
- const clean = (v) => {
56
- if (v === null || v === void 0) return void 0;
57
- let s = typeof v === "string" ? v : String(v);
58
- if (trim) s = s.replace(/\r?\n$/, "");
59
- return s;
60
- };
61
- const out = {};
62
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
63
- throw new ConfigError(
64
- [{ path: "<root>", from: providerName, message: "E_SHAPE: provider returned non-object" }],
65
- "E_SHAPE"
66
- );
67
- }
68
- for (const [k, v] of Object.entries(raw)) {
69
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
70
- out[k] = v;
71
- continue;
72
- }
73
- const c = clean(v);
74
- if (c !== void 0) out[k] = c;
75
- }
76
- return out;
77
- }
78
- function statusToCode(status) {
79
- if (status === 403 || status === 401) return "E_DENIED";
80
- if (status === 404) return "E_NOT_FOUND";
81
- if (status === 429) return "E_THROTTLED";
82
- if (status >= 500) return "E_UPSTREAM";
83
- return "E_PROVIDER";
84
- }
85
-
86
- export { fetchWithRedirectGuard, getFetch, normalizeSecretMap, statusToCode };
@@ -1,38 +0,0 @@
1
- import { parseAllDocuments } from 'yaml';
2
-
3
- // src/formats/yaml.ts
4
- function parseYamlText(text, from = "yaml") {
5
- const stripped = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
6
- if (!stripped.trim()) return {};
7
- const docs = parseAllDocuments(stripped, {
8
- version: "1.2",
9
- uniqueKeys: true
10
- }).filter((d) => {
11
- if (d.errors.length > 0) return true;
12
- try {
13
- const v = d.toJS();
14
- return v !== null && v !== void 0;
15
- } catch {
16
- return true;
17
- }
18
- });
19
- if (docs.length === 0) return {};
20
- if (docs.length > 1) {
21
- throw new Error(`ParseError (${from}): multi-doc YAML not supported (got ${docs.length} documents)`);
22
- }
23
- const doc = docs[0];
24
- if (doc.errors.length > 0) {
25
- const first = doc.errors[0];
26
- const line = first.linePos?.[0]?.line ?? "?";
27
- throw new Error(`ParseError (${from}:${line}): ${first.message}`);
28
- }
29
- let value;
30
- try {
31
- value = doc.toJS();
32
- } catch (e) {
33
- throw new Error(`ParseError (${from}): ${e.message}`);
34
- }
35
- return value;
36
- }
37
-
38
- export { parseYamlText };