@atscript/typescript 0.1.40 → 0.1.42

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/cli.cjs CHANGED
@@ -688,27 +688,26 @@ else obj[key] = value;
688
688
  }
689
689
  const regexCache = new Map();
690
690
  var Validator = class {
691
- isLimitExceeded() {
692
- if (this.stackErrors.length > 0) {
693
- const top = this.stackErrors[this.stackErrors.length - 1];
694
- return top !== null && top.length >= this.opts.errorLimit;
695
- }
696
- return this.errors.length >= this.opts.errorLimit;
691
+ buildPath() {
692
+ if (this.depth <= 0) return "";
693
+ let path$4 = this.pathSegments[0];
694
+ for (let i = 1; i < this.depth; i++) path$4 += `.${this.pathSegments[i]}`;
695
+ return path$4;
697
696
  }
698
697
  push(name) {
699
- this.stackPath.push(name);
698
+ this.pathSegments[this.depth] = name;
699
+ this.depth++;
700
700
  this.stackErrors.push(null);
701
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
702
701
  }
703
702
  pop(saveErrors) {
704
- this.stackPath.pop();
703
+ this.depth--;
705
704
  const popped = this.stackErrors.pop();
706
705
  if (saveErrors && popped !== null && popped !== undefined && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
707
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
708
706
  return popped;
709
707
  }
710
708
  clear() {
711
709
  this.stackErrors[this.stackErrors.length - 1] = null;
710
+ if (this.limitExceeded) this.limitExceeded = false;
712
711
  }
713
712
  error(message, path$4, details) {
714
713
  let errors = this.stackErrors[this.stackErrors.length - 1];
@@ -717,11 +716,12 @@ var Validator = class {
717
716
  this.stackErrors[this.stackErrors.length - 1] = errors;
718
717
  } else errors = this.errors;
719
718
  const error = {
720
- path: path$4 || this.cachedPath,
719
+ path: path$4 || this.buildPath(),
721
720
  message
722
721
  };
723
722
  if (details?.length) error.details = details;
724
723
  errors.push(error);
724
+ if (errors.length >= this.opts.errorLimit) this.limitExceeded = true;
725
725
  }
726
726
  throw() {
727
727
  throw new ValidatorError(this.errors);
@@ -738,12 +738,11 @@ var Validator = class {
738
738
  * @throws {ValidatorError} When validation fails and `safe` is not `true`.
739
739
  */ validate(value, safe, context) {
740
740
  this.errors = [];
741
- this.stackErrors = [];
742
- this.stackPath = [""];
743
- this.cachedPath = "";
741
+ this.stackErrors.length = 0;
742
+ this.depth = 0;
743
+ this.limitExceeded = false;
744
744
  this.context = context;
745
745
  const passed = this.validateSafe(this.def, value);
746
- this.pop(!passed);
747
746
  this.context = undefined;
748
747
  if (!passed) {
749
748
  if (safe) return false;
@@ -752,18 +751,24 @@ var Validator = class {
752
751
  return true;
753
752
  }
754
753
  validateSafe(def, value) {
755
- if (this.isLimitExceeded()) return false;
756
- if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
757
- if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.cachedPath);
754
+ if (this.limitExceeded) return false;
755
+ if (this.hasReplace) {
756
+ let replaced = this.replaceCache.get(def);
757
+ if (replaced === undefined) {
758
+ replaced = this.opts.replace(def, this.buildPath());
759
+ this.replaceCache.set(def, replaced);
760
+ }
761
+ def = replaced;
762
+ }
758
763
  if (def.optional && (value === undefined || value === null)) return true;
759
- for (const plugin of this.opts.plugins) {
764
+ if (this.hasPlugins) for (const plugin of this.opts.plugins) {
760
765
  const result = plugin(this, def, value);
761
766
  if (result === false || result === true) return result;
762
767
  }
763
768
  return this.validateAnnotatedType(def, value);
764
769
  }
765
770
  get path() {
766
- return this.cachedPath;
771
+ return this.buildPath();
767
772
  }
768
773
  validateAnnotatedType(def, value) {
769
774
  switch (def.type.kind) {
@@ -780,21 +785,21 @@ var Validator = class {
780
785
  }
781
786
  }
782
787
  validateUnion(def, value) {
783
- let i = 0;
784
- const popped = [];
785
- for (const item of def.type.items) {
786
- this.push(`[${item.type.kind || item.type.designType}(${i})]`);
788
+ const items = def.type.items;
789
+ let details;
790
+ for (const item of items) {
791
+ this.stackErrors.push(null);
787
792
  if (this.validateSafe(item, value)) {
788
- this.pop(false);
793
+ this.stackErrors.pop();
789
794
  return true;
790
795
  }
791
- const errors = this.pop(false);
792
- if (errors) popped.push(...errors);
793
- i++;
796
+ const branchErrors = this.stackErrors.pop();
797
+ if (this.limitExceeded) this.limitExceeded = false;
798
+ if (branchErrors) if (details) for (const err of branchErrors) details.push(err);
799
+ else details = branchErrors;
794
800
  }
795
- this.clear();
796
- const expected = def.type.items.map((item, i$1) => `[${item.type.kind || item.type.designType}(${i$1})]`).join(", ");
797
- this.error(`Value does not match any of the allowed types: ${expected}`, undefined, popped);
801
+ const expected = items.map((item, i) => `[${item.type.kind || item.type.designType}(${i})]`).join(", ");
802
+ this.error(`Value does not match any of the allowed types: ${expected}`, undefined, details);
798
803
  return false;
799
804
  }
800
805
  validateIntersection(def, value) {
@@ -872,7 +877,7 @@ var Validator = class {
872
877
  if (!this.validateSafe(def.type.of, item)) {
873
878
  passed = false;
874
879
  this.pop(true);
875
- if (this.isLimitExceeded()) return false;
880
+ if (this.limitExceeded) return false;
876
881
  } else this.pop(false);
877
882
  i++;
878
883
  }
@@ -884,67 +889,72 @@ var Validator = class {
884
889
  return false;
885
890
  }
886
891
  let passed = true;
887
- const valueKeys = new Set(Object.keys(value));
888
- const typeKeys = new Set();
892
+ let keysToStrip;
889
893
  let skipList;
890
894
  if (this.opts.skipList) {
891
- const path$4 = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
895
+ const path$4 = this.depth > 0 ? `${this.buildPath()}.` : "";
892
896
  for (const item of this.opts.skipList) if (item.startsWith(path$4)) {
893
897
  const key = item.slice(path$4.length);
894
898
  if (!skipList) skipList = new Set();
895
899
  skipList.add(key);
896
- valueKeys.delete(key);
897
900
  }
898
901
  }
899
902
  let partialFunctionMatched = false;
900
- if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.cachedPath);
903
+ if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.buildPath());
901
904
  for (const [key, item] of def.type.props.entries()) {
902
905
  if (skipList && skipList.has(key) || isPhantomType(item)) continue;
903
- typeKeys.add(key);
904
906
  if (value[key] === undefined) {
905
- if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.stackPath.length <= 1) continue;
907
+ if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.depth === 0) continue;
906
908
  }
907
909
  this.push(key);
908
910
  if (this.validateSafe(item, value[key])) this.pop(false);
909
911
  else {
910
912
  passed = false;
911
913
  this.pop(true);
912
- if (this.isLimitExceeded()) return false;
913
- }
914
- }
915
- for (const key of valueKeys)
916
- /** matched patterns for unknown keys */ if (!typeKeys.has(key)) {
917
- const matched = [];
918
- for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
919
- pattern,
920
- def: propDef
921
- });
922
- if (matched.length > 0) {
923
- this.push(key);
924
- let keyPassed = false;
925
- for (const { def: propDef } of matched) {
926
- if (this.validateSafe(propDef, value[key])) {
927
- keyPassed = true;
928
- break;
914
+ if (this.limitExceeded) return false;
915
+ }
916
+ }
917
+ const hasPatterns = def.type.propsPatterns.length > 0;
918
+ if (this.opts.unknownProps !== "ignore" || hasPatterns) {
919
+ const keys = Object.keys(value);
920
+ for (const key of keys) {
921
+ if (skipList && skipList.has(key)) continue;
922
+ const knownProp = def.type.props.get(key);
923
+ if (knownProp && !isPhantomType(knownProp)) continue;
924
+ const matched = [];
925
+ for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
926
+ pattern,
927
+ def: propDef
928
+ });
929
+ if (matched.length > 0) {
930
+ this.push(key);
931
+ let keyPassed = false;
932
+ for (const { def: propDef } of matched) {
933
+ if (this.validateSafe(propDef, value[key])) {
934
+ keyPassed = true;
935
+ break;
936
+ }
937
+ this.clear();
929
938
  }
930
- this.clear();
931
- }
932
- if (!keyPassed) {
933
- this.validateSafe(matched[0].def, value[key]);
934
- this.pop(true);
935
- passed = false;
936
- if (this.isLimitExceeded()) return false;
937
- } else this.pop(false);
938
- } else if (this.opts.unknownProps !== "ignore") {
939
- if (this.opts.unknownProps === "error") {
939
+ if (!keyPassed) {
940
+ this.validateSafe(matched[0].def, value[key]);
941
+ this.pop(true);
942
+ passed = false;
943
+ if (this.limitExceeded) return false;
944
+ } else this.pop(false);
945
+ } else if (this.opts.unknownProps === "error") {
940
946
  this.push(key);
941
947
  this.error(`Unexpected property`);
942
948
  this.pop(true);
943
- if (this.isLimitExceeded()) return false;
949
+ if (this.limitExceeded) return false;
944
950
  passed = false;
945
- } else if (this.opts.unknownProps === "strip") delete value[key];
951
+ } else if (this.opts.unknownProps === "strip") {
952
+ if (!keysToStrip) keysToStrip = [];
953
+ keysToStrip.push(key);
954
+ }
946
955
  }
947
956
  }
957
+ if (passed && keysToStrip) for (const key of keysToStrip) delete value[key];
948
958
  return passed;
949
959
  }
950
960
  validatePrimitive(def, value) {
@@ -1008,6 +1018,7 @@ else {
1008
1018
  }
1009
1019
  }
1010
1020
  validateString(def, value) {
1021
+ if (def.metadata.size === 0) return true;
1011
1022
  const filled = def.metadata.get("meta.required");
1012
1023
  if (filled) {
1013
1024
  if (value.trim().length === 0) {
@@ -1051,6 +1062,7 @@ else {
1051
1062
  return true;
1052
1063
  }
1053
1064
  validateNumber(def, value) {
1065
+ if (def.metadata.size === 0) return true;
1054
1066
  const int = def.metadata.get("expect.int");
1055
1067
  if (int && value % 1 !== 0) {
1056
1068
  const message = typeof int === "object" && int.message ? int.message : `Expected integer, got ${value}`;
@@ -1078,6 +1090,7 @@ else {
1078
1090
  return true;
1079
1091
  }
1080
1092
  validateBoolean(def, value) {
1093
+ if (def.metadata.size === 0) return true;
1081
1094
  const filled = def.metadata.get("meta.required");
1082
1095
  if (filled) {
1083
1096
  if (value !== true) {
@@ -1091,16 +1104,21 @@ else {
1091
1104
  constructor(def, opts) {
1092
1105
  _define_property$4(this, "def", void 0);
1093
1106
  _define_property$4(this, "opts", void 0);
1107
+ _define_property$4(this, "hasPlugins", void 0);
1108
+ _define_property$4(this, "hasReplace", void 0);
1109
+ _define_property$4(this, "replaceCache", void 0);
1094
1110
  /** Validation errors collected during the last {@link validate} call. */ _define_property$4(this, "errors", void 0);
1095
1111
  _define_property$4(this, "stackErrors", void 0);
1096
- _define_property$4(this, "stackPath", void 0);
1097
- _define_property$4(this, "cachedPath", void 0);
1112
+ _define_property$4(this, "pathSegments", void 0);
1113
+ _define_property$4(this, "depth", void 0);
1114
+ _define_property$4(this, "limitExceeded", void 0);
1098
1115
  _define_property$4(this, "context", void 0);
1099
1116
  this.def = def;
1100
1117
  this.errors = [];
1101
1118
  this.stackErrors = [];
1102
- this.stackPath = [];
1103
- this.cachedPath = "";
1119
+ this.pathSegments = [];
1120
+ this.depth = 0;
1121
+ this.limitExceeded = false;
1104
1122
  this.opts = {
1105
1123
  partial: false,
1106
1124
  unknownProps: "error",
@@ -1108,6 +1126,9 @@ else {
1108
1126
  ...opts,
1109
1127
  plugins: opts?.plugins || []
1110
1128
  };
1129
+ this.hasPlugins = this.opts.plugins.length > 0;
1130
+ this.hasReplace = typeof this.opts.replace === "function";
1131
+ if (this.hasReplace) this.replaceCache = new WeakMap();
1111
1132
  }
1112
1133
  };
1113
1134
  var ValidatorError = class extends Error {
@@ -2426,7 +2447,7 @@ const BANNER = DYE_COLORS.cyan(`
2426
2447
  const PLAN_HEADER = [
2427
2448
  "",
2428
2449
  DYE_COLORS.bold("╔══════════════════════════════════════╗"),
2429
- DYE_COLORS.bold("║ Schema Sync Plan ║"),
2450
+ DYE_COLORS.bold("║ Schema Sync Plan ║"),
2430
2451
  DYE_COLORS.bold("╚══════════════════════════════════════╝"),
2431
2452
  ""
2432
2453
  ];
@@ -2515,7 +2536,7 @@ var DbSyncController = class {
2515
2536
  }
2516
2537
  this.printer.typeCount(dbTypes.length);
2517
2538
  this.printer.banner();
2518
- const { SchemaSync } = await this.importFromCwd("@atscripthttps://db.atscript.dev/sync", true);
2539
+ const { SchemaSync } = await this.importFromCwd("@atscript/db/sync", true);
2519
2540
  const sync = new SchemaSync(dbSpace);
2520
2541
  const plan = await sync.plan(dbTypes, {
2521
2542
  force,
package/dist/index.cjs CHANGED
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  }) : target, mod));
24
24
 
25
25
  //#endregion
26
- const require_json_schema = require('./json-schema-B55uxKNQ.cjs');
26
+ const require_json_schema = require('./json-schema-Bu4xgpQn.cjs');
27
27
  const path = __toESM(require("path"));
28
28
  const __atscript_core = __toESM(require("@atscript/core"));
29
29
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { buildJsonSchema, defineAnnotatedType } from "./json-schema-DaFltW4t.mjs";
1
+ import { buildJsonSchema, defineAnnotatedType } from "./json-schema-Bl8jkrCj.mjs";
2
2
  import path from "path";
3
3
  import { DEFAULT_FORMAT, flattenInterfaceNode, hasNavPropAnnotation, isArray, isConst, isGroup, isInterface, isPrimitive, isQueryLogical, isRef, isStructure } from "@atscript/core";
4
4
 
@@ -12,27 +12,26 @@ else obj[key] = value;
12
12
  }
13
13
  const regexCache = new Map();
14
14
  var Validator = class {
15
- isLimitExceeded() {
16
- if (this.stackErrors.length > 0) {
17
- const top = this.stackErrors[this.stackErrors.length - 1];
18
- return top !== null && top.length >= this.opts.errorLimit;
19
- }
20
- return this.errors.length >= this.opts.errorLimit;
15
+ buildPath() {
16
+ if (this.depth <= 0) return "";
17
+ let path = this.pathSegments[0];
18
+ for (let i = 1; i < this.depth; i++) path += `.${this.pathSegments[i]}`;
19
+ return path;
21
20
  }
22
21
  push(name) {
23
- this.stackPath.push(name);
22
+ this.pathSegments[this.depth] = name;
23
+ this.depth++;
24
24
  this.stackErrors.push(null);
25
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
26
25
  }
27
26
  pop(saveErrors) {
28
- this.stackPath.pop();
27
+ this.depth--;
29
28
  const popped = this.stackErrors.pop();
30
29
  if (saveErrors && popped !== null && popped !== undefined && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
31
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
32
30
  return popped;
33
31
  }
34
32
  clear() {
35
33
  this.stackErrors[this.stackErrors.length - 1] = null;
34
+ if (this.limitExceeded) this.limitExceeded = false;
36
35
  }
37
36
  error(message, path, details) {
38
37
  let errors = this.stackErrors[this.stackErrors.length - 1];
@@ -41,11 +40,12 @@ var Validator = class {
41
40
  this.stackErrors[this.stackErrors.length - 1] = errors;
42
41
  } else errors = this.errors;
43
42
  const error = {
44
- path: path || this.cachedPath,
43
+ path: path || this.buildPath(),
45
44
  message
46
45
  };
47
46
  if (details?.length) error.details = details;
48
47
  errors.push(error);
48
+ if (errors.length >= this.opts.errorLimit) this.limitExceeded = true;
49
49
  }
50
50
  throw() {
51
51
  throw new ValidatorError(this.errors);
@@ -62,12 +62,11 @@ var Validator = class {
62
62
  * @throws {ValidatorError} When validation fails and `safe` is not `true`.
63
63
  */ validate(value, safe, context) {
64
64
  this.errors = [];
65
- this.stackErrors = [];
66
- this.stackPath = [""];
67
- this.cachedPath = "";
65
+ this.stackErrors.length = 0;
66
+ this.depth = 0;
67
+ this.limitExceeded = false;
68
68
  this.context = context;
69
69
  const passed = this.validateSafe(this.def, value);
70
- this.pop(!passed);
71
70
  this.context = undefined;
72
71
  if (!passed) {
73
72
  if (safe) return false;
@@ -76,18 +75,24 @@ var Validator = class {
76
75
  return true;
77
76
  }
78
77
  validateSafe(def, value) {
79
- if (this.isLimitExceeded()) return false;
80
- if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
81
- if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.cachedPath);
78
+ if (this.limitExceeded) return false;
79
+ if (this.hasReplace) {
80
+ let replaced = this.replaceCache.get(def);
81
+ if (replaced === undefined) {
82
+ replaced = this.opts.replace(def, this.buildPath());
83
+ this.replaceCache.set(def, replaced);
84
+ }
85
+ def = replaced;
86
+ }
82
87
  if (def.optional && (value === undefined || value === null)) return true;
83
- for (const plugin of this.opts.plugins) {
88
+ if (this.hasPlugins) for (const plugin of this.opts.plugins) {
84
89
  const result = plugin(this, def, value);
85
90
  if (result === false || result === true) return result;
86
91
  }
87
92
  return this.validateAnnotatedType(def, value);
88
93
  }
89
94
  get path() {
90
- return this.cachedPath;
95
+ return this.buildPath();
91
96
  }
92
97
  validateAnnotatedType(def, value) {
93
98
  switch (def.type.kind) {
@@ -104,21 +109,21 @@ var Validator = class {
104
109
  }
105
110
  }
106
111
  validateUnion(def, value) {
107
- let i = 0;
108
- const popped = [];
109
- for (const item of def.type.items) {
110
- this.push(`[${item.type.kind || item.type.designType}(${i})]`);
112
+ const items = def.type.items;
113
+ let details;
114
+ for (const item of items) {
115
+ this.stackErrors.push(null);
111
116
  if (this.validateSafe(item, value)) {
112
- this.pop(false);
117
+ this.stackErrors.pop();
113
118
  return true;
114
119
  }
115
- const errors = this.pop(false);
116
- if (errors) popped.push(...errors);
117
- i++;
120
+ const branchErrors = this.stackErrors.pop();
121
+ if (this.limitExceeded) this.limitExceeded = false;
122
+ if (branchErrors) if (details) for (const err of branchErrors) details.push(err);
123
+ else details = branchErrors;
118
124
  }
119
- this.clear();
120
- const expected = def.type.items.map((item, i$1) => `[${item.type.kind || item.type.designType}(${i$1})]`).join(", ");
121
- this.error(`Value does not match any of the allowed types: ${expected}`, undefined, popped);
125
+ const expected = items.map((item, i) => `[${item.type.kind || item.type.designType}(${i})]`).join(", ");
126
+ this.error(`Value does not match any of the allowed types: ${expected}`, undefined, details);
122
127
  return false;
123
128
  }
124
129
  validateIntersection(def, value) {
@@ -196,7 +201,7 @@ var Validator = class {
196
201
  if (!this.validateSafe(def.type.of, item)) {
197
202
  passed = false;
198
203
  this.pop(true);
199
- if (this.isLimitExceeded()) return false;
204
+ if (this.limitExceeded) return false;
200
205
  } else this.pop(false);
201
206
  i++;
202
207
  }
@@ -208,67 +213,72 @@ var Validator = class {
208
213
  return false;
209
214
  }
210
215
  let passed = true;
211
- const valueKeys = new Set(Object.keys(value));
212
- const typeKeys = new Set();
216
+ let keysToStrip;
213
217
  let skipList;
214
218
  if (this.opts.skipList) {
215
- const path = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
219
+ const path = this.depth > 0 ? `${this.buildPath()}.` : "";
216
220
  for (const item of this.opts.skipList) if (item.startsWith(path)) {
217
221
  const key = item.slice(path.length);
218
222
  if (!skipList) skipList = new Set();
219
223
  skipList.add(key);
220
- valueKeys.delete(key);
221
224
  }
222
225
  }
223
226
  let partialFunctionMatched = false;
224
- if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.cachedPath);
227
+ if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.buildPath());
225
228
  for (const [key, item] of def.type.props.entries()) {
226
229
  if (skipList && skipList.has(key) || isPhantomType(item)) continue;
227
- typeKeys.add(key);
228
230
  if (value[key] === undefined) {
229
- if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.stackPath.length <= 1) continue;
231
+ if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.depth === 0) continue;
230
232
  }
231
233
  this.push(key);
232
234
  if (this.validateSafe(item, value[key])) this.pop(false);
233
235
  else {
234
236
  passed = false;
235
237
  this.pop(true);
236
- if (this.isLimitExceeded()) return false;
237
- }
238
- }
239
- for (const key of valueKeys)
240
- /** matched patterns for unknown keys */ if (!typeKeys.has(key)) {
241
- const matched = [];
242
- for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
243
- pattern,
244
- def: propDef
245
- });
246
- if (matched.length > 0) {
247
- this.push(key);
248
- let keyPassed = false;
249
- for (const { def: propDef } of matched) {
250
- if (this.validateSafe(propDef, value[key])) {
251
- keyPassed = true;
252
- break;
238
+ if (this.limitExceeded) return false;
239
+ }
240
+ }
241
+ const hasPatterns = def.type.propsPatterns.length > 0;
242
+ if (this.opts.unknownProps !== "ignore" || hasPatterns) {
243
+ const keys = Object.keys(value);
244
+ for (const key of keys) {
245
+ if (skipList && skipList.has(key)) continue;
246
+ const knownProp = def.type.props.get(key);
247
+ if (knownProp && !isPhantomType(knownProp)) continue;
248
+ const matched = [];
249
+ for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
250
+ pattern,
251
+ def: propDef
252
+ });
253
+ if (matched.length > 0) {
254
+ this.push(key);
255
+ let keyPassed = false;
256
+ for (const { def: propDef } of matched) {
257
+ if (this.validateSafe(propDef, value[key])) {
258
+ keyPassed = true;
259
+ break;
260
+ }
261
+ this.clear();
253
262
  }
254
- this.clear();
255
- }
256
- if (!keyPassed) {
257
- this.validateSafe(matched[0].def, value[key]);
258
- this.pop(true);
259
- passed = false;
260
- if (this.isLimitExceeded()) return false;
261
- } else this.pop(false);
262
- } else if (this.opts.unknownProps !== "ignore") {
263
- if (this.opts.unknownProps === "error") {
263
+ if (!keyPassed) {
264
+ this.validateSafe(matched[0].def, value[key]);
265
+ this.pop(true);
266
+ passed = false;
267
+ if (this.limitExceeded) return false;
268
+ } else this.pop(false);
269
+ } else if (this.opts.unknownProps === "error") {
264
270
  this.push(key);
265
271
  this.error(`Unexpected property`);
266
272
  this.pop(true);
267
- if (this.isLimitExceeded()) return false;
273
+ if (this.limitExceeded) return false;
268
274
  passed = false;
269
- } else if (this.opts.unknownProps === "strip") delete value[key];
275
+ } else if (this.opts.unknownProps === "strip") {
276
+ if (!keysToStrip) keysToStrip = [];
277
+ keysToStrip.push(key);
278
+ }
270
279
  }
271
280
  }
281
+ if (passed && keysToStrip) for (const key of keysToStrip) delete value[key];
272
282
  return passed;
273
283
  }
274
284
  validatePrimitive(def, value) {
@@ -332,6 +342,7 @@ else {
332
342
  }
333
343
  }
334
344
  validateString(def, value) {
345
+ if (def.metadata.size === 0) return true;
335
346
  const filled = def.metadata.get("meta.required");
336
347
  if (filled) {
337
348
  if (value.trim().length === 0) {
@@ -375,6 +386,7 @@ else {
375
386
  return true;
376
387
  }
377
388
  validateNumber(def, value) {
389
+ if (def.metadata.size === 0) return true;
378
390
  const int = def.metadata.get("expect.int");
379
391
  if (int && value % 1 !== 0) {
380
392
  const message = typeof int === "object" && int.message ? int.message : `Expected integer, got ${value}`;
@@ -402,6 +414,7 @@ else {
402
414
  return true;
403
415
  }
404
416
  validateBoolean(def, value) {
417
+ if (def.metadata.size === 0) return true;
405
418
  const filled = def.metadata.get("meta.required");
406
419
  if (filled) {
407
420
  if (value !== true) {
@@ -415,16 +428,21 @@ else {
415
428
  constructor(def, opts) {
416
429
  _define_property(this, "def", void 0);
417
430
  _define_property(this, "opts", void 0);
431
+ _define_property(this, "hasPlugins", void 0);
432
+ _define_property(this, "hasReplace", void 0);
433
+ _define_property(this, "replaceCache", void 0);
418
434
  /** Validation errors collected during the last {@link validate} call. */ _define_property(this, "errors", void 0);
419
435
  _define_property(this, "stackErrors", void 0);
420
- _define_property(this, "stackPath", void 0);
421
- _define_property(this, "cachedPath", void 0);
436
+ _define_property(this, "pathSegments", void 0);
437
+ _define_property(this, "depth", void 0);
438
+ _define_property(this, "limitExceeded", void 0);
422
439
  _define_property(this, "context", void 0);
423
440
  this.def = def;
424
441
  this.errors = [];
425
442
  this.stackErrors = [];
426
- this.stackPath = [];
427
- this.cachedPath = "";
443
+ this.pathSegments = [];
444
+ this.depth = 0;
445
+ this.limitExceeded = false;
428
446
  this.opts = {
429
447
  partial: false,
430
448
  unknownProps: "error",
@@ -432,6 +450,9 @@ else {
432
450
  ...opts,
433
451
  plugins: opts?.plugins || []
434
452
  };
453
+ this.hasPlugins = this.opts.plugins.length > 0;
454
+ this.hasReplace = typeof this.opts.replace === "function";
455
+ if (this.hasReplace) this.replaceCache = new WeakMap();
435
456
  }
436
457
  };
437
458
  var ValidatorError = class extends Error {
@@ -13,27 +13,26 @@ else obj[key] = value;
13
13
  }
14
14
  const regexCache = new Map();
15
15
  var Validator = class {
16
- isLimitExceeded() {
17
- if (this.stackErrors.length > 0) {
18
- const top = this.stackErrors[this.stackErrors.length - 1];
19
- return top !== null && top.length >= this.opts.errorLimit;
20
- }
21
- return this.errors.length >= this.opts.errorLimit;
16
+ buildPath() {
17
+ if (this.depth <= 0) return "";
18
+ let path = this.pathSegments[0];
19
+ for (let i = 1; i < this.depth; i++) path += `.${this.pathSegments[i]}`;
20
+ return path;
22
21
  }
23
22
  push(name) {
24
- this.stackPath.push(name);
23
+ this.pathSegments[this.depth] = name;
24
+ this.depth++;
25
25
  this.stackErrors.push(null);
26
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
27
26
  }
28
27
  pop(saveErrors) {
29
- this.stackPath.pop();
28
+ this.depth--;
30
29
  const popped = this.stackErrors.pop();
31
30
  if (saveErrors && popped !== null && popped !== undefined && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
32
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
33
31
  return popped;
34
32
  }
35
33
  clear() {
36
34
  this.stackErrors[this.stackErrors.length - 1] = null;
35
+ if (this.limitExceeded) this.limitExceeded = false;
37
36
  }
38
37
  error(message, path, details) {
39
38
  let errors = this.stackErrors[this.stackErrors.length - 1];
@@ -42,11 +41,12 @@ var Validator = class {
42
41
  this.stackErrors[this.stackErrors.length - 1] = errors;
43
42
  } else errors = this.errors;
44
43
  const error = {
45
- path: path || this.cachedPath,
44
+ path: path || this.buildPath(),
46
45
  message
47
46
  };
48
47
  if (details?.length) error.details = details;
49
48
  errors.push(error);
49
+ if (errors.length >= this.opts.errorLimit) this.limitExceeded = true;
50
50
  }
51
51
  throw() {
52
52
  throw new ValidatorError(this.errors);
@@ -63,12 +63,11 @@ var Validator = class {
63
63
  * @throws {ValidatorError} When validation fails and `safe` is not `true`.
64
64
  */ validate(value, safe, context) {
65
65
  this.errors = [];
66
- this.stackErrors = [];
67
- this.stackPath = [""];
68
- this.cachedPath = "";
66
+ this.stackErrors.length = 0;
67
+ this.depth = 0;
68
+ this.limitExceeded = false;
69
69
  this.context = context;
70
70
  const passed = this.validateSafe(this.def, value);
71
- this.pop(!passed);
72
71
  this.context = undefined;
73
72
  if (!passed) {
74
73
  if (safe) return false;
@@ -77,18 +76,24 @@ var Validator = class {
77
76
  return true;
78
77
  }
79
78
  validateSafe(def, value) {
80
- if (this.isLimitExceeded()) return false;
81
- if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
82
- if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.cachedPath);
79
+ if (this.limitExceeded) return false;
80
+ if (this.hasReplace) {
81
+ let replaced = this.replaceCache.get(def);
82
+ if (replaced === undefined) {
83
+ replaced = this.opts.replace(def, this.buildPath());
84
+ this.replaceCache.set(def, replaced);
85
+ }
86
+ def = replaced;
87
+ }
83
88
  if (def.optional && (value === undefined || value === null)) return true;
84
- for (const plugin of this.opts.plugins) {
89
+ if (this.hasPlugins) for (const plugin of this.opts.plugins) {
85
90
  const result = plugin(this, def, value);
86
91
  if (result === false || result === true) return result;
87
92
  }
88
93
  return this.validateAnnotatedType(def, value);
89
94
  }
90
95
  get path() {
91
- return this.cachedPath;
96
+ return this.buildPath();
92
97
  }
93
98
  validateAnnotatedType(def, value) {
94
99
  switch (def.type.kind) {
@@ -105,21 +110,21 @@ var Validator = class {
105
110
  }
106
111
  }
107
112
  validateUnion(def, value) {
108
- let i = 0;
109
- const popped = [];
110
- for (const item of def.type.items) {
111
- this.push(`[${item.type.kind || item.type.designType}(${i})]`);
113
+ const items = def.type.items;
114
+ let details;
115
+ for (const item of items) {
116
+ this.stackErrors.push(null);
112
117
  if (this.validateSafe(item, value)) {
113
- this.pop(false);
118
+ this.stackErrors.pop();
114
119
  return true;
115
120
  }
116
- const errors = this.pop(false);
117
- if (errors) popped.push(...errors);
118
- i++;
121
+ const branchErrors = this.stackErrors.pop();
122
+ if (this.limitExceeded) this.limitExceeded = false;
123
+ if (branchErrors) if (details) for (const err of branchErrors) details.push(err);
124
+ else details = branchErrors;
119
125
  }
120
- this.clear();
121
- const expected = def.type.items.map((item, i$1) => `[${item.type.kind || item.type.designType}(${i$1})]`).join(", ");
122
- this.error(`Value does not match any of the allowed types: ${expected}`, undefined, popped);
126
+ const expected = items.map((item, i) => `[${item.type.kind || item.type.designType}(${i})]`).join(", ");
127
+ this.error(`Value does not match any of the allowed types: ${expected}`, undefined, details);
123
128
  return false;
124
129
  }
125
130
  validateIntersection(def, value) {
@@ -197,7 +202,7 @@ var Validator = class {
197
202
  if (!this.validateSafe(def.type.of, item)) {
198
203
  passed = false;
199
204
  this.pop(true);
200
- if (this.isLimitExceeded()) return false;
205
+ if (this.limitExceeded) return false;
201
206
  } else this.pop(false);
202
207
  i++;
203
208
  }
@@ -209,67 +214,72 @@ var Validator = class {
209
214
  return false;
210
215
  }
211
216
  let passed = true;
212
- const valueKeys = new Set(Object.keys(value));
213
- const typeKeys = new Set();
217
+ let keysToStrip;
214
218
  let skipList;
215
219
  if (this.opts.skipList) {
216
- const path = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
220
+ const path = this.depth > 0 ? `${this.buildPath()}.` : "";
217
221
  for (const item of this.opts.skipList) if (item.startsWith(path)) {
218
222
  const key = item.slice(path.length);
219
223
  if (!skipList) skipList = new Set();
220
224
  skipList.add(key);
221
- valueKeys.delete(key);
222
225
  }
223
226
  }
224
227
  let partialFunctionMatched = false;
225
- if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.cachedPath);
228
+ if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.buildPath());
226
229
  for (const [key, item] of def.type.props.entries()) {
227
230
  if (skipList && skipList.has(key) || isPhantomType(item)) continue;
228
- typeKeys.add(key);
229
231
  if (value[key] === undefined) {
230
- if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.stackPath.length <= 1) continue;
232
+ if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.depth === 0) continue;
231
233
  }
232
234
  this.push(key);
233
235
  if (this.validateSafe(item, value[key])) this.pop(false);
234
236
  else {
235
237
  passed = false;
236
238
  this.pop(true);
237
- if (this.isLimitExceeded()) return false;
239
+ if (this.limitExceeded) return false;
238
240
  }
239
241
  }
240
- for (const key of valueKeys)
241
- /** matched patterns for unknown keys */ if (!typeKeys.has(key)) {
242
- const matched = [];
243
- for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
244
- pattern,
245
- def: propDef
246
- });
247
- if (matched.length > 0) {
248
- this.push(key);
249
- let keyPassed = false;
250
- for (const { def: propDef } of matched) {
251
- if (this.validateSafe(propDef, value[key])) {
252
- keyPassed = true;
253
- break;
242
+ const hasPatterns = def.type.propsPatterns.length > 0;
243
+ if (this.opts.unknownProps !== "ignore" || hasPatterns) {
244
+ const keys = Object.keys(value);
245
+ for (const key of keys) {
246
+ if (skipList && skipList.has(key)) continue;
247
+ const knownProp = def.type.props.get(key);
248
+ if (knownProp && !isPhantomType(knownProp)) continue;
249
+ const matched = [];
250
+ for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
251
+ pattern,
252
+ def: propDef
253
+ });
254
+ if (matched.length > 0) {
255
+ this.push(key);
256
+ let keyPassed = false;
257
+ for (const { def: propDef } of matched) {
258
+ if (this.validateSafe(propDef, value[key])) {
259
+ keyPassed = true;
260
+ break;
261
+ }
262
+ this.clear();
254
263
  }
255
- this.clear();
256
- }
257
- if (!keyPassed) {
258
- this.validateSafe(matched[0].def, value[key]);
259
- this.pop(true);
260
- passed = false;
261
- if (this.isLimitExceeded()) return false;
262
- } else this.pop(false);
263
- } else if (this.opts.unknownProps !== "ignore") {
264
- if (this.opts.unknownProps === "error") {
264
+ if (!keyPassed) {
265
+ this.validateSafe(matched[0].def, value[key]);
266
+ this.pop(true);
267
+ passed = false;
268
+ if (this.limitExceeded) return false;
269
+ } else this.pop(false);
270
+ } else if (this.opts.unknownProps === "error") {
265
271
  this.push(key);
266
272
  this.error(`Unexpected property`);
267
273
  this.pop(true);
268
- if (this.isLimitExceeded()) return false;
274
+ if (this.limitExceeded) return false;
269
275
  passed = false;
270
- } else if (this.opts.unknownProps === "strip") delete value[key];
276
+ } else if (this.opts.unknownProps === "strip") {
277
+ if (!keysToStrip) keysToStrip = [];
278
+ keysToStrip.push(key);
279
+ }
271
280
  }
272
281
  }
282
+ if (passed && keysToStrip) for (const key of keysToStrip) delete value[key];
273
283
  return passed;
274
284
  }
275
285
  validatePrimitive(def, value) {
@@ -333,6 +343,7 @@ else {
333
343
  }
334
344
  }
335
345
  validateString(def, value) {
346
+ if (def.metadata.size === 0) return true;
336
347
  const filled = def.metadata.get("meta.required");
337
348
  if (filled) {
338
349
  if (value.trim().length === 0) {
@@ -376,6 +387,7 @@ else {
376
387
  return true;
377
388
  }
378
389
  validateNumber(def, value) {
390
+ if (def.metadata.size === 0) return true;
379
391
  const int = def.metadata.get("expect.int");
380
392
  if (int && value % 1 !== 0) {
381
393
  const message = typeof int === "object" && int.message ? int.message : `Expected integer, got ${value}`;
@@ -403,6 +415,7 @@ else {
403
415
  return true;
404
416
  }
405
417
  validateBoolean(def, value) {
418
+ if (def.metadata.size === 0) return true;
406
419
  const filled = def.metadata.get("meta.required");
407
420
  if (filled) {
408
421
  if (value !== true) {
@@ -416,16 +429,21 @@ else {
416
429
  constructor(def, opts) {
417
430
  _define_property(this, "def", void 0);
418
431
  _define_property(this, "opts", void 0);
432
+ _define_property(this, "hasPlugins", void 0);
433
+ _define_property(this, "hasReplace", void 0);
434
+ _define_property(this, "replaceCache", void 0);
419
435
  /** Validation errors collected during the last {@link validate} call. */ _define_property(this, "errors", void 0);
420
436
  _define_property(this, "stackErrors", void 0);
421
- _define_property(this, "stackPath", void 0);
422
- _define_property(this, "cachedPath", void 0);
437
+ _define_property(this, "pathSegments", void 0);
438
+ _define_property(this, "depth", void 0);
439
+ _define_property(this, "limitExceeded", void 0);
423
440
  _define_property(this, "context", void 0);
424
441
  this.def = def;
425
442
  this.errors = [];
426
443
  this.stackErrors = [];
427
- this.stackPath = [];
428
- this.cachedPath = "";
444
+ this.pathSegments = [];
445
+ this.depth = 0;
446
+ this.limitExceeded = false;
429
447
  this.opts = {
430
448
  partial: false,
431
449
  unknownProps: "error",
@@ -433,6 +451,9 @@ else {
433
451
  ...opts,
434
452
  plugins: opts?.plugins || []
435
453
  };
454
+ this.hasPlugins = this.opts.plugins.length > 0;
455
+ this.hasReplace = typeof this.opts.replace === "function";
456
+ if (this.hasReplace) this.replaceCache = new WeakMap();
436
457
  }
437
458
  };
438
459
  var ValidatorError = class extends Error {
package/dist/utils.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const require_json_schema = require('./json-schema-B55uxKNQ.cjs');
2
+ const require_json_schema = require('./json-schema-Bu4xgpQn.cjs');
3
3
 
4
4
  //#region packages/typescript/src/runtime/default-value.ts
5
5
  /**
package/dist/utils.d.ts CHANGED
@@ -51,14 +51,18 @@ interface TValidatorPluginContext {
51
51
  declare class Validator<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>> {
52
52
  protected readonly def: T;
53
53
  protected opts: TValidatorOptions;
54
+ protected hasPlugins: boolean;
55
+ protected hasReplace: boolean;
56
+ private replaceCache?;
54
57
  constructor(def: T, opts?: Partial<TValidatorOptions>);
55
58
  /** Validation errors collected during the last {@link validate} call. */
56
59
  errors: TError[];
57
60
  protected stackErrors: Array<TError[] | null>;
58
- protected stackPath: string[];
59
- protected cachedPath: string;
61
+ protected pathSegments: string[];
62
+ protected depth: number;
63
+ protected limitExceeded: boolean;
60
64
  protected context: unknown;
61
- protected isLimitExceeded(): boolean;
65
+ protected buildPath(): string;
62
66
  protected push(name: string): void;
63
67
  protected pop(saveErrors: boolean): TError[] | null | undefined;
64
68
  protected clear(): void;
package/dist/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { Validator, ValidatorError, annotate, buildJsonSchema, cloneRefProp, createAnnotatedTypeNode, defineAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, mergeJsonSchemas } from "./json-schema-DaFltW4t.mjs";
1
+ import { Validator, ValidatorError, annotate, buildJsonSchema, cloneRefProp, createAnnotatedTypeNode, defineAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, mergeJsonSchemas } from "./json-schema-Bl8jkrCj.mjs";
2
2
 
3
3
  //#region packages/typescript/src/runtime/default-value.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/typescript",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "description": "Atscript: typescript-gen support.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -61,11 +61,12 @@
61
61
  "moost": "^0.6.2"
62
62
  },
63
63
  "devDependencies": {
64
- "vitest": "3.2.4"
64
+ "vitest": "3.2.4",
65
+ "@atscript/db": "^0.1.41"
65
66
  },
66
67
  "peerDependencies": {
67
- "@atscript/db": "^0.1.39",
68
- "@atscript/core": "^0.1.40"
68
+ "@atscript/db": "^0.1.41",
69
+ "@atscript/core": "^0.1.42"
69
70
  },
70
71
  "peerDependenciesMeta": {
71
72
  "@atscript/db": {