@lunora/values 1.0.0-alpha.1 → 1.0.0-alpha.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/dist/index.mjs CHANGED
@@ -1,9 +1,5 @@
1
- export { ValidationError, describeValue, formatPath } from './packem_shared/ValidationError-DWWcFe37.mjs';
2
- export { jsonSchemaFromNode, objectSchemaFromNodes } from './packem_shared/jsonSchemaFromNode-weszUOQG.mjs';
3
- export { argsToJsonSchema, toJsonSchema } from './packem_shared/argsToJsonSchema-DdHmmamC.mjs';
4
- export { isOrWrapsFromValidator, optionalInner, v } from './packem_shared/isOrWrapsFromValidator-DJMAE0l9.mjs';
5
- export { parseValidatorMap } from './packem_shared/parseValidatorMap-CCjevE5Z.mjs';
6
-
7
- const VERSION = "0.0.0";
8
-
9
- export { VERSION };
1
+ export { ValidationError, describeValue, formatPath } from './packem_shared/ValidationError-CoyFtkxj.mjs';
2
+ export { jsonSchemaFromNode, objectSchemaFromNodes } from './packem_shared/jsonSchemaFromNode-e81rO5qr.mjs';
3
+ export { argsToJsonSchema, toJsonSchema } from './packem_shared/argsToJsonSchema-DSAZmlYY.mjs';
4
+ export { isOrWrapsFromValidator, optionalInner, v } from './packem_shared/isOrWrapsFromValidator-BQtxt-B8.mjs';
5
+ export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap } from './packem_shared/DEFER_VALIDATION-CIKr17sW.mjs';
@@ -1,13 +1,25 @@
1
- import { ValidationError } from './ValidationError-DWWcFe37.mjs';
1
+ import { ValidationError } from './ValidationError-CoyFtkxj.mjs';
2
2
 
