@equinor/roma-framework 5.0.0 → 5.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/roma-framework",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "repository": "https://github.com/equinor/tops-roma",
5
5
  "types": "./index.d.ts",
6
6
  "private": false,
@@ -6,8 +6,8 @@ import { useState, useEffect, lazy, useRef, createContext, useContext, useMemo }
6
6
  import { ModuleProvider } from "@equinor/fusion-framework-react-module";
7
7
  import styled, { StyleSheetManager, keyframes } from "styled-components";
8
8
  import { EdsProvider, StarProgress, Typography, Card, Button, TopBar, Chip, SideSheet, Menu, Tooltip, Icon, List } from "@equinor/eds-core-react";
9
- import { E as EmptyError, o as operate, c as createOperatorSubscriber, i as innerFrom, a as identity, b as isFunction, I as IntlProvider, d as invariant, j as joinPaths, g as getResolveToMatches, r as resolveTo, w as warning, s as stripBasename, e as createPath, m as matchPath, B as BehaviorSubject, f as firstValueFrom, h as getDefaultExportFromCjs, k as of, l as from } from "./router-lZjM0_Ti.mjs";
10
- import { QueryClient, QueryClientProvider, useQueryClient, useQuery, useMutation } from "@tanstack/react-query";
9
+ import { E as EmptyError, o as operate, c as createOperatorSubscriber, i as innerFrom, a as identity, b as isFunction, I as IntlProvider, d as invariant, j as joinPaths, g as getResolveToMatches, r as resolveTo, w as warning, s as stripBasename, e as createPath, m as matchPath, B as BehaviorSubject, f as firstValueFrom, h as getDefaultExportFromCjs, k as of, l as from } from "./router-BRrTrnno.mjs";
10
+ import { QueryClient, QueryClientProvider, useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
11
11
  import { useCurrentApp, useApps as useApps$1 } from "@equinor/fusion-framework-react/app";
12
12
  import { App } from "@equinor/fusion-framework-module-app/app";
13
13
  import { tokens } from "@equinor/eds-tokens";
@@ -1598,10 +1598,20 @@ function promisifyRequest(request) {
1598
1598
  });
1599
1599
  }
1600
1600
  function createStore(dbName, storeName) {
1601
- const request = indexedDB.open(dbName);
1602
- request.onupgradeneeded = () => request.result.createObjectStore(storeName);
1603
- const dbp = promisifyRequest(request);
1604
- return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
1601
+ let dbp;
1602
+ const getDB = () => {
1603
+ if (dbp)
1604
+ return dbp;
1605
+ const request = indexedDB.open(dbName);
1606
+ request.onupgradeneeded = () => request.result.createObjectStore(storeName);
1607
+ dbp = promisifyRequest(request);
1608
+ dbp.then((db) => {
1609
+ db.onclose = () => dbp = void 0;
1610
+ }, () => {
1611
+ });
1612
+ return dbp;
1613
+ };
1614
+ return (txMode, callback) => getDB().then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
1605
1615
  }
1606
1616
  let defaultGetStoreFunc;
