@epsilon-asi/foundation 0.0.10 → 0.0.11
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/build/files/index.d.ts +9 -0
- package/build/files/index.js +24 -0
- package/build/files/init.d.ts +33 -0
- package/build/files/init.js +62 -0
- package/build/files/load.d.ts +9 -0
- package/build/files/load.js +54 -0
- package/build/files/parse.d.ts +5 -0
- package/build/files/parse.js +27 -0
- package/build/files/save.d.ts +5 -0
- package/build/files/save.js +30 -0
- package/build/files/serialize.d.ts +6 -0
- package/build/files/serialize.js +24 -0
- package/build/files/types.d.ts +108 -0
- package/build/files/types.js +18 -0
- package/build/files/util.d.ts +28 -0
- package/build/files/util.js +418 -0
- package/package.json +17 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createSchemaFile, interpolateEnv, interpolateEnvHook } from "./init";
|
|
2
|
+
import { loadFile, loadFileSync, safeLoadFile, safeLoadFileSync } from "./load";
|
|
3
|
+
import { parseStringSync } from "./parse";
|
|
4
|
+
import { parseString } from "./parse";
|
|
5
|
+
import { serialize, serializeAsync } from "./serialize";
|
|
6
|
+
import { saveFile, saveFileSync } from "./save";
|
|
7
|
+
import { SchemaFileError } from "./types";
|
|
8
|
+
export type { ErrorFormatter, FileFormat, LoadOptions, ParseOptions, ParseParams, PreprocessContext, SafeResult, SaveOptions, SchemaFileErrorKind, SerializeOptions, SerializeStrategy, } from "./types";
|
|
9
|
+
export { createSchemaFile, interpolateEnv, interpolateEnvHook, loadFile, loadFileSync, safeLoadFile, safeLoadFileSync, serialize, serializeAsync, parseString, parseStringSync, saveFileSync, saveFile, SchemaFileError };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaFileError = exports.saveFile = exports.saveFileSync = exports.parseStringSync = exports.parseString = exports.serializeAsync = exports.serialize = exports.safeLoadFileSync = exports.safeLoadFile = exports.loadFileSync = exports.loadFile = exports.interpolateEnvHook = exports.interpolateEnv = exports.createSchemaFile = void 0;
|
|
4
|
+
const init_1 = require("./init");
|
|
5
|
+
Object.defineProperty(exports, "createSchemaFile", { enumerable: true, get: function () { return init_1.createSchemaFile; } });
|
|
6
|
+
Object.defineProperty(exports, "interpolateEnv", { enumerable: true, get: function () { return init_1.interpolateEnv; } });
|
|
7
|
+
Object.defineProperty(exports, "interpolateEnvHook", { enumerable: true, get: function () { return init_1.interpolateEnvHook; } });
|
|
8
|
+
const load_1 = require("./load");
|
|
9
|
+
Object.defineProperty(exports, "loadFile", { enumerable: true, get: function () { return load_1.loadFile; } });
|
|
10
|
+
Object.defineProperty(exports, "loadFileSync", { enumerable: true, get: function () { return load_1.loadFileSync; } });
|
|
11
|
+
Object.defineProperty(exports, "safeLoadFile", { enumerable: true, get: function () { return load_1.safeLoadFile; } });
|
|
12
|
+
Object.defineProperty(exports, "safeLoadFileSync", { enumerable: true, get: function () { return load_1.safeLoadFileSync; } });
|
|
13
|
+
const parse_1 = require("./parse");
|
|
14
|
+
Object.defineProperty(exports, "parseStringSync", { enumerable: true, get: function () { return parse_1.parseStringSync; } });
|
|
15
|
+
const parse_2 = require("./parse");
|
|
16
|
+
Object.defineProperty(exports, "parseString", { enumerable: true, get: function () { return parse_2.parseString; } });
|
|
17
|
+
const serialize_1 = require("./serialize");
|
|
18
|
+
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serialize_1.serialize; } });
|
|
19
|
+
Object.defineProperty(exports, "serializeAsync", { enumerable: true, get: function () { return serialize_1.serializeAsync; } });
|
|
20
|
+
const save_1 = require("./save");
|
|
21
|
+
Object.defineProperty(exports, "saveFile", { enumerable: true, get: function () { return save_1.saveFile; } });
|
|
22
|
+
Object.defineProperty(exports, "saveFileSync", { enumerable: true, get: function () { return save_1.saveFileSync; } });
|
|
23
|
+
const types_1 = require("./types");
|
|
24
|
+
Object.defineProperty(exports, "SchemaFileError", { enumerable: true, get: function () { return types_1.SchemaFileError; } });
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { LoadOptions, ParseOptions, SaveOptions, SerializeOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Bind a schema and default options once, reuse everywhere.
|
|
5
|
+
* Per-call options are shallow-merged over the defaults.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createSchemaFile<S extends z.ZodType>(schema: S, defaults?: {
|
|
8
|
+
load?: LoadOptions;
|
|
9
|
+
save?: SaveOptions;
|
|
10
|
+
}): {
|
|
11
|
+
schema: S;
|
|
12
|
+
load: (filePath: string, o?: LoadOptions) => Promise<z.core.output<S>>;
|
|
13
|
+
loadSync: (filePath: string, o?: LoadOptions) => z.core.output<S>;
|
|
14
|
+
safeLoad: (filePath: string, o?: LoadOptions) => Promise<import("./types").SafeResult<z.core.output<S>>>;
|
|
15
|
+
safeLoadSync: (filePath: string, o?: LoadOptions) => import("./types").SafeResult<z.core.output<S>>;
|
|
16
|
+
parse: (text: string, o?: ParseOptions) => Promise<z.core.output<S>>;
|
|
17
|
+
save: (filePath: string, value: z.output<S>, o?: SaveOptions) => Promise<string>;
|
|
18
|
+
saveSync: (filePath: string, value: z.output<S>, o?: SaveOptions) => string;
|
|
19
|
+
serialize: (value: z.output<S>, o: SerializeOptions) => Promise<string>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Recursively replace ${VAR} and ${VAR:-fallback} in string values.
|
|
23
|
+
* For a `preprocess` hook use interpolateEnvHook(): a hook's second argument is the
|
|
24
|
+
* PreprocessContext, which this function would read as `env`. Note results are strings,
|
|
25
|
+
* so use z.coerce.* in the schema for numeric/boolean fields filled from env vars.
|
|
26
|
+
*/
|
|
27
|
+
export declare function interpolateEnv(value: unknown, env?: Record<string, string | undefined>, options?: {
|
|
28
|
+
strict?: boolean;
|
|
29
|
+
}): unknown;
|
|
30
|
+
/** A `preprocess` hook that runs interpolateEnv over the parsed data: { preprocess: interpolateEnvHook() }. */
|
|
31
|
+
export declare function interpolateEnvHook(env?: Record<string, string | undefined>, options?: {
|
|
32
|
+
strict?: boolean;
|
|
33
|
+
}): (raw: unknown) => unknown;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSchemaFile = createSchemaFile;
|
|
4
|
+
exports.interpolateEnv = interpolateEnv;
|
|
5
|
+
exports.interpolateEnvHook = interpolateEnvHook;
|
|
6
|
+
const util_1 = require("./util");
|
|
7
|
+
const serialize_1 = require("./serialize");
|
|
8
|
+
const load_1 = require("./load");
|
|
9
|
+
const save_1 = require("./save");
|
|
10
|
+
const parse_1 = require("./parse");
|
|
11
|
+
/**
|
|
12
|
+
* Bind a schema and default options once, reuse everywhere.
|
|
13
|
+
* Per-call options are shallow-merged over the defaults.
|
|
14
|
+
*/
|
|
15
|
+
function createSchemaFile(schema, defaults = {}) {
|
|
16
|
+
const l = (o) => (Object.assign(Object.assign({}, defaults.load), o));
|
|
17
|
+
const s = (o) => (Object.assign(Object.assign({}, defaults.save), o));
|
|
18
|
+
return {
|
|
19
|
+
schema,
|
|
20
|
+
load: (filePath, o) => (0, load_1.loadFile)(filePath, schema, l(o)),
|
|
21
|
+
loadSync: (filePath, o) => (0, load_1.loadFileSync)(filePath, schema, l(o)),
|
|
22
|
+
safeLoad: (filePath, o) => (0, load_1.safeLoadFile)(filePath, schema, l(o)),
|
|
23
|
+
safeLoadSync: (filePath, o) => (0, load_1.safeLoadFileSync)(filePath, schema, l(o)),
|
|
24
|
+
parse: (text, o) => (0, parse_1.parseString)(schema, text, l(o)),
|
|
25
|
+
save: (filePath, value, o) => (0, save_1.saveFile)(filePath, schema, value, s(o)),
|
|
26
|
+
saveSync: (filePath, value, o) => (0, save_1.saveFileSync)(filePath, schema, value, s(o)),
|
|
27
|
+
serialize: (value, o) => (0, serialize_1.serializeAsync)(schema, value, Object.assign(Object.assign({}, defaults.save), o)),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Recursively replace ${VAR} and ${VAR:-fallback} in string values.
|
|
32
|
+
* For a `preprocess` hook use interpolateEnvHook(): a hook's second argument is the
|
|
33
|
+
* PreprocessContext, which this function would read as `env`. Note results are strings,
|
|
34
|
+
* so use z.coerce.* in the schema for numeric/boolean fields filled from env vars.
|
|
35
|
+
*/
|
|
36
|
+
function interpolateEnv(value, env = process.env, options = {}) {
|
|
37
|
+
const pattern = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
38
|
+
const walk = (v) => {
|
|
39
|
+
if (typeof v === "string") {
|
|
40
|
+
return v.replace(pattern, (_m, name, fallback) => {
|
|
41
|
+
const found = env[name];
|
|
42
|
+
if (found !== undefined && found !== "")
|
|
43
|
+
return found;
|
|
44
|
+
if (fallback !== undefined)
|
|
45
|
+
return fallback;
|
|
46
|
+
if (options.strict)
|
|
47
|
+
throw new Error(`Environment variable "${name}" is not set`);
|
|
48
|
+
return "";
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(v))
|
|
52
|
+
return v.map(walk);
|
|
53
|
+
if ((0, util_1.isPlainObject)(v))
|
|
54
|
+
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));
|
|
55
|
+
return v;
|
|
56
|
+
};
|
|
57
|
+
return walk(value);
|
|
58
|
+
}
|
|
59
|
+
/** A `preprocess` hook that runs interpolateEnv over the parsed data: { preprocess: interpolateEnvHook() }. */
|
|
60
|
+
function interpolateEnvHook(env = process.env, options = {}) {
|
|
61
|
+
return (raw) => interpolateEnv(raw, env, options);
|
|
62
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { LoadOptions, SafeResult } from "./types";
|
|
3
|
+
/** Read a JSON/YAML file and return a validated, typed value. */
|
|
4
|
+
export declare function loadFile<S extends z.ZodType>(filePath: string, schema: S, options?: LoadOptions): Promise<z.output<S>>;
|
|
5
|
+
/** Synchronous variant. Fails if the schema contains async refinements/transforms. */
|
|
6
|
+
export declare function loadFileSync<S extends z.ZodType>(filePath: string, schema: S, options?: LoadOptions): z.output<S>;
|
|
7
|
+
/** Like loadFile, but returns a result object instead of throwing SchemaFileError. */
|
|
8
|
+
export declare function safeLoadFile<S extends z.ZodType>(filePath: string, schema: S, options?: LoadOptions): Promise<SafeResult<z.output<S>>>;
|
|
9
|
+
export declare function safeLoadFileSync<S extends z.ZodType>(filePath: string, schema: S, options?: LoadOptions): SafeResult<z.output<S>>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadFile = loadFile;
|
|
13
|
+
exports.loadFileSync = loadFileSync;
|
|
14
|
+
exports.safeLoadFile = safeLoadFile;
|
|
15
|
+
exports.safeLoadFileSync = safeLoadFileSync;
|
|
16
|
+
const types_1 = require("./types");
|
|
17
|
+
const util_1 = require("./util");
|
|
18
|
+
/** Read a JSON/YAML file and return a validated, typed value. */
|
|
19
|
+
function loadFile(filePath_1, schema_1) {
|
|
20
|
+
return __awaiter(this, arguments, void 0, function* (filePath, schema, options = {}) {
|
|
21
|
+
const opts = Object.assign(Object.assign({}, options), { filePath });
|
|
22
|
+
const { raw, format } = (0, util_1.toRaw)(yield (0, util_1.readTextAsync)(filePath, opts), opts);
|
|
23
|
+
return (0, util_1.validateAsync)(schema, yield (0, util_1.runPreprocess)(raw, format, opts), opts);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Synchronous variant. Fails if the schema contains async refinements/transforms. */
|
|
27
|
+
function loadFileSync(filePath, schema, options = {}) {
|
|
28
|
+
const opts = Object.assign(Object.assign({}, options), { filePath });
|
|
29
|
+
const { raw, format } = (0, util_1.toRaw)((0, util_1.readTextSync)(filePath, opts), opts);
|
|
30
|
+
return (0, util_1.validateSync)(schema, (0, util_1.runPreprocessSync)(raw, format, opts), opts);
|
|
31
|
+
}
|
|
32
|
+
/** Like loadFile, but returns a result object instead of throwing SchemaFileError. */
|
|
33
|
+
function safeLoadFile(filePath_1, schema_1) {
|
|
34
|
+
return __awaiter(this, arguments, void 0, function* (filePath, schema, options = {}) {
|
|
35
|
+
try {
|
|
36
|
+
return { success: true, data: yield loadFile(filePath, schema, options) };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof types_1.SchemaFileError)
|
|
40
|
+
return { success: false, error };
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function safeLoadFileSync(filePath, schema, options = {}) {
|
|
46
|
+
try {
|
|
47
|
+
return { success: true, data: loadFileSync(filePath, schema, options) };
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof types_1.SchemaFileError)
|
|
51
|
+
return { success: false, error };
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { ParseOptions } from "./types";
|
|
3
|
+
/** Parse and validate a string already in memory. */
|
|
4
|
+
export declare function parseString<S extends z.ZodType>(schema: S, text: string, options?: ParseOptions): Promise<z.output<S>>;
|
|
5
|
+
export declare function parseStringSync<S extends z.ZodType>(schema: S, text: string, options?: ParseOptions): z.output<S>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.parseString = parseString;
|
|
13
|
+
exports.parseStringSync = parseStringSync;
|
|
14
|
+
const util_1 = require("./util");
|
|
15
|
+
/** Parse and validate a string already in memory. */
|
|
16
|
+
function parseString(schema_1, text_1) {
|
|
17
|
+
return __awaiter(this, arguments, void 0, function* (schema, text, options = {}) {
|
|
18
|
+
const format = (0, util_1.resolveFormat)(options.format, options.filePath, text);
|
|
19
|
+
const raw = yield (0, util_1.runPreprocess)((0, util_1.decodeText)(text, format, options), format, options);
|
|
20
|
+
return (0, util_1.validateAsync)(schema, raw, options);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function parseStringSync(schema, text, options = {}) {
|
|
24
|
+
const format = (0, util_1.resolveFormat)(options.format, options.filePath, text);
|
|
25
|
+
const raw = (0, util_1.runPreprocessSync)((0, util_1.decodeText)(text, format, options), format, options);
|
|
26
|
+
return (0, util_1.validateSync)(schema, raw, options);
|
|
27
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { SaveOptions } from "./types";
|
|
3
|
+
export declare function saveFileSync<S extends z.ZodType>(filePath: string, schema: S, value: z.output<S>, options?: SaveOptions): string;
|
|
4
|
+
/** Serialize and write to disk. Returns the text that was written. */
|
|
5
|
+
export declare function saveFile<S extends z.ZodType>(filePath: string, schema: S, value: z.output<S>, options?: SaveOptions): Promise<string>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.saveFileSync = saveFileSync;
|
|
13
|
+
exports.saveFile = saveFile;
|
|
14
|
+
const serialize_1 = require("./serialize");
|
|
15
|
+
const util_1 = require("./util");
|
|
16
|
+
function saveFileSync(filePath, schema, value, options = {}) {
|
|
17
|
+
const format = (0, util_1.resolveFormat)(options.format, filePath);
|
|
18
|
+
const text = (0, serialize_1.serialize)(schema, value, Object.assign(Object.assign({}, options), { format, filePath }));
|
|
19
|
+
(0, util_1.writeTextSync)(filePath, text, options);
|
|
20
|
+
return text;
|
|
21
|
+
}
|
|
22
|
+
/** Serialize and write to disk. Returns the text that was written. */
|
|
23
|
+
function saveFile(filePath_1, schema_1, value_1) {
|
|
24
|
+
return __awaiter(this, arguments, void 0, function* (filePath, schema, value, options = {}) {
|
|
25
|
+
const format = (0, util_1.resolveFormat)(options.format, filePath);
|
|
26
|
+
const text = yield (0, serialize_1.serializeAsync)(schema, value, Object.assign(Object.assign({}, options), { format, filePath }));
|
|
27
|
+
yield (0, util_1.writeTextAsync)(filePath, text, options);
|
|
28
|
+
return text;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { SerializeOptions } from "./types";
|
|
3
|
+
/** Validate/encode a value with the schema and render it as JSON or YAML text. */
|
|
4
|
+
export declare function serialize<S extends z.ZodType>(schema: S, value: z.output<S>, options: SerializeOptions): string;
|
|
5
|
+
/** Async variant; required when the schema has async refinements or codecs. */
|
|
6
|
+
export declare function serializeAsync<S extends z.ZodType>(schema: S, value: z.output<S>, options: SerializeOptions): Promise<string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.serialize = serialize;
|
|
13
|
+
exports.serializeAsync = serializeAsync;
|
|
14
|
+
const util_1 = require("./util");
|
|
15
|
+
/** Validate/encode a value with the schema and render it as JSON or YAML text. */
|
|
16
|
+
function serialize(schema, value, options) {
|
|
17
|
+
return (0, util_1.render)((0, util_1.toWireSync)(schema, value, options), options);
|
|
18
|
+
}
|
|
19
|
+
/** Async variant; required when the schema has async refinements or codecs. */
|
|
20
|
+
function serializeAsync(schema, value, options) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
return (0, util_1.render)(yield (0, util_1.toWireAsync)(schema, value, options), options);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import * as YAML from "yaml";
|
|
3
|
+
export type FileFormat = "json" | "yaml";
|
|
4
|
+
export type ParseParams = Parameters<z.ZodType["safeParse"]>[1];
|
|
5
|
+
export type ErrorFormatter = (error: z.core.$ZodError) => string;
|
|
6
|
+
export type SchemaFileErrorKind = "format" | "read" | "parse" | "preprocess" | "validate" | "encode" | "serialize" | "write";
|
|
7
|
+
export declare class SchemaFileError extends Error {
|
|
8
|
+
readonly kind: SchemaFileErrorKind;
|
|
9
|
+
readonly filePath?: string;
|
|
10
|
+
/** Present for "validate" / "encode" errors that came from Zod. */
|
|
11
|
+
readonly issues?: z.core.$ZodIssue[];
|
|
12
|
+
constructor(kind: SchemaFileErrorKind, message: string, details?: {
|
|
13
|
+
filePath?: string;
|
|
14
|
+
issues?: z.core.$ZodIssue[];
|
|
15
|
+
cause?: unknown;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export type SafeResult<T> = {
|
|
19
|
+
success: true;
|
|
20
|
+
data: T;
|
|
21
|
+
} | {
|
|
22
|
+
success: false;
|
|
23
|
+
error: SchemaFileError;
|
|
24
|
+
};
|
|
25
|
+
export interface PreprocessContext {
|
|
26
|
+
format: FileFormat;
|
|
27
|
+
filePath?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ParseOptions {
|
|
30
|
+
/** Force a format. "auto" (default) uses the file extension, then sniffs content. */
|
|
31
|
+
format?: FileFormat | "auto";
|
|
32
|
+
/** Only used for error messages and extension-based format detection. */
|
|
33
|
+
filePath?: string;
|
|
34
|
+
/** Strip a leading UTF-8 BOM. Default: true. */
|
|
35
|
+
stripBom?: boolean;
|
|
36
|
+
/** Value handed to the schema when the content is empty/whitespace. Default: undefined. */
|
|
37
|
+
emptyValue?: unknown;
|
|
38
|
+
/** Hook to transform raw parsed data before validation (env interpolation, migrations, ...). */
|
|
39
|
+
preprocess?: (raw: unknown, ctx: PreprocessContext) => unknown | Promise<unknown>;
|
|
40
|
+
/** Extra params forwarded to schema.safeParse (e.g. custom error map). */
|
|
41
|
+
parseParams?: ParseParams;
|
|
42
|
+
/** Customize the human-readable validation message. Default: z.prettifyError. */
|
|
43
|
+
formatError?: ErrorFormatter;
|
|
44
|
+
json?: {
|
|
45
|
+
reviver?: (this: unknown, key: string, value: unknown) => unknown;
|
|
46
|
+
};
|
|
47
|
+
/** Passed straight to YAML.parse (uniqueKeys, maxAliasCount, merge, version, strict, ...). */
|
|
48
|
+
yaml?: YAML.ParseOptions & YAML.DocumentOptions & YAML.SchemaOptions & YAML.ToJSOptions;
|
|
49
|
+
}
|
|
50
|
+
export interface LoadOptions extends ParseOptions {
|
|
51
|
+
encoding?: BufferEncoding;
|
|
52
|
+
/** If the file does not exist, validate `missingValue` instead of throwing. Default: false. */
|
|
53
|
+
allowMissing?: boolean;
|
|
54
|
+
/** Input used when the file is missing and allowMissing is true. Default: {} (so schema defaults apply). */
|
|
55
|
+
missingValue?: unknown;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* How the in-memory (output-typed) value is turned back into plain data:
|
|
59
|
+
* - "encode": z.encode(schema, value). Runs codecs in reverse (e.g. Date -> ISO string)
|
|
60
|
+
* and validates. Throws on one-way .transform(). Default.
|
|
61
|
+
* - "parse": schema.parse(value). Validates and writes the *output* shape. Use for schemas
|
|
62
|
+
* with one-way transforms whose output is still valid input.
|
|
63
|
+
* - "none": write the value as-is with no validation.
|
|
64
|
+
*/
|
|
65
|
+
export type SerializeStrategy = "encode" | "parse" | "none";
|
|
66
|
+
export interface SerializeOptions {
|
|
67
|
+
format: FileFormat;
|
|
68
|
+
strategy?: SerializeStrategy;
|
|
69
|
+
/** Spaces of indentation. Default: 2. */
|
|
70
|
+
indent?: number;
|
|
71
|
+
/** Deterministic output: sort object keys recursively (true = default string order). */
|
|
72
|
+
sortKeys?: boolean | ((a: string, b: string) => number);
|
|
73
|
+
/** Ensure output ends with a newline. Default: true. */
|
|
74
|
+
trailingNewline?: boolean;
|
|
75
|
+
/** Customize the human-readable validation message. Default: z.prettifyError. */
|
|
76
|
+
formatError?: ErrorFormatter;
|
|
77
|
+
/** Only used for error messages. */
|
|
78
|
+
filePath?: string;
|
|
79
|
+
json?: {
|
|
80
|
+
replacer?: (this: unknown, key: string, value: unknown) => unknown;
|
|
81
|
+
};
|
|
82
|
+
yaml?: {
|
|
83
|
+
/** Options for new YAML.Document(...) (version, schema, aliasDuplicateObjects, keepUndefined, ...). */
|
|
84
|
+
document?: YAML.DocumentOptions & YAML.SchemaOptions & YAML.CreateNodeOptions;
|
|
85
|
+
/**
|
|
86
|
+
* Options for doc.toString(...) (lineWidth, defaultStringType, flowCollectionPadding, ...).
|
|
87
|
+
* Not named `toString`: every object literal inherits that, so TypeScript would reject any
|
|
88
|
+
* `yaml` options that leave it out.
|
|
89
|
+
*/
|
|
90
|
+
stringify?: YAML.ToStringOptions;
|
|
91
|
+
/** Header comment written at the top of the file (multi-line allowed, no leading "#"). */
|
|
92
|
+
comment?: string;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export interface SaveOptions extends Omit<SerializeOptions, "format" | "filePath"> {
|
|
96
|
+
/** "auto" (default) picks by extension: .json / .yaml / .yml. */
|
|
97
|
+
format?: FileFormat | "auto";
|
|
98
|
+
encoding?: BufferEncoding;
|
|
99
|
+
/** Create parent directories. Default: true. */
|
|
100
|
+
createDirs?: boolean;
|
|
101
|
+
/** Write to a temp file then rename, so readers never see a half-written file. Default: true. */
|
|
102
|
+
atomic?: boolean;
|
|
103
|
+
/** Allow replacing an existing file. Default: true. */
|
|
104
|
+
overwrite?: boolean;
|
|
105
|
+
/** File permission bits for the written file, e.g. 0o600 for secrets. */
|
|
106
|
+
mode?: number;
|
|
107
|
+
}
|
|
108
|
+
export declare const EXTENSIONS: Record<string, FileFormat>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EXTENSIONS = exports.SchemaFileError = void 0;
|
|
4
|
+
class SchemaFileError extends Error {
|
|
5
|
+
constructor(kind, message, details = {}) {
|
|
6
|
+
super(message, { cause: details.cause });
|
|
7
|
+
this.name = "SchemaFileError";
|
|
8
|
+
this.kind = kind;
|
|
9
|
+
this.filePath = details.filePath;
|
|
10
|
+
this.issues = details.issues;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.SchemaFileError = SchemaFileError;
|
|
14
|
+
exports.EXTENSIONS = {
|
|
15
|
+
".json": "json",
|
|
16
|
+
".yaml": "yaml",
|
|
17
|
+
".yml": "yaml",
|
|
18
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { FileFormat, LoadOptions, ParseOptions, SaveOptions, SerializeOptions } from "./types";
|
|
3
|
+
declare const MISSING: unique symbol;
|
|
4
|
+
export declare function label(filePath?: string): string;
|
|
5
|
+
export declare function isPlainObject(v: unknown): v is Record<string, unknown>;
|
|
6
|
+
export declare function decodeText(text: string, format: FileFormat, opts: ParseOptions): unknown;
|
|
7
|
+
export declare function formatFromExtension(filePath: string): FileFormat | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a format from an explicit option, the extension, or (last) the content.
|
|
10
|
+
* Content sniffing falls back to YAML because YAML 1.2 is a superset of JSON.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveFormat(format: FileFormat | "auto" | undefined, filePath?: string, content?: string): FileFormat;
|
|
13
|
+
export declare function toRaw(text: string | typeof MISSING, opts: LoadOptions): {
|
|
14
|
+
raw: unknown;
|
|
15
|
+
format: FileFormat;
|
|
16
|
+
};
|
|
17
|
+
export declare function readTextAsync(filePath: string, opts: LoadOptions): Promise<string | typeof MISSING>;
|
|
18
|
+
export declare function readTextSync(filePath: string, opts: LoadOptions): string | typeof MISSING;
|
|
19
|
+
export declare function runPreprocess(raw: unknown, format: FileFormat, opts: ParseOptions): Promise<unknown>;
|
|
20
|
+
export declare function runPreprocessSync(raw: unknown, format: FileFormat, opts: ParseOptions): unknown;
|
|
21
|
+
export declare function validateAsync<S extends z.ZodType>(schema: S, raw: unknown, opts: ParseOptions): Promise<z.output<S>>;
|
|
22
|
+
export declare function validateSync<S extends z.ZodType>(schema: S, raw: unknown, opts: ParseOptions): z.output<S>;
|
|
23
|
+
export declare function toWireSync<S extends z.ZodType>(schema: S, value: z.output<S>, opts: SerializeOptions): unknown;
|
|
24
|
+
export declare function toWireAsync<S extends z.ZodType>(schema: S, value: z.output<S>, opts: SerializeOptions): Promise<unknown>;
|
|
25
|
+
export declare function render(data: unknown, opts: SerializeOptions): string;
|
|
26
|
+
export declare function writeTextAsync(filePath: string, text: string, opts: SaveOptions): Promise<void>;
|
|
27
|
+
export declare function writeTextSync(filePath: string, text: string, opts: SaveOptions): void;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.label = label;
|
|
49
|
+
exports.isPlainObject = isPlainObject;
|
|
50
|
+
exports.decodeText = decodeText;
|
|
51
|
+
exports.formatFromExtension = formatFromExtension;
|
|
52
|
+
exports.resolveFormat = resolveFormat;
|
|
53
|
+
exports.toRaw = toRaw;
|
|
54
|
+
exports.readTextAsync = readTextAsync;
|
|
55
|
+
exports.readTextSync = readTextSync;
|
|
56
|
+
exports.runPreprocess = runPreprocess;
|
|
57
|
+
exports.runPreprocessSync = runPreprocessSync;
|
|
58
|
+
exports.validateAsync = validateAsync;
|
|
59
|
+
exports.validateSync = validateSync;
|
|
60
|
+
exports.toWireSync = toWireSync;
|
|
61
|
+
exports.toWireAsync = toWireAsync;
|
|
62
|
+
exports.render = render;
|
|
63
|
+
exports.writeTextAsync = writeTextAsync;
|
|
64
|
+
exports.writeTextSync = writeTextSync;
|
|
65
|
+
const YAML = __importStar(require("yaml"));
|
|
66
|
+
const z = __importStar(require("zod"));
|
|
67
|
+
const promises_1 = require("node:fs/promises");
|
|
68
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
69
|
+
const node_fs_1 = require("node:fs");
|
|
70
|
+
const types_1 = require("./types");
|
|
71
|
+
const MISSING = Symbol("missing");
|
|
72
|
+
function label(filePath) {
|
|
73
|
+
return filePath !== null && filePath !== void 0 ? filePath : "input";
|
|
74
|
+
}
|
|
75
|
+
function errMsg(e) {
|
|
76
|
+
return e instanceof Error ? e.message : String(e);
|
|
77
|
+
}
|
|
78
|
+
function isPlainObject(v) {
|
|
79
|
+
if (typeof v !== "object" || v === null)
|
|
80
|
+
return false;
|
|
81
|
+
const proto = Object.getPrototypeOf(v);
|
|
82
|
+
return proto === Object.prototype || proto === null;
|
|
83
|
+
}
|
|
84
|
+
function isNotFound(e) {
|
|
85
|
+
return (e === null || e === void 0 ? void 0 : e.code) === "ENOENT";
|
|
86
|
+
}
|
|
87
|
+
function decodeText(text, format, opts) {
|
|
88
|
+
var _a;
|
|
89
|
+
const src = opts.stripBom !== false && text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
90
|
+
if (src.trim() === "")
|
|
91
|
+
return opts.emptyValue;
|
|
92
|
+
try {
|
|
93
|
+
return format === "json" ? JSON.parse(src, (_a = opts.json) === null || _a === void 0 ? void 0 : _a.reviver) : YAML.parse(src, opts.yaml);
|
|
94
|
+
}
|
|
95
|
+
catch (cause) {
|
|
96
|
+
throw new types_1.SchemaFileError("parse", `Failed to parse ${label(opts.filePath)} as ${format.toUpperCase()}: ${errMsg(cause)}`, { filePath: opts.filePath, cause });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function formatFromExtension(filePath) {
|
|
100
|
+
return types_1.EXTENSIONS[node_path_1.default.extname(filePath).toLowerCase()];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve a format from an explicit option, the extension, or (last) the content.
|
|
104
|
+
* Content sniffing falls back to YAML because YAML 1.2 is a superset of JSON.
|
|
105
|
+
*/
|
|
106
|
+
function resolveFormat(format, filePath, content) {
|
|
107
|
+
if (format && format !== "auto")
|
|
108
|
+
return format;
|
|
109
|
+
const byExt = filePath ? formatFromExtension(filePath) : undefined;
|
|
110
|
+
if (byExt)
|
|
111
|
+
return byExt;
|
|
112
|
+
if (content !== undefined)
|
|
113
|
+
return "yaml";
|
|
114
|
+
throw new types_1.SchemaFileError("format", `Cannot determine format for ${label(filePath)}; pass { format: "json" | "yaml" }`, { filePath });
|
|
115
|
+
}
|
|
116
|
+
function toRaw(text, opts) {
|
|
117
|
+
if (text === MISSING) {
|
|
118
|
+
return {
|
|
119
|
+
raw: "missingValue" in opts ? opts.missingValue : {},
|
|
120
|
+
format: resolveFormat(opts.format, opts.filePath, ""),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const format = resolveFormat(opts.format, opts.filePath, text);
|
|
124
|
+
return { raw: decodeText(text, format, opts), format };
|
|
125
|
+
}
|
|
126
|
+
function readTextAsync(filePath, opts) {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
var _a;
|
|
129
|
+
try {
|
|
130
|
+
return yield (0, promises_1.readFile)(filePath, { encoding: (_a = opts.encoding) !== null && _a !== void 0 ? _a : "utf8" });
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
if (opts.allowMissing && isNotFound(cause))
|
|
134
|
+
return MISSING;
|
|
135
|
+
throw new types_1.SchemaFileError("read", `Failed to read ${filePath}: ${errMsg(cause)}`, { filePath, cause });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function readTextSync(filePath, opts) {
|
|
140
|
+
var _a;
|
|
141
|
+
try {
|
|
142
|
+
return (0, node_fs_1.readFileSync)(filePath, { encoding: (_a = opts.encoding) !== null && _a !== void 0 ? _a : "utf8" });
|
|
143
|
+
}
|
|
144
|
+
catch (cause) {
|
|
145
|
+
if (opts.allowMissing && isNotFound(cause))
|
|
146
|
+
return MISSING;
|
|
147
|
+
throw new types_1.SchemaFileError("read", `Failed to read ${filePath}: ${errMsg(cause)}`, { filePath, cause });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function runPreprocess(raw, format, opts) {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
if (!opts.preprocess)
|
|
153
|
+
return raw;
|
|
154
|
+
try {
|
|
155
|
+
return yield opts.preprocess(raw, { format, filePath: opts.filePath });
|
|
156
|
+
}
|
|
157
|
+
catch (cause) {
|
|
158
|
+
throw preprocessError(cause, opts.filePath);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function runPreprocessSync(raw, format, opts) {
|
|
163
|
+
if (!opts.preprocess)
|
|
164
|
+
return raw;
|
|
165
|
+
let result;
|
|
166
|
+
try {
|
|
167
|
+
result = opts.preprocess(raw, { format, filePath: opts.filePath });
|
|
168
|
+
}
|
|
169
|
+
catch (cause) {
|
|
170
|
+
throw preprocessError(cause, opts.filePath);
|
|
171
|
+
}
|
|
172
|
+
if (result instanceof Promise) {
|
|
173
|
+
// Nobody will await it, so keep a rejection from surfacing as an unhandledRejection.
|
|
174
|
+
result.catch(() => {
|
|
175
|
+
});
|
|
176
|
+
throw new types_1.SchemaFileError("preprocess", "preprocess returned a Promise; use the async API instead", {
|
|
177
|
+
filePath: opts.filePath,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
function preprocessError(cause, filePath) {
|
|
183
|
+
return new types_1.SchemaFileError("preprocess", `Preprocess failed for ${label(filePath)}: ${errMsg(cause)}`, {
|
|
184
|
+
filePath,
|
|
185
|
+
cause,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function zodError(kind, error, formatError, filePath) {
|
|
189
|
+
const pretty = (formatError !== null && formatError !== void 0 ? formatError : z.prettifyError)(error);
|
|
190
|
+
const verb = kind === "encode" ? "Encoding" : "Validation";
|
|
191
|
+
return new types_1.SchemaFileError(kind, `${verb} failed for ${label(filePath)}:\n${pretty}`, {
|
|
192
|
+
filePath,
|
|
193
|
+
issues: error.issues,
|
|
194
|
+
cause: error,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function validateAsync(schema, raw, opts) {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
const result = yield schema.safeParseAsync(raw, opts.parseParams);
|
|
200
|
+
if (result.success)
|
|
201
|
+
return result.data;
|
|
202
|
+
throw zodError("validate", result.error, opts.formatError, opts.filePath);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function validateSync(schema, raw, opts) {
|
|
206
|
+
let result;
|
|
207
|
+
try {
|
|
208
|
+
result = schema.safeParse(raw, opts.parseParams);
|
|
209
|
+
}
|
|
210
|
+
catch (cause) {
|
|
211
|
+
// e.g. "Encountered Promise during synchronous parse" for async refinements
|
|
212
|
+
throw new types_1.SchemaFileError("validate", `Synchronous validation failed for ${label(opts.filePath)}: ${errMsg(cause)} (try the async API)`, { filePath: opts.filePath, cause });
|
|
213
|
+
}
|
|
214
|
+
if (result.success)
|
|
215
|
+
return result.data;
|
|
216
|
+
throw zodError("validate", result.error, opts.formatError, opts.filePath);
|
|
217
|
+
}
|
|
218
|
+
function wireError(cause, strategy, opts) {
|
|
219
|
+
const kind = strategy === "encode" ? "encode" : "validate";
|
|
220
|
+
if (cause instanceof z.core.$ZodError)
|
|
221
|
+
return zodError(kind, cause, opts.formatError, opts.filePath);
|
|
222
|
+
const hint = cause instanceof z.core.$ZodAsyncError
|
|
223
|
+
? " (try the async API)"
|
|
224
|
+
: cause instanceof z.core.$ZodEncodeError
|
|
225
|
+
? ' (one-way .transform() cannot be encoded; use z.codec() or strategy: "parse")'
|
|
226
|
+
: "";
|
|
227
|
+
return new types_1.SchemaFileError(kind, `Could not ${strategy} value for ${label(opts.filePath)}: ${errMsg(cause)}${hint}`, {
|
|
228
|
+
filePath: opts.filePath,
|
|
229
|
+
cause,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function toWireSync(schema, value, opts) {
|
|
233
|
+
var _a;
|
|
234
|
+
const strategy = (_a = opts.strategy) !== null && _a !== void 0 ? _a : "encode";
|
|
235
|
+
if (strategy === "none")
|
|
236
|
+
return value;
|
|
237
|
+
try {
|
|
238
|
+
return strategy === "encode" ? z.encode(schema, value) : schema.parse(value);
|
|
239
|
+
}
|
|
240
|
+
catch (cause) {
|
|
241
|
+
throw wireError(cause, strategy, opts);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function toWireAsync(schema, value, opts) {
|
|
245
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
246
|
+
var _a;
|
|
247
|
+
const strategy = (_a = opts.strategy) !== null && _a !== void 0 ? _a : "encode";
|
|
248
|
+
if (strategy === "none")
|
|
249
|
+
return value;
|
|
250
|
+
try {
|
|
251
|
+
return strategy === "encode" ? yield z.encodeAsync(schema, value) : yield schema.parseAsync(value);
|
|
252
|
+
}
|
|
253
|
+
catch (cause) {
|
|
254
|
+
throw wireError(cause, strategy, opts);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function sortKeysDeep(v, compare) {
|
|
259
|
+
if (Array.isArray(v))
|
|
260
|
+
return v.map((x) => sortKeysDeep(x, compare));
|
|
261
|
+
if (isPlainObject(v)) {
|
|
262
|
+
return Object.fromEntries(Object.keys(v)
|
|
263
|
+
.sort(compare)
|
|
264
|
+
.map((k) => [k, sortKeysDeep(v[k], compare)]));
|
|
265
|
+
}
|
|
266
|
+
return v;
|
|
267
|
+
}
|
|
268
|
+
function render(data, opts) {
|
|
269
|
+
var _a, _b, _c, _d, _e;
|
|
270
|
+
const input = opts.sortKeys
|
|
271
|
+
? sortKeysDeep(data, typeof opts.sortKeys === "function" ? opts.sortKeys : undefined)
|
|
272
|
+
: data;
|
|
273
|
+
const indent = (_a = opts.indent) !== null && _a !== void 0 ? _a : 2;
|
|
274
|
+
const trailingNewline = opts.trailingNewline !== false;
|
|
275
|
+
try {
|
|
276
|
+
if (opts.format === "json") {
|
|
277
|
+
const out = JSON.stringify(input, (_b = opts.json) === null || _b === void 0 ? void 0 : _b.replacer, indent);
|
|
278
|
+
if (out === undefined)
|
|
279
|
+
throw new Error("value is not JSON-serializable");
|
|
280
|
+
return trailingNewline ? `${out}\n` : out;
|
|
281
|
+
}
|
|
282
|
+
const doc = new YAML.Document(input, (_c = opts.yaml) === null || _c === void 0 ? void 0 : _c.document);
|
|
283
|
+
if ((_d = opts.yaml) === null || _d === void 0 ? void 0 : _d.comment) {
|
|
284
|
+
doc.commentBefore = opts.yaml.comment
|
|
285
|
+
.split("\n")
|
|
286
|
+
.map((line) => (line ? ` ${line}` : line))
|
|
287
|
+
.join("\n");
|
|
288
|
+
}
|
|
289
|
+
const out = doc.toString(Object.assign({ indent }, (_e = opts.yaml) === null || _e === void 0 ? void 0 : _e.stringify));
|
|
290
|
+
return trailingNewline ? out : out.replace(/\n$/, "");
|
|
291
|
+
}
|
|
292
|
+
catch (cause) {
|
|
293
|
+
throw new types_1.SchemaFileError("serialize", `Failed to serialize ${label(opts.filePath)} as ${opts.format.toUpperCase()}: ${errMsg(cause)}`, { filePath: opts.filePath, cause });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function tempPathFor(filePath) {
|
|
297
|
+
const rand = Math.random().toString(36).slice(2, 10);
|
|
298
|
+
return node_path_1.default.join(node_path_1.default.dirname(filePath), `.${node_path_1.default.basename(filePath)}.${process.pid}.${rand}.tmp`);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The rename in an atomic write replaces whatever sits at the path, so it has to target the file a
|
|
302
|
+
* symlink points at (even one that does not exist yet), or the link itself gets replaced.
|
|
303
|
+
*/
|
|
304
|
+
function atomicTargetAsync(filePath) {
|
|
305
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
306
|
+
try {
|
|
307
|
+
return yield (0, promises_1.realpath)(filePath);
|
|
308
|
+
}
|
|
309
|
+
catch (_a) {
|
|
310
|
+
return (0, promises_1.readlink)(filePath).then((link) => node_path_1.default.resolve(node_path_1.default.dirname(filePath), link), () => filePath);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function atomicTargetSync(filePath) {
|
|
315
|
+
try {
|
|
316
|
+
return (0, node_fs_1.realpathSync)(filePath);
|
|
317
|
+
}
|
|
318
|
+
catch (_a) {
|
|
319
|
+
try {
|
|
320
|
+
return node_path_1.default.resolve(node_path_1.default.dirname(filePath), (0, node_fs_1.readlinkSync)(filePath));
|
|
321
|
+
}
|
|
322
|
+
catch (_b) {
|
|
323
|
+
return filePath;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/** The rename also swaps in a new file, so an explicit `mode` aside, keep the replaced file's permissions. */
|
|
328
|
+
function preservedModeAsync(target, opts) {
|
|
329
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
330
|
+
if (opts.mode !== undefined)
|
|
331
|
+
return undefined;
|
|
332
|
+
return (0, promises_1.stat)(target).then((stats) => stats.mode & 0o777, () => undefined);
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function preservedModeSync(target, opts) {
|
|
336
|
+
if (opts.mode !== undefined)
|
|
337
|
+
return undefined;
|
|
338
|
+
try {
|
|
339
|
+
return (0, node_fs_1.statSync)(target).mode & 0o777;
|
|
340
|
+
}
|
|
341
|
+
catch (_a) {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function writeTextAsync(filePath, text, opts) {
|
|
346
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
347
|
+
var _a;
|
|
348
|
+
try {
|
|
349
|
+
if (opts.createDirs !== false)
|
|
350
|
+
yield (0, promises_1.mkdir)(node_path_1.default.dirname(filePath), { recursive: true });
|
|
351
|
+
if (opts.overwrite === false && (yield (0, promises_1.access)(filePath).then(() => true, () => false))) {
|
|
352
|
+
throw new types_1.SchemaFileError("write", `Refusing to overwrite existing file ${filePath}`, { filePath });
|
|
353
|
+
}
|
|
354
|
+
const base = { encoding: (_a = opts.encoding) !== null && _a !== void 0 ? _a : "utf8", mode: opts.mode };
|
|
355
|
+
if (opts.atomic === false) {
|
|
356
|
+
yield (0, promises_1.writeFile)(filePath, text, Object.assign(Object.assign({}, base), { flag: opts.overwrite === false ? "wx" : "w" }));
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const target = yield atomicTargetAsync(filePath);
|
|
360
|
+
const preserved = yield preservedModeAsync(target, opts);
|
|
361
|
+
const tmp = tempPathFor(target);
|
|
362
|
+
try {
|
|
363
|
+
yield (0, promises_1.writeFile)(tmp, text, Object.assign(Object.assign({}, base), { flag: "wx" }));
|
|
364
|
+
if (preserved !== undefined)
|
|
365
|
+
yield (0, promises_1.chmod)(tmp, preserved);
|
|
366
|
+
yield (0, promises_1.rename)(tmp, target);
|
|
367
|
+
}
|
|
368
|
+
catch (e) {
|
|
369
|
+
yield (0, promises_1.unlink)(tmp).catch(() => {
|
|
370
|
+
});
|
|
371
|
+
throw e;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch (cause) {
|
|
375
|
+
if (cause instanceof types_1.SchemaFileError)
|
|
376
|
+
throw cause;
|
|
377
|
+
throw new types_1.SchemaFileError("write", `Failed to write ${filePath}: ${errMsg(cause)}`, { filePath, cause });
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function writeTextSync(filePath, text, opts) {
|
|
382
|
+
var _a;
|
|
383
|
+
try {
|
|
384
|
+
if (opts.createDirs !== false)
|
|
385
|
+
(0, node_fs_1.mkdirSync)(node_path_1.default.dirname(filePath), { recursive: true });
|
|
386
|
+
if (opts.overwrite === false && (0, node_fs_1.existsSync)(filePath)) {
|
|
387
|
+
throw new types_1.SchemaFileError("write", `Refusing to overwrite existing file ${filePath}`, { filePath });
|
|
388
|
+
}
|
|
389
|
+
const base = { encoding: (_a = opts.encoding) !== null && _a !== void 0 ? _a : "utf8", mode: opts.mode };
|
|
390
|
+
if (opts.atomic === false) {
|
|
391
|
+
(0, node_fs_1.writeFileSync)(filePath, text, Object.assign(Object.assign({}, base), { flag: opts.overwrite === false ? "wx" : "w" }));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const target = atomicTargetSync(filePath);
|
|
395
|
+
const preserved = preservedModeSync(target, opts);
|
|
396
|
+
const tmp = tempPathFor(target);
|
|
397
|
+
try {
|
|
398
|
+
(0, node_fs_1.writeFileSync)(tmp, text, Object.assign(Object.assign({}, base), { flag: "wx" }));
|
|
399
|
+
if (preserved !== undefined)
|
|
400
|
+
(0, node_fs_1.chmodSync)(tmp, preserved);
|
|
401
|
+
(0, node_fs_1.renameSync)(tmp, target);
|
|
402
|
+
}
|
|
403
|
+
catch (e) {
|
|
404
|
+
try {
|
|
405
|
+
(0, node_fs_1.unlinkSync)(tmp);
|
|
406
|
+
}
|
|
407
|
+
catch (_b) {
|
|
408
|
+
/* ignore */
|
|
409
|
+
}
|
|
410
|
+
throw e;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (cause) {
|
|
414
|
+
if (cause instanceof types_1.SchemaFileError)
|
|
415
|
+
throw cause;
|
|
416
|
+
throw new types_1.SchemaFileError("write", `Failed to write ${filePath}: ${errMsg(cause)}`, { filePath, cause });
|
|
417
|
+
}
|
|
418
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epsilon-asi/foundation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"mainDir": "./",
|
|
6
|
+
"types": "./build/index.d.ts",
|
|
7
|
+
"typesVersions": {
|
|
8
|
+
"*": {
|
|
9
|
+
"files": [
|
|
10
|
+
"./build/files/index.d.ts"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
6
14
|
"scripts": {
|
|
7
15
|
"build": "tsc",
|
|
8
16
|
"build:clean": "rm -rf ./build && npm run build",
|
|
@@ -50,6 +58,11 @@
|
|
|
50
58
|
"import": "./build/index.js",
|
|
51
59
|
"require": "./build/index.js"
|
|
52
60
|
},
|
|
61
|
+
"./files": {
|
|
62
|
+
"types": "./build/files/index.d.ts",
|
|
63
|
+
"import": "./build/files/index.js",
|
|
64
|
+
"require": "./build/files/index.js"
|
|
65
|
+
},
|
|
53
66
|
"./package.json": "./package.json"
|
|
54
67
|
},
|
|
55
68
|
"files": [
|
|
@@ -59,7 +72,9 @@
|
|
|
59
72
|
],
|
|
60
73
|
"author": "",
|
|
61
74
|
"license": "SEE LICENSE IN LICENSE",
|
|
62
|
-
"dependencies": {
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"yaml": "^2.9.1"
|
|
77
|
+
},
|
|
63
78
|
"peerDependencies": {
|
|
64
79
|
"zod": "^4.0.0"
|
|
65
80
|
}
|