3
+ const DEFER_VALIDATION = /* @__PURE__ */ Symbol("lunora.deferValidation");
4
+ const COMPILED_PARSERS = /* @__PURE__ */ new WeakMap();
5
+ const installCompiledValidatorMap = (validators, compiled) => {
6
+ COMPILED_PARSERS.set(validators, compiled);
7
+ };
3
8
  const parseValidatorMap = (validators, source, label) => {
9
+ const compiled = COMPILED_PARSERS.get(validators);
10
+ if (compiled !== void 0) {
11
+ const fast = compiled(source);
12
+ if (fast !== DEFER_VALIDATION) {
13
+ return fast;
14
+ }
15
+ }
4
16
  const out = {};
5
17
  for (const key of Object.keys(validators)) {
6
18
  const validator = validators[key];
7
19
  if (!validator) {
8
20
  continue;
9
21
  }
10
- const candidate = source[key];
22
+ const candidate = Object.hasOwn(source, key) ? source[key] : void 0;
11
23
  if (candidate === void 0 && validator.kind === "optional") {
12
24
  continue;
13
25
  }
@@ -27,4 +39,4 @@ const parseValidatorMap = (validators, source, label) => {
27
39
  return out;
28
40
  };
29
41
 
30
- export { parseValidatorMap };
42
+ export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap };
@@ -1,18 +1,32 @@
1
+ import { LunoraError } from '@lunora/errors';
2
+
1
3
  const MAX_DESCRIBED_LENGTH = 80;
2
4
  const truncate = (text) => text.length > MAX_DESCRIBED_LENGTH ? `${text.slice(0, MAX_DESCRIBED_LENGTH)}…` : text;
3
- class ValidationError extends Error {
5
+ const describeObject = (value) => {
6
+ try {
7
+ const { constructor } = value;
8
+ const constructorName = constructor?.name;
9
+ if (constructorName !== void 0 && constructorName !== "Object") {
10
+ return `object ${constructorName}`;
11
+ }
12
+ } catch {
13
+ return "object";
14
+ }
15
+ return "object";
16
+ };
17
+ class ValidationError extends LunoraError {
4
18
  path;
5
19
  expected;
6
20
  received;
7
21
  constructor(message, options) {
8
- super(message);
9
- this.name = "ValidationError";
22
+ super("VALIDATION_ERROR", message, { name: "ValidationError" });
10
23
  this.path = options.path;
11
24
  this.expected = options.expected;
12
25
  this.received = options.received;
13
26
  }
14
27
  }
15
- const describeValue = (value) => {
28
+ const describeValue = (value, options) => {
29
+ const literal = options?.literal ?? true;
16
30
  if (value === null) {
17
31
  return "null";
18
32
  }
@@ -23,25 +37,16 @@ const describeValue = (value) => {
23
37
  return "ArrayBuffer";
24
38
  }
25
39
  if (typeof value === "string") {
26
- return `string ${truncate(JSON.stringify(value))}`;
40
+ return literal ? `string ${truncate(JSON.stringify(value))}` : "string";
27
41
  }
28
42
  if (typeof value === "number" || typeof value === "boolean") {
29
- return `${typeof value} ${String(value)}`;
43
+ return literal ? `${typeof value} ${String(value)}` : typeof value;
30
44
  }
31
45
  if (typeof value === "bigint") {
32
- return `bigint ${value.toString()}n`;
46
+ return literal ? `bigint ${value.toString()}n` : "bigint";
33
47
  }
34
48
  if (typeof value === "object") {
35
- try {
36
- const { constructor } = value;
37
- const constructorName = constructor?.name;
38
- if (constructorName !== void 0 && constructorName !== "Object") {
39
- return `object ${constructorName}`;
40
- }
41
- } catch {
42
- return "object";
43
- }
44
- return "object";
49
+ return describeObject(value);
45
50
  }
46
51
  return typeof value;
47
52
  };
@@ -1,4 +1,4 @@
1
- import { objectSchemaFromNodes, jsonSchemaFromNode } from './jsonSchemaFromNode-weszUOQG.mjs';
1
+ import { objectSchemaFromNodes, jsonSchemaFromNode } from './jsonSchemaFromNode-e81rO5qr.mjs';
2
2
 
3
3
  const introspect = (validator) => validator;
4
4
  const metaOf = (validator) => introspect(validator)._meta ?? {};
@@ -1,8 +1,9 @@
1
- import { ValidationError, formatPath, describeValue } from './ValidationError-DWWcFe37.mjs';
1
+ import { LunoraError } from '@lunora/errors';
2
+ import { ValidationError, formatPath, describeValue } from './ValidationError-CoyFtkxj.mjs';
2
3
 
3
- function fail(context, expected, received) {
4
+ function fail(context, expected, received, options) {
4
5
  const path = [...context.path];
5
- const receivedDescription = describeValue(received);
6
+ const receivedDescription = describeValue(received, { literal: !options?.redactValue });
6
7
  throw new ValidationError(`Expected ${expected} at ${formatPath(path)}, received ${receivedDescription}`, {
7
8
  expected,
8
9
  path,
@@ -77,7 +78,7 @@ const createValidator = (kind, parser, meta) => {
77
78
  const refinedParser = (value, context) => {
78
79
  const parsed = parser(value, context);
79
80
  if (!predicate(parsed)) {
80
- fail(context, message ?? "value matching refinement", parsed);
81
+ fail(context, message ?? "value matching refinement", parsed, { redactValue: true });
81
82
  }
82
83
  return parsed;
83
84
  };
@@ -171,6 +172,24 @@ const storage = (bucket) => asColumn(
171
172
  bucket === void 0 ? void 0 : { bucket }
172
173
  )
173
174
  );
175
+ const geoPoint = () => asColumn(
176
+ createValidator("geoPoint", (value, context) => {
177
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
178
+ fail(context, "geoPoint { lat, lng }", value);
179
+ }
180
+ const point = value;
181
+ const { lat, lng } = point;
182
+ if (typeof lat !== "number" || !Number.isFinite(lat) || lat < -90 || lat > 90) {
183
+ context.path.push("lat");
184
+ fail(context, "latitude in [-90, 90]", lat);
185
+ }
186
+ if (typeof lng !== "number" || !Number.isFinite(lng) || lng < -180 || lng > 180) {
187
+ context.path.push("lng");
188
+ fail(context, "longitude in [-180, 180]", lng);
189
+ }
190
+ return { lat, lng };
191
+ })
192
+ );
174
193
  const literal = (literalValue) => asColumn(
175
194
  createValidator(
176
195
  "literal",
@@ -193,11 +212,11 @@ const array = (inner) => {
193
212
  fail(context, "array", value);
194
213
  }
195
214
  const { length } = value;
196
- const out = Array.from({ length });
215
+ const out = [];
197
216
  const { path } = context;
198
217
  for (let index = 0; index < length; index += 1) {
199
218
  path.push(index);
200
- out[index] = innerInternal._parse(value[index], context);
219
+ out.push(innerInternal._parse(value[index], context));
201
220
  path.pop();
202
221
  }
203
222
  return out;
@@ -222,7 +241,7 @@ const objectValidator = (shape) => {
222
241
  const out = {};
223
242
  const { path } = context;
224
243
  for (const { child, isOptional, key } of entries) {
225
- const fieldValue = input[key];
244
+ const fieldValue = Object.hasOwn(input, key) ? input[key] : void 0;
226
245
  if (fieldValue === void 0 && isOptional) {
227
246
  continue;
228
247
  }
@@ -264,7 +283,7 @@ const record = (keyValidator, valueValidator) => {
264
283
  };
265
284
  const union = (...members) => {
266
285
  if (members.length === 0) {
267
- throw new Error("v.union requires at least one member");
286
+ throw new LunoraError("INTERNAL", "v.union requires at least one member");
268
287
  }
269
288
  const memberInternals = members.map((member) => toInternal(member));
270
289
  return asColumn(
@@ -324,7 +343,7 @@ const standardIssuePath = (path) => {
324
343
  const from = (schema) => {
325
344
  const props = schema["~standard"];
326
345
  if (props?.version !== 1 || typeof props.validate !== "function") {
327
- throw new Error('@lunora/values: v.from() expects a Standard Schema v1 object (missing or invalid "~standard")');
346
+ throw new LunoraError("INTERNAL", '@lunora/values: v.from() expects a Standard Schema v1 object (missing or invalid "~standard")');
328
347
  }
329
348
  const validate = props.validate;
330
349
  return asColumn(
@@ -396,6 +415,7 @@ const v = {
396
415
  bytes,
397
416
  date,
398
417
  from,
418
+ geoPoint,
399
419
  id,
400
420
  literal,
401
421
  null: nullValidator,
@@ -20,6 +20,14 @@ const jsonSchemaFromNode = (node, reader) => {
20
20
  case "date": {
21
21
  return { description: "epoch milliseconds (date)", type: "integer" };
22
22
  }
23
+ case "geoPoint": {
24
+ return {
25
+ description: "geographic point (WGS84 decimal degrees)",
26
+ properties: { lat: { maximum: 90, minimum: -90, type: "number" }, lng: { maximum: 180, minimum: -180, type: "number" } },
27
+ required: ["lat", "lng"],
28
+ type: "object"
29
+ };
30
+ }
23
31
  case "id": {
24
32
  return { description: `Id<"${String(reader.tableName(node))}">`, type: "string", "x-lunora-table": reader.tableName(node) };
25
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/values",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.11",
4
4
  "description": "Validators for Lunora: the v.* validator suite with end-to-end return-type inference",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -25,7 +25,7 @@
25
25
  "directory": "packages/values"
26
26
  },
27
27
  "files": [
28
- "dist",
28
+ "./dist",
29
29
  "README.md",
30
30
  "LICENSE.md",
31
31
  "__assets__"
@@ -45,6 +45,9 @@
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
+ "dependencies": {
49
+ "@lunora/errors": "1.0.0-alpha.8"
50
+ },
48
51
  "engines": {
49
52
  "node": "^22.15.0 || >=24.11.0"
50
53
  }