1607
1617
  function defaultGetStore() {
@@ -2090,29 +2100,18 @@ function printValue(value, quoteStrings) {
2090
2100
  function toArray(value) {
2091
2101
  return value == null ? [] : [].concat(value);
2092
2102
  }
2093
- let _Symbol$toStringTag;
2103
+ let _Symbol$toStringTag, _Symbol$hasInstance, _Symbol$toStringTag2;
2094
2104
  let strReg = /\$\{\s*(\w+)\s*\}/g;
2095
2105
  _Symbol$toStringTag = Symbol.toStringTag;
2096
- class ValidationError extends Error {
2097
- static formatError(message, params) {
2098
- const path = params.label || params.path || "this";
2099
- if (path !== params.path) params = Object.assign({}, params, {
2100
- path
2101
- });
2102
- if (typeof message === "string") return message.replace(strReg, (_, key) => printValue(params[key]));
2103
- if (typeof message === "function") return message(params);
2104
- return message;
2105
- }
2106
- static isError(err) {
2107
- return err && err.name === "ValidationError";
2108
- }
2109
- constructor(errorOrErrors, value, field, type, disableStack) {
2110
- super();
2106
+ class ValidationErrorNoStack {
2107
+ constructor(errorOrErrors, value, field, type) {
2108
+ this.name = void 0;
2109
+ this.message = void 0;
2111
2110
  this.value = void 0;
2112
2111
  this.path = void 0;
2113
2112
  this.type = void 0;
2114
- this.errors = void 0;
2115
2113
  this.params = void 0;
2114
+ this.errors = void 0;
2116
2115
  this.inner = void 0;
2117
2116
  this[_Symbol$toStringTag] = "Error";
2118
2117
  this.name = "ValidationError";
@@ -2131,7 +2130,50 @@ class ValidationError extends Error {
2131
2130
  }
2132
2131
  });
2133
2132
  this.message = this.errors.length > 1 ? `${this.errors.length} errors occurred` : this.errors[0];
2134
- if (!disableStack && Error.captureStackTrace) Error.captureStackTrace(this, ValidationError);
2133
+ }
2134
+ }
2135
+ _Symbol$hasInstance = Symbol.hasInstance;
2136
+ _Symbol$toStringTag2 = Symbol.toStringTag;
2137
+ class ValidationError extends Error {
2138
+ static formatError(message, params) {
2139
+ const path = params.label || params.path || "this";
2140
+ params = Object.assign({}, params, {
2141
+ path,
2142
+ originalPath: params.path
2143
+ });
2144
+ if (typeof message === "string") return message.replace(strReg, (_, key) => printValue(params[key]));
2145
+ if (typeof message === "function") return message(params);
2146
+ return message;
2147
+ }
2148
+ static isError(err) {
2149
+ return err && err.name === "ValidationError";
2150
+ }
2151
+ constructor(errorOrErrors, value, field, type, disableStack) {
2152
+ const errorNoStack = new ValidationErrorNoStack(errorOrErrors, value, field, type);
2153
+ if (disableStack) {
2154
+ return errorNoStack;
2155
+ }
2156
+ super();
2157
+ this.value = void 0;
2158
+ this.path = void 0;
2159
+ this.type = void 0;
2160
+ this.params = void 0;
2161
+ this.errors = [];
2162
+ this.inner = [];
2163
+ this[_Symbol$toStringTag2] = "Error";
2164
+ this.name = errorNoStack.name;
2165
+ this.message = errorNoStack.message;
2166
+ this.type = errorNoStack.type;
2167
+ this.value = errorNoStack.value;
2168
+ this.path = errorNoStack.path;
2169
+ this.errors = errorNoStack.errors;
2170
+ this.inner = errorNoStack.inner;
2171
+ if (Error.captureStackTrace) {
2172
+ Error.captureStackTrace(this, ValidationError);
2173
+ }
2174
+ }
2175
+ static [_Symbol$hasInstance](inst) {
2176
+ return ValidationErrorNoStack[Symbol.hasInstance](inst) || super[Symbol.hasInstance](inst);
2135
2177
  }
2136
2178
  }
2137
2179
  let mixed = {
@@ -2159,6 +2201,9 @@ let string = {
2159
2201
  email: "${path} must be a valid email",
2160
2202
  url: "${path} must be a valid URL",
2161
2203
  uuid: "${path} must be a valid UUID",
2204
+ datetime: "${path} must be a valid ISO date-time",
2205
+ datetime_precision: "${path} must be a valid ISO date-time with a sub-second precision of exactly ${precision} digits",
2206
+ datetime_offset: '${path} must be a valid ISO date-time with UTC "Z" timezone',
2162
2207
  trim: "${path} must be a trimmed string",
2163
2208
  lowercase: "${path} must be a lowercase string",
2164
2209
  uppercase: "${path} must be a upper case string"
@@ -2180,7 +2225,8 @@ let boolean = {
2180
2225
  isValue: "${path} field must be ${value}"
2181
2226
  };
2182
2227
  let object = {
2183
- noUnknown: "${path} field has unspecified keys: ${unknown}"
2228
+ noUnknown: "${path} field has unspecified keys: ${unknown}",
2229
+ exact: "${path} object contains unknown properties: ${properties}"
2184
2230
  };
2185
2231
  let array = {
2186
2232
  min: "${path} field must have at least ${min} items",
@@ -2327,20 +2373,21 @@ function createValidation(config) {
2327
2373
  abortEarly = schema.spec.abortEarly,
2328
2374
  disableStackTrace = schema.spec.disableStackTrace
2329
2375
  } = options;
2330
- function resolve(item) {
2331
- return Reference.isRef(item) ? item.getValue(value, parent, context) : item;
2332
- }
2376
+ const resolveOptions = {
2377
+ value,
2378
+ parent,
2379
+ context
2380
+ };
2333
2381
  function createError(overrides = {}) {
2334
- var _overrides$disableSta;
2335
- const nextParams = Object.assign({
2382
+ const nextParams = resolveParams(Object.assign({
2336
2383
  value,
2337
2384
  originalValue,
2338
2385
  label: schema.spec.label,
2339
2386
  path: overrides.path || path,
2340
- spec: schema.spec
2341
- }, params, overrides.params);
2342
- for (const key of Object.keys(nextParams)) nextParams[key] = resolve(nextParams[key]);
2343
- const error = new ValidationError(ValidationError.formatError(overrides.message || message, nextParams), value, nextParams.path, overrides.type || name, (_overrides$disableSta = overrides.disableStackTrace) != null ? _overrides$disableSta : disableStackTrace);
2387
+ spec: schema.spec,
2388
+ disableStackTrace: overrides.disableStackTrace || disableStackTrace
2389
+ }, params, overrides.params), resolveOptions);
2390
+ const error = new ValidationError(ValidationError.formatError(overrides.message || message, nextParams), value, nextParams.path, overrides.type || name, nextParams.disableStackTrace);
2344
2391
  error.params = nextParams;
2345
2392
  return error;
2346
2393
  }
@@ -2351,7 +2398,9 @@ function createValidation(config) {
2351
2398
  type: name,
2352
2399
  from: options.from,
2353
2400
  createError,
2354
- resolve,
2401
+ resolve(item) {
2402
+ return resolveMaybeRef(item, resolveOptions);
2403
+ },
2355
2404
  options,
2356
2405
  originalValue,
2357
2406
  schema
@@ -2388,6 +2437,16 @@ function createValidation(config) {
2388
2437
  validate.OPTIONS = config;
2389
2438
  return validate;
2390
2439
  }
2440
+ function resolveParams(params, options) {
2441
+ if (!params) return params;
2442
+ for (const key of Object.keys(params)) {
2443
+ params[key] = resolveMaybeRef(params[key], options);
2444
+ }
2445
+ return params;
2446
+ }
2447
+ function resolveMaybeRef(item, options) {
2448
+ return Reference.isRef(item) ? item.getValue(options.value, options.parent, options.context) : item;
2449
+ }
2391
2450
  function getIn(schema, path, value, context = value) {
2392
2451
  let parent, lastPart, lastPartDebug;
2393
2452
  if (!path) return {
@@ -2484,6 +2543,69 @@ function clone(src, seen = /* @__PURE__ */ new Map()) {
2484
2543
  }
2485
2544
  return copy;
2486
2545
  }
2546
+ function createStandardPath(path) {
2547
+ if (!(path != null && path.length)) {
2548
+ return void 0;
2549
+ }
2550
+ const segments = [];
2551
+ let currentSegment = "";
2552
+ let inBrackets = false;
2553
+ let inQuotes = false;
2554
+ for (let i = 0; i < path.length; i++) {
2555
+ const char = path[i];
2556
+ if (char === "[" && !inQuotes) {
2557
+ if (currentSegment) {
2558
+ segments.push(...currentSegment.split(".").filter(Boolean));
2559
+ currentSegment = "";
2560
+ }
2561
+ inBrackets = true;
2562
+ continue;
2563
+ }
2564
+ if (char === "]" && !inQuotes) {
2565
+ if (currentSegment) {
2566
+ if (/^\d+$/.test(currentSegment)) {
2567
+ segments.push(currentSegment);
2568
+ } else {
2569
+ segments.push(currentSegment.replace(/^"|"$/g, ""));
2570
+ }
2571
+ currentSegment = "";
2572
+ }
2573
+ inBrackets = false;
2574
+ continue;
2575
+ }
2576
+ if (char === '"') {
2577
+ inQuotes = !inQuotes;
2578
+ continue;
2579
+ }
2580
+ if (char === "." && !inBrackets && !inQuotes) {
2581
+ if (currentSegment) {
2582
+ segments.push(currentSegment);
2583
+ currentSegment = "";
2584
+ }
2585
+ continue;
2586
+ }
2587
+ currentSegment += char;
2588
+ }
2589
+ if (currentSegment) {
2590
+ segments.push(...currentSegment.split(".").filter(Boolean));
2591
+ }
2592
+ return segments;
2593
+ }
2594
+ function createStandardIssues(error, parentPath) {
2595
+ const path = parentPath ? `${parentPath}.${error.path}` : error.path;
2596
+ return error.errors.map((err) => ({
2597
+ message: err,
2598
+ path: createStandardPath(path)
2599
+ }));
2600
+ }
2601
+ function issuesFromValidationError(error, parentPath) {
2602
+ var _error$inner;
2603
+ if (!((_error$inner = error.inner) != null && _error$inner.length) && error.errors.length) {
2604
+ return createStandardIssues(error, parentPath);
2605
+ }
2606
+ const path = parentPath ? `${parentPath}.${error.path}` : error.path;
2607
+ return error.inner.flatMap((err) => issuesFromValidationError(err, path));
2608
+ }
2487
2609
  class Schema {
2488
2610
  constructor(options) {
2489
2611
  this.type = void 0;
@@ -2613,9 +2735,11 @@ class Schema {
2613
2735
  * Run the configured transform pipeline over an input value.
2614
2736
  */
2615
2737
  cast(value, options = {}) {
2616
- let resolvedSchema = this.resolve(Object.assign({
2738
+ let resolvedSchema = this.resolve(Object.assign({}, options, {
2617
2739
  value
2618
- }, options));
2740
+ // parent: options.parent,
2741
+ // context: options.context,
2742
+ }));
2619
2743
  let allowOptionality = options.assert === "ignore-optionality";
2620
2744
  let result = resolvedSchema._cast(value, options);
2621
2745
  if (options.assert !== false && !resolvedSchema.isType(result)) {
@@ -2632,7 +2756,7 @@ attempted value: ${formattedValue}
2632
2756
  return result;
2633
2757
  }
2634
2758
  _cast(rawValue, options) {
2635
- let value = rawValue === void 0 ? rawValue : this.transforms.reduce((prevValue, fn) => fn.call(this, prevValue, rawValue, this), rawValue);
2759
+ let value = rawValue === void 0 ? rawValue : this.transforms.reduce((prevValue, fn) => fn.call(this, prevValue, rawValue, this, options), rawValue);
2636
2760
  if (value === void 0) {
2637
2761
  value = this.getDefault(options);
2638
2762
  }
@@ -2745,7 +2869,7 @@ attempted value: ${formattedValue}
2745
2869
  key: void 0,
2746
2870
  // index: undefined,
2747
2871
  [isIndex ? "index" : "key"]: k,
2748
- path: isIndex || k.includes(".") ? `${parentPath || ""}[${value ? k : `"${k}"`}]` : (parentPath ? `${parentPath}.` : "") + key
2872
+ path: isIndex || k.includes(".") ? `${parentPath || ""}[${isIndex ? k : `"${k}"`}]` : (parentPath ? `${parentPath}.` : "") + key
2749
2873
  });
2750
2874
  return (_, panic, next) => this.resolve(testOptions)._validate(value, testOptions, panic, next);
2751
2875
  }
@@ -3027,13 +3151,41 @@ attempted value: ${formattedValue}
3027
3151
  type: next.type,
3028
3152
  oneOf: next._whitelist.describe(),
3029
3153
  notOneOf: next._blacklist.describe(),
3030
- tests: next.tests.map((fn) => ({
3031
- name: fn.OPTIONS.name,
3032
- params: fn.OPTIONS.params
3033
- })).filter((n, idx, list) => list.findIndex((c) => c.name === n.name) === idx)
3154
+ tests: next.tests.filter((n, idx, list) => list.findIndex((c) => c.OPTIONS.name === n.OPTIONS.name) === idx).map((fn) => {
3155
+ const params = fn.OPTIONS.params && options ? resolveParams(Object.assign({}, fn.OPTIONS.params), options) : fn.OPTIONS.params;
3156
+ return {
3157
+ name: fn.OPTIONS.name,
3158
+ params
3159
+ };
3160
+ })
3034
3161
  };
3035
3162
  return description;
3036
3163
  }
3164
+ get ["~standard"]() {
3165
+ const schema = this;
3166
+ const standard = {
3167
+ version: 1,
3168
+ vendor: "yup",
3169
+ async validate(value) {
3170
+ try {
3171
+ const result = await schema.validate(value, {
3172
+ abortEarly: false
3173
+ });
3174
+ return {
3175
+ value: result
3176
+ };
3177
+ } catch (err) {
3178
+ if (err instanceof ValidationError) {
3179
+ return {
3180
+ issues: issuesFromValidationError(err)
3181
+ };
3182
+ }
3183
+ throw err;
3184
+ }
3185
+ }
3186
+ };
3187
+ return standard;
3188
+ }
3037
3189
  }
3038
3190
  Schema.prototype.__isYupSchema__ = true;
3039
3191
  for (const method of ["validate", "validateSync"]) Schema.prototype[`${method}At`] = function(path, value, options = {}) {
@@ -3062,8 +3214,8 @@ class BooleanSchema extends Schema {
3062
3214
  }
3063
3215
  });
3064
3216
  this.withMutation(() => {
3065
- this.transform((value, _raw, ctx) => {
3066
- if (ctx.spec.coerce && !ctx.isType(value)) {
3217
+ this.transform((value, _raw) => {
3218
+ if (this.spec.coerce && !this.isType(value)) {
3067
3219
  if (/^(true|1)$/i.test(String(value))) return true;
3068
3220
  if (/^(false|0)$/i.test(String(value))) return false;
3069
3221
  }
@@ -3123,6 +3275,45 @@ class BooleanSchema extends Schema {
3123
3275
  }
3124
3276
  }
3125
3277
  create$7.prototype = BooleanSchema.prototype;
3278
+ const isoReg = /^(\d{4}|[+-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,.](\d{1,}))?)?(?:(Z)|([+-])(\d{2})(?::?(\d{2}))?)?)?$/;
3279
+ function parseIsoDate(date2) {
3280
+ const struct = parseDateStruct(date2);
3281
+ if (!struct) return Date.parse ? Date.parse(date2) : Number.NaN;
3282
+ if (struct.z === void 0 && struct.plusMinus === void 0) {
3283
+ return new Date(struct.year, struct.month, struct.day, struct.hour, struct.minute, struct.second, struct.millisecond).valueOf();
3284
+ }
3285
+ let totalMinutesOffset = 0;
3286
+ if (struct.z !== "Z" && struct.plusMinus !== void 0) {
3287
+ totalMinutesOffset = struct.hourOffset * 60 + struct.minuteOffset;
3288
+ if (struct.plusMinus === "+") totalMinutesOffset = 0 - totalMinutesOffset;
3289
+ }
3290
+ return Date.UTC(struct.year, struct.month, struct.day, struct.hour, struct.minute + totalMinutesOffset, struct.second, struct.millisecond);
3291
+ }
3292
+ function parseDateStruct(date2) {
3293
+ var _regexResult$7$length, _regexResult$;
3294
+ const regexResult = isoReg.exec(date2);
3295
+ if (!regexResult) return null;
3296
+ return {
3297
+ year: toNumber(regexResult[1]),
3298
+ month: toNumber(regexResult[2], 1) - 1,
3299
+ day: toNumber(regexResult[3], 1),
3300
+ hour: toNumber(regexResult[4]),
3301
+ minute: toNumber(regexResult[5]),
3302
+ second: toNumber(regexResult[6]),
3303
+ millisecond: regexResult[7] ? (
3304
+ // allow arbitrary sub-second precision beyond milliseconds
3305
+ toNumber(regexResult[7].substring(0, 3))
3306
+ ) : 0,
3307
+ precision: (_regexResult$7$length = (_regexResult$ = regexResult[7]) == null ? void 0 : _regexResult$.length) != null ? _regexResult$7$length : void 0,
3308
+ z: regexResult[8] || void 0,
3309
+ plusMinus: regexResult[9] || void 0,
3310
+ hourOffset: toNumber(regexResult[10]),
3311
+ minuteOffset: toNumber(regexResult[11])
3312
+ };
3313
+ }
3314
+ function toNumber(str, defaultValue = 0) {
3315
+ return Number(str) || defaultValue;
3316
+ }
3126
3317
  let rEmail = (
3127
3318
  // eslint-disable-next-line
3128
3319
  /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
@@ -3132,6 +3323,10 @@ let rUrl = (
3132
3323
  /^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
3133
3324
  );
3134
3325
  let rUUID = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
3326
+ let yearMonthDay = "^\\d{4}-\\d{2}-\\d{2}";
3327
+ let hourMinuteSecond = "\\d{2}:\\d{2}:\\d{2}";
3328
+ let zOrOffset = "(([+-]\\d{2}(:?\\d{2})?)|Z)";
3329
+ let rIsoDateTime = new RegExp(`${yearMonthDay}T${hourMinuteSecond}(\\.\\d+)?${zOrOffset}$`);
3135
3330
  let isTrimmed = (value) => isAbsent(value) || value === value.trim();
3136
3331
  let objStringTag = {}.toString();
3137
3332
  function create$6() {
@@ -3147,8 +3342,8 @@ class StringSchema extends Schema {
3147
3342
  }
3148
3343
  });
3149
3344
  this.withMutation(() => {
3150
- this.transform((value, _raw, ctx) => {
3151
- if (!ctx.spec.coerce || ctx.isType(value)) return value;
3345
+ this.transform((value, _raw) => {
3346
+ if (!this.spec.coerce || this.isType(value)) return value;
3152
3347
  if (Array.isArray(value)) return value;
3153
3348
  const strValue = value != null && value.toString ? value.toString() : value;
3154
3349
  if (strValue === objStringTag) return value;
@@ -3258,6 +3453,53 @@ class StringSchema extends Schema {
3258
3453
  excludeEmptyString: false
3259
3454
  });
3260
3455
  }
3456
+ datetime(options) {
3457
+ let message = "";
3458
+ let allowOffset;
3459
+ let precision;
3460
+ if (options) {
3461
+ if (typeof options === "object") {
3462
+ ({
3463
+ message = "",
3464
+ allowOffset = false,
3465
+ precision = void 0
3466
+ } = options);
3467
+ } else {
3468
+ message = options;
3469
+ }
3470
+ }
3471
+ return this.matches(rIsoDateTime, {
3472
+ name: "datetime",
3473
+ message: message || string.datetime,
3474
+ excludeEmptyString: true
3475
+ }).test({
3476
+ name: "datetime_offset",
3477
+ message: message || string.datetime_offset,
3478
+ params: {
3479
+ allowOffset
3480
+ },
3481
+ skipAbsent: true,
3482
+ test: (value) => {
3483
+ if (!value || allowOffset) return true;
3484
+ const struct = parseDateStruct(value);
3485
+ if (!struct) return false;
3486
+ return !!struct.z;
3487
+ }
3488
+ }).test({
3489
+ name: "datetime_precision",
3490
+ message: message || string.datetime_precision,
3491
+ params: {
3492
+ precision
3493
+ },
3494
+ skipAbsent: true,
3495
+ test: (value) => {
3496
+ if (!value || precision == void 0) return true;
3497
+ const struct = parseDateStruct(value);
3498
+ if (!struct) return false;
3499
+ return struct.precision === precision;
3500
+ }
3501
+ });
3502
+ }
3261
3503
  //-- transforms --
3262
3504
  ensure() {
3263
3505
  return this.default("").transform((val) => val === null ? "" : val);
@@ -3289,39 +3531,6 @@ class StringSchema extends Schema {
3289
3531
  }
3290
3532
  }
3291
3533
  create$6.prototype = StringSchema.prototype;
3292
- const isoReg = /^(\d{4}|[+-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,.](\d{1,}))?)?(?:(Z)|([+-])(\d{2})(?::?(\d{2}))?)?)?$/;
3293
- function toNumber(str, defaultValue = 0) {
3294
- return Number(str) || defaultValue;
3295
- }
3296
- function parseIsoDate(date2) {
3297
- const regexResult = isoReg.exec(date2);
3298
- if (!regexResult) return Date.parse ? Date.parse(date2) : Number.NaN;
3299
- const struct = {
3300
- year: toNumber(regexResult[1]),
3301
- month: toNumber(regexResult[2], 1) - 1,
3302
- day: toNumber(regexResult[3], 1),
3303
- hour: toNumber(regexResult[4]),
3304
- minute: toNumber(regexResult[5]),
3305
- second: toNumber(regexResult[6]),
3306
- millisecond: regexResult[7] ? (
3307
- // allow arbitrary sub-second precision beyond milliseconds
3308
- toNumber(regexResult[7].substring(0, 3))
3309
- ) : 0,
3310
- z: regexResult[8] || void 0,
3311
- plusMinus: regexResult[9] || void 0,
3312
- hourOffset: toNumber(regexResult[10]),
3313
- minuteOffset: toNumber(regexResult[11])
3314
- };
3315
- if (struct.z === void 0 && struct.plusMinus === void 0) {
3316
- return new Date(struct.year, struct.month, struct.day, struct.hour, struct.minute, struct.second, struct.millisecond).valueOf();
3317
- }
3318
- let totalMinutesOffset = 0;
3319
- if (struct.z !== "Z" && struct.plusMinus !== void 0) {
3320
- totalMinutesOffset = struct.hourOffset * 60 + struct.minuteOffset;
3321
- if (struct.plusMinus === "+") totalMinutesOffset = 0 - totalMinutesOffset;
3322
- }
3323
- return Date.UTC(struct.year, struct.month, struct.day, struct.hour, struct.minute + totalMinutesOffset, struct.second, struct.millisecond);
3324
- }
3325
3534
  let invalidDate = /* @__PURE__ */ new Date("");
3326
3535
  let isDate = (obj) => Object.prototype.toString.call(obj) === "[object Date]";
3327
3536
  class DateSchema extends Schema {
@@ -3333,8 +3542,8 @@ class DateSchema extends Schema {
3333
3542
  }
3334
3543
  });
3335
3544
  this.withMutation(() => {
3336
- this.transform((value, _raw, ctx) => {
3337
- if (!ctx.spec.coerce || ctx.isType(value) || value === null) return value;
3545
+ this.transform((value, _raw) => {
3546
+ if (!this.spec.coerce || this.isType(value) || value === null) return value;
3338
3547
  value = parseIsoDate(value);
3339
3548
  return !isNaN(value) ? new Date(value) : DateSchema.INVALID_DATE;
3340
3549
  });
@@ -3416,7 +3625,7 @@ function sortByKeyOrder(keys) {
3416
3625
  return findIndex(keys, a) - findIndex(keys, b);
3417
3626
  };
3418
3627
  }
3419
- const parseJson = (value, _, ctx) => {
3628
+ const parseJson = (value, _, schema) => {
3420
3629
  if (typeof value !== "string") {
3421
3630
  return value;
3422
3631
  }
@@ -3425,7 +3634,7 @@ const parseJson = (value, _, ctx) => {
3425
3634
  parsed = JSON.parse(value);
3426
3635
  } catch (err) {
3427
3636
  }
3428
- return ctx.isType(parsed) ? parsed : value;
3637
+ return schema.isType(parsed) ? parsed : value;
3429
3638
  };
3430
3639
  function deepPartial(schema) {
3431
3640
  if ("fields" in schema) {
@@ -3501,9 +3710,9 @@ class ObjectSchema extends Schema {
3501
3710
  for (const prop of props) {
3502
3711
  let field = fields[prop];
3503
3712
  let exists = prop in value;
3713
+ let inputValue = value[prop];
3504
3714
  if (field) {
3505
3715
  let fieldValue;
3506
- let inputValue = value[prop];
3507
3716
  innerOptions.path = (options.path ? `${options.path}.` : "") + prop;
3508
3717
  field = field.resolve({
3509
3718
  value: inputValue,
@@ -3516,17 +3725,14 @@ class ObjectSchema extends Schema {
3516
3725
  isChanged = isChanged || prop in value;
3517
3726
  continue;
3518
3727
  }
3519
- fieldValue = !options.__validating || !strict ? (
3520
- // TODO: use _cast, this is double resolving
3521
- field.cast(value[prop], innerOptions)
3522
- ) : value[prop];
3728
+ fieldValue = !options.__validating || !strict ? field.cast(inputValue, innerOptions) : inputValue;
3523
3729
  if (fieldValue !== void 0) {
3524
3730
  intermediateValue[prop] = fieldValue;
3525
3731
  }
3526
3732
  } else if (exists && !strip) {
3527
- intermediateValue[prop] = value[prop];
3733
+ intermediateValue[prop] = inputValue;
3528
3734
  }
3529
- if (exists !== prop in intermediateValue || intermediateValue[prop] !== value[prop]) {
3735
+ if (exists !== prop in intermediateValue || intermediateValue[prop] !== inputValue) {
3530
3736
  isChanged = true;
3531
3737
  }
3532
3738
  }
@@ -3677,6 +3883,30 @@ class ObjectSchema extends Schema {
3677
3883
  json() {
3678
3884
  return this.transform(parseJson);
3679
3885
  }
3886
+ /**
3887
+ * Similar to `noUnknown` but only validates that an object is the right shape without stripping the unknown keys
3888
+ */
3889
+ exact(message) {
3890
+ return this.test({
3891
+ name: "exact",
3892
+ exclusive: true,
3893
+ message: message || object.exact,
3894
+ test(value) {
3895
+ if (value == null) return true;
3896
+ const unknownKeys = unknown(this.schema, value);
3897
+ return unknownKeys.length === 0 || this.createError({
3898
+ params: {
3899
+ properties: unknownKeys.join(", ")
3900
+ }
3901
+ });
3902
+ }
3903
+ });
3904
+ }
3905
+ stripUnknown() {
3906
+ return this.clone({
3907
+ noUnknown: true
3908
+ });
3909
+ }
3680
3910
  noUnknown(noAllow = true, message = object.noUnknown) {
3681
3911
  if (typeof noAllow !== "boolean") {
3682
3912
  message = noAllow;
@@ -3763,7 +3993,11 @@ class ArraySchema extends Schema {
3763
3993
  let isChanged = false;
3764
3994
  const castArray = value.map((v, idx) => {
3765
3995
  const castElement = this.innerType.cast(v, Object.assign({}, _opts, {
3766
- path: `${_opts.path || ""}[${idx}]`
3996
+ path: `${_opts.path || ""}[${idx}]`,
3997
+ parent: value,
3998
+ originalValue: v,
3999
+ value: v,
4000
+ index: idx
3767
4001
  }));
3768
4002
  if (castElement !== v) {
3769
4003
  isChanged = true;