@afora/core 0.0.7 → 0.0.8
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/README.md +34 -6
- package/dist/core/application/start.d.ts +7 -0
- package/dist/core/application/types/application.interface.d.ts +36 -2
- package/dist/core/command/types/command.interface.d.ts +7 -0
- package/dist/core/entity/abstract-entity.d.ts +28 -1
- package/dist/core/entity/entity.d.ts +1 -1
- package/dist/core/entity/event.d.ts +13 -2
- package/dist/core/entity/exceptions.d.ts +8 -0
- package/dist/core/entity/types/entity.interface.d.ts +66 -2
- package/dist/core/entity/version.d.ts +13 -0
- package/dist/core/event-policy/event-policy.d.ts +25 -0
- package/dist/core/event-policy/exceptions.d.ts +11 -0
- package/dist/core/event-policy/publish.d.ts +17 -0
- package/dist/core/event-policy/publishers.d.ts +18 -0
- package/dist/core/event-policy/types/event-policy.interface.d.ts +72 -0
- package/dist/core/output/coerce.d.ts +9 -0
- package/dist/core/output/openapi-sink.d.ts +138 -38
- package/dist/core/output/status.d.ts +1 -1
- package/dist/core/parse/parse.d.ts +10 -0
- package/dist/core/parse/strip.d.ts +13 -0
- package/dist/core/repository/exceptions.d.ts +30 -0
- package/dist/core/repository/in-memory.d.ts +14 -1
- package/dist/core/repository/plan.d.ts +20 -0
- package/dist/core/repository/provider.d.ts +1 -1
- package/dist/core/repository/query.d.ts +9 -2
- package/dist/core/repository/repository.d.ts +40 -8
- package/dist/core/repository/state.d.ts +30 -2
- package/dist/core/repository/types/query.interface.d.ts +106 -5
- package/dist/core/repository/types/repository.interface.d.ts +106 -7
- package/dist/experimental.js +4 -4
- package/dist/{index-r78dsvtc.js → index-qxfkyd6k.js} +612 -612
- package/dist/{index-q6hggpzw.js → index-t5qwtyj5.js} +1807 -280
- package/dist/index.d.ts +22 -11
- package/dist/index.js +62 -14
- package/dist/std/blueprint-plugin.d.ts +6 -2
- package/dist/std/blueprint.d.ts +3 -0
- package/dist/std/entity.d.ts +2 -1
- package/dist/std/event-policies.d.ts +2 -0
- package/dist/std/properties/exceptions.d.ts +11 -0
- package/dist/std/properties/json.d.ts +54 -0
- package/dist/std/properties/time.d.ts +4 -0
- package/dist/std/use-cases/crud.d.ts +6 -4
- package/dist/std/use-cases/shared.d.ts +32 -4
- package/dist/std/use-cases/types.d.ts +100 -21
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +347 -2
- package/dist/testing/memory-publisher.d.ts +16 -0
- package/dist/testing/provider-contract.d.ts +14 -0
- package/package.json +3 -2
|
@@ -26,18 +26,18 @@ __export(exports_exceptions, {
|
|
|
26
26
|
UnknownRecordPlugin: () => UnknownRecordPlugin2
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
// src/core/
|
|
29
|
+
// src/core/property/exceptions.ts
|
|
30
30
|
var exports_exceptions2 = {};
|
|
31
31
|
__export(exports_exceptions2, {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
InvalidPropertyValue: () => InvalidPropertyValue2,
|
|
33
|
+
PropertyRequired: () => PropertyRequired2
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
// src/core/
|
|
36
|
+
// src/core/blueprint/exceptions.ts
|
|
37
37
|
var exports_exceptions3 = {};
|
|
38
38
|
__export(exports_exceptions3, {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
ReservedBlueprintKey: () => ReservedBlueprintKey2,
|
|
40
|
+
UndeclaredBlueprintProperty: () => UndeclaredBlueprintProperty2
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
// src/core/property/is-property.ts
|
|
@@ -989,307 +989,286 @@ class AbstractRecord2 {
|
|
|
989
989
|
}
|
|
990
990
|
}
|
|
991
991
|
|
|
992
|
-
// src/core/
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
992
|
+
// src/core/blueprint/blueprint.ts
|
|
993
|
+
import { Type as Type3 } from "typebox";
|
|
994
|
+
|
|
995
|
+
// src/core/property/property.ts
|
|
996
|
+
import { Type } from "typebox";
|
|
997
|
+
|
|
998
|
+
// src/core/symbols/state.ts
|
|
999
|
+
var State2 = Symbol("state");
|
|
1000
|
+
|
|
1001
|
+
// src/core/property/abstract-property.ts
|
|
1002
|
+
var parsingDefinitions = new WeakMap;
|
|
1003
|
+
function parsingDefinitionOf(Class) {
|
|
1004
|
+
let definition = parsingDefinitions.get(Class);
|
|
1005
|
+
if (!definition) {
|
|
1006
|
+
definition = Object.create(Class.prototype).createDefinition();
|
|
1007
|
+
parsingDefinitions.set(Class, definition);
|
|
1008
|
+
}
|
|
1009
|
+
return definition;
|
|
1002
1010
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1011
|
+
|
|
1012
|
+
class AbstractProperty2 {
|
|
1013
|
+
get [State2]() {
|
|
1014
|
+
return this.definition[State2];
|
|
1015
|
+
}
|
|
1016
|
+
definition;
|
|
1017
|
+
value;
|
|
1018
|
+
constructor(value) {
|
|
1019
|
+
this.definition = this.createDefinition();
|
|
1020
|
+
this.value = this.definition.make(value === Demo2 ? this.definition.type[Demo2] : value);
|
|
1021
|
+
}
|
|
1022
|
+
static demo() {
|
|
1023
|
+
return new this(Demo2);
|
|
1024
|
+
}
|
|
1025
|
+
static safeParse(value) {
|
|
1026
|
+
return parsingDefinitionOf(this).parse(value);
|
|
1027
|
+
}
|
|
1028
|
+
static with(options) {
|
|
1029
|
+
return refinePropertyOf(this, options);
|
|
1030
|
+
}
|
|
1031
|
+
static get "~standard"() {
|
|
1032
|
+
return standardOfClass(this);
|
|
1033
|
+
}
|
|
1013
1034
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1035
|
+
|
|
1036
|
+
// src/core/property/enums/property-states.ts
|
|
1037
|
+
var PropertyStates2;
|
|
1038
|
+
((PropertyStates) => {
|
|
1039
|
+
PropertyStates[PropertyStates["Declared"] = 0] = "Declared";
|
|
1040
|
+
PropertyStates[PropertyStates["PreHandling"] = 1] = "PreHandling";
|
|
1041
|
+
PropertyStates[PropertyStates["Handling"] = 2] = "Handling";
|
|
1042
|
+
PropertyStates[PropertyStates["AfterHandling"] = 3] = "AfterHandling";
|
|
1043
|
+
PropertyStates[PropertyStates["Done"] = 4] = "Done";
|
|
1044
|
+
})(PropertyStates2 ||= {});
|
|
1045
|
+
|
|
1046
|
+
// src/core/property/exceptions.ts
|
|
1047
|
+
var PropertyRequired2 = exceptionOf2({
|
|
1048
|
+
layer: "property" /* Property */,
|
|
1049
|
+
name: "PropertyRequired",
|
|
1050
|
+
message: (_, source) => `Property "${source}" is required.`
|
|
1051
|
+
});
|
|
1052
|
+
var InvalidPropertyValue2 = exceptionOf2({
|
|
1053
|
+
layer: "property" /* Property */,
|
|
1054
|
+
name: "InvalidPropertyValue",
|
|
1055
|
+
message: ({ errors }, source) => `Invalid value for property "${source}": ${errors.join("; ")}`
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
// src/core/property/define-property.ts
|
|
1059
|
+
var MISMATCH = Symbol("mismatch");
|
|
1060
|
+
function once(build) {
|
|
1061
|
+
let result;
|
|
1062
|
+
return () => {
|
|
1063
|
+
result ??= build();
|
|
1064
|
+
return result;
|
|
1065
|
+
};
|
|
1019
1066
|
}
|
|
1020
|
-
function
|
|
1021
|
-
|
|
1067
|
+
function segmentsOf(pointer) {
|
|
1068
|
+
if (pointer === "")
|
|
1069
|
+
return [];
|
|
1070
|
+
return pointer.slice(1).split("/").map((segment) => {
|
|
1071
|
+
const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
1072
|
+
return /^(0|[1-9]\d*)$/.test(key) ? Number(key) : key;
|
|
1073
|
+
});
|
|
1022
1074
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1075
|
+
|
|
1076
|
+
class AbstractDefineProperty2 {
|
|
1077
|
+
[State2] = 0 /* Declared */;
|
|
1078
|
+
make(value) {
|
|
1079
|
+
const attempt = this.attempt(value);
|
|
1080
|
+
if ("failure" in attempt)
|
|
1081
|
+
throw attempt.failure.exception();
|
|
1082
|
+
return attempt.value;
|
|
1027
1083
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1084
|
+
parse(value) {
|
|
1085
|
+
const attempt = this.attemptWithoutThrowing(value);
|
|
1086
|
+
if (!("failure" in attempt))
|
|
1087
|
+
return { value: attempt.value };
|
|
1088
|
+
const { exception, raised, issues } = attempt.failure;
|
|
1089
|
+
return {
|
|
1090
|
+
issues: issues.map((issue) => raised ? { ...issue, cause: exception() } : withLazyCause(issue, exception))
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
preHandle(value) {
|
|
1094
|
+
return value;
|
|
1095
|
+
}
|
|
1096
|
+
afterHandle(value) {
|
|
1097
|
+
return value;
|
|
1098
|
+
}
|
|
1099
|
+
handle(value) {
|
|
1100
|
+
return this.type.schema.match(value) ? value : MISMATCH;
|
|
1101
|
+
}
|
|
1102
|
+
attemptWithoutThrowing(value) {
|
|
1103
|
+
try {
|
|
1104
|
+
return this.attempt(value);
|
|
1105
|
+
} catch (error) {
|
|
1106
|
+
return {
|
|
1107
|
+
failure: this.raise(error instanceof Exception2 ? error : this.invalidValue(error))
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
attempt(value) {
|
|
1112
|
+
const { name, optional } = this.type;
|
|
1113
|
+
this[State2] = 0 /* Declared */;
|
|
1114
|
+
if (value === undefined) {
|
|
1115
|
+
if (!optional) {
|
|
1116
|
+
return {
|
|
1117
|
+
failure: {
|
|
1118
|
+
exception: () => new PropertyRequired2({ source: name }),
|
|
1119
|
+
raised: false,
|
|
1120
|
+
issues: [
|
|
1121
|
+
{
|
|
1122
|
+
message: "is required",
|
|
1123
|
+
path: [],
|
|
1124
|
+
code: "required",
|
|
1125
|
+
source: name
|
|
1126
|
+
}
|
|
1127
|
+
]
|
|
1049
1128
|
}
|
|
1050
|
-
}
|
|
1129
|
+
};
|
|
1051
1130
|
}
|
|
1052
|
-
|
|
1131
|
+
this[State2] = 4 /* Done */;
|
|
1132
|
+
return { value };
|
|
1053
1133
|
}
|
|
1134
|
+
if (!this.type.schema.matchShape(value)) {
|
|
1135
|
+
return { failure: this.mismatch(value) };
|
|
1136
|
+
}
|
|
1137
|
+
try {
|
|
1138
|
+
this[State2] = 1 /* PreHandling */;
|
|
1139
|
+
value = this.runHandler(() => this.preHandle(value));
|
|
1140
|
+
this[State2] = 2 /* Handling */;
|
|
1141
|
+
const handled = this.handle(value);
|
|
1142
|
+
if (handled === MISMATCH) {
|
|
1143
|
+
return { failure: this.mismatch(value) };
|
|
1144
|
+
}
|
|
1145
|
+
value = handled;
|
|
1146
|
+
this[State2] = 3 /* AfterHandling */;
|
|
1147
|
+
value = this.runHandler(() => this.afterHandle(value));
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
if (error instanceof Exception2)
|
|
1150
|
+
return { failure: this.raise(error) };
|
|
1151
|
+
throw error;
|
|
1152
|
+
}
|
|
1153
|
+
this[State2] = 4 /* Done */;
|
|
1154
|
+
return { value };
|
|
1054
1155
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
if (!isRecordClass2(Record)) {
|
|
1065
|
-
throw new InvalidRecordPlugin2({
|
|
1066
|
-
source: name,
|
|
1067
|
-
details: { reason: "it must be made from a class of `recordOf`" }
|
|
1068
|
-
});
|
|
1156
|
+
runHandler(handler) {
|
|
1157
|
+
try {
|
|
1158
|
+
return handler();
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
if (error instanceof Exception2)
|
|
1161
|
+
throw error;
|
|
1162
|
+
throw this.invalidValue(error);
|
|
1163
|
+
}
|
|
1069
1164
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
source: name,
|
|
1165
|
+
invalidValue(error) {
|
|
1166
|
+
return new InvalidPropertyValue2({
|
|
1167
|
+
source: this.type.name,
|
|
1073
1168
|
details: {
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1169
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
1170
|
+
},
|
|
1171
|
+
cause: error
|
|
1076
1172
|
});
|
|
1077
1173
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
const own = membersOf(Record, name);
|
|
1089
|
-
const plugin = Object.freeze({
|
|
1090
|
-
[Kind2]: "record-plugin",
|
|
1091
|
-
name,
|
|
1092
|
-
version,
|
|
1093
|
-
...description === undefined ? {} : { description },
|
|
1094
|
-
record: Record,
|
|
1095
|
-
keys,
|
|
1096
|
-
members: Object.freeze(Object.keys(own.descriptors)),
|
|
1097
|
-
options: declaration.options,
|
|
1098
|
-
requires,
|
|
1099
|
-
is: (value) => hasPlugin2(value, plugin),
|
|
1100
|
-
toJSON: () => descriptorOf(plugin)
|
|
1101
|
-
});
|
|
1102
|
-
internals.set(plugin, own);
|
|
1103
|
-
return plugin;
|
|
1104
|
-
}
|
|
1105
|
-
function descriptorOf(plugin) {
|
|
1106
|
-
return Object.freeze({
|
|
1107
|
-
kind: "record-plugin",
|
|
1108
|
-
name: plugin.name,
|
|
1109
|
-
version: plugin.version,
|
|
1110
|
-
...plugin.description === undefined ? {} : { description: plugin.description },
|
|
1111
|
-
keys: plugin.keys,
|
|
1112
|
-
sensitive: plugin.options.sensitive,
|
|
1113
|
-
unique: plugin.options.unique,
|
|
1114
|
-
change: plugin.options.change,
|
|
1115
|
-
members: plugin.members,
|
|
1116
|
-
requires: Object.freeze(plugin.requires.map(({ name, version }) => Object.freeze({ name, version })))
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
function applyPlugins(blueprint, plugins, name, reserved) {
|
|
1120
|
-
const flat = [];
|
|
1121
|
-
for (const plugin of plugins) {
|
|
1122
|
-
if (!isRecordPlugin2(plugin)) {
|
|
1123
|
-
throw new InvalidRecordPlugin2({
|
|
1124
|
-
source: name,
|
|
1125
|
-
details: {
|
|
1126
|
-
reason: "`options.plugins` takes plugins made by `recordPluginOf`"
|
|
1174
|
+
raise(exception) {
|
|
1175
|
+
return {
|
|
1176
|
+
exception: () => exception,
|
|
1177
|
+
raised: true,
|
|
1178
|
+
issues: [
|
|
1179
|
+
{
|
|
1180
|
+
message: exception.message,
|
|
1181
|
+
path: [],
|
|
1182
|
+
code: "invalid_value",
|
|
1183
|
+
source: this.type.name
|
|
1127
1184
|
}
|
|
1128
|
-
|
|
1129
|
-
}
|
|
1130
|
-
for (const applied of [...plugin.requires, plugin]) {
|
|
1131
|
-
if (flat.includes(applied))
|
|
1132
|
-
continue;
|
|
1133
|
-
if (flat.some((other) => other.name === applied.name)) {
|
|
1134
|
-
throw new RecordPluginConflict2({
|
|
1135
|
-
source: name,
|
|
1136
|
-
details: {
|
|
1137
|
-
plugin: applied.name,
|
|
1138
|
-
key: applied.name,
|
|
1139
|
-
owner: "another plugin"
|
|
1140
|
-
}
|
|
1141
|
-
});
|
|
1142
|
-
}
|
|
1143
|
-
flat.push(applied);
|
|
1144
|
-
}
|
|
1185
|
+
]
|
|
1186
|
+
};
|
|
1145
1187
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1188
|
+
mismatch(value) {
|
|
1189
|
+
const { name, schema } = this.type;
|
|
1190
|
+
const errors = schema.type.Errors(value);
|
|
1191
|
+
const issues = errors.map((error) => ({
|
|
1192
|
+
message: error.message,
|
|
1193
|
+
path: segmentsOf(error.instancePath),
|
|
1194
|
+
code: "invalid_value",
|
|
1195
|
+
source: name
|
|
1196
|
+
}));
|
|
1197
|
+
return {
|
|
1198
|
+
exception: once(() => new InvalidPropertyValue2({
|
|
1153
1199
|
source: name,
|
|
1154
|
-
details: {
|
|
1155
|
-
})
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
claim(plugin, member);
|
|
1167
|
-
descriptors[member] = own.descriptors[member];
|
|
1168
|
-
}
|
|
1169
|
-
if (own.hooks.onSet || own.hooks.onSetAll) {
|
|
1170
|
-
hooks.push(Object.freeze({
|
|
1171
|
-
plugin,
|
|
1172
|
-
keys: Object.freeze(Object.keys(plugin.record.blueprint.properties)),
|
|
1173
|
-
...own.hooks
|
|
1174
|
-
}));
|
|
1175
|
-
}
|
|
1200
|
+
details: { errors: errors.map(describeError) }
|
|
1201
|
+
})),
|
|
1202
|
+
raised: false,
|
|
1203
|
+
issues: issues.length > 0 ? issues : [
|
|
1204
|
+
{
|
|
1205
|
+
message: "is invalid",
|
|
1206
|
+
path: [],
|
|
1207
|
+
code: "invalid_value",
|
|
1208
|
+
source: name
|
|
1209
|
+
}
|
|
1210
|
+
]
|
|
1211
|
+
};
|
|
1176
1212
|
}
|
|
1177
|
-
return {
|
|
1178
|
-
blueprint: flat.length === 0 ? blueprint : blueprint.join(...flat.map((plugin) => plugin.record.blueprint)),
|
|
1179
|
-
plugins: Object.freeze(flat),
|
|
1180
|
-
sensitive: flat.flatMap((plugin) => plugin.options.sensitive),
|
|
1181
|
-
unique: flat.flatMap((plugin) => plugin.options.unique),
|
|
1182
|
-
change: flat.flatMap((plugin) => plugin.options.change),
|
|
1183
|
-
descriptors,
|
|
1184
|
-
hooks: Object.freeze(hooks)
|
|
1185
|
-
};
|
|
1186
1213
|
}
|
|
1187
1214
|
|
|
1188
|
-
// src/core/
|
|
1189
|
-
function
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
const keys = Object.keys(blueprint.properties);
|
|
1214
|
-
const change = keys.filter((key) => declaredChange.includes(key) || applied.change.includes(key));
|
|
1215
|
-
for (const key of [...sensitive, ...unique, ...declaredChange]) {
|
|
1216
|
-
if (!keys.includes(key)) {
|
|
1217
|
-
throw new UndeclaredRecordProperty2({
|
|
1218
|
-
source: name,
|
|
1219
|
-
details: { key }
|
|
1220
|
-
});
|
|
1215
|
+
// src/core/property/property.ts
|
|
1216
|
+
function propertyOf2({
|
|
1217
|
+
name,
|
|
1218
|
+
schema,
|
|
1219
|
+
optional,
|
|
1220
|
+
sensitive = false,
|
|
1221
|
+
unique = false,
|
|
1222
|
+
default: _default,
|
|
1223
|
+
preHandle: onPreHandle,
|
|
1224
|
+
afterHandle: onAfterHandle
|
|
1225
|
+
}) {
|
|
1226
|
+
const valueSchema = optional ? Type.Optional(schema) : schema;
|
|
1227
|
+
const SchemaConstructor = schemaOf2(name, valueSchema);
|
|
1228
|
+
const type = {
|
|
1229
|
+
[Demo2]: _default,
|
|
1230
|
+
name,
|
|
1231
|
+
schema: new SchemaConstructor,
|
|
1232
|
+
optional: optional ?? false,
|
|
1233
|
+
sensitive,
|
|
1234
|
+
unique
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
class DefineProperty extends AbstractDefineProperty2 {
|
|
1238
|
+
get type() {
|
|
1239
|
+
return type;
|
|
1221
1240
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
for (const member of Object.keys(applied.descriptors)) {
|
|
1225
|
-
if (methods.includes(member)) {
|
|
1226
|
-
const plugin = applied.plugins.find((plugin) => plugin.members.includes(member));
|
|
1227
|
-
throw new RecordPluginConflict2({
|
|
1228
|
-
source: name,
|
|
1229
|
-
details: {
|
|
1230
|
-
plugin: plugin.name,
|
|
1231
|
-
key: member,
|
|
1232
|
-
owner: `record "${name}" (the \`change\` namespace)`
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1241
|
+
preHandle(value) {
|
|
1242
|
+
return onPreHandle ? onPreHandle(value) : value;
|
|
1235
1243
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (RESERVED_RECORD_KEYS2.includes(key) || reserved.includes(key) || methods.includes(key)) {
|
|
1239
|
-
throw new ReservedRecordKey2({ source: name, details: { key } });
|
|
1244
|
+
afterHandle(value) {
|
|
1245
|
+
return onAfterHandle ? onAfterHandle(value) : value;
|
|
1240
1246
|
}
|
|
1241
1247
|
}
|
|
1242
|
-
const options = Object.freeze({
|
|
1243
|
-
sensitive: Object.freeze(keys.filter((key) => sensitive.includes(key) || isMarked(blueprint.properties[key], "sensitive", { lists: true }))),
|
|
1244
|
-
unique: Object.freeze(keys.filter((key) => unique.includes(key) || isMarked(blueprint.properties[key], "unique"))),
|
|
1245
|
-
change: Object.freeze([...change])
|
|
1246
|
-
});
|
|
1247
1248
|
|
|
1248
|
-
class
|
|
1249
|
-
static
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
static [RecordPlugins] = applied.plugins;
|
|
1254
|
-
static [RecordPluginHooks] = applied.hooks;
|
|
1255
|
-
}
|
|
1256
|
-
if (declaredName !== undefined) {
|
|
1257
|
-
declareRecordName(DeclaredRecord, declaredName);
|
|
1258
|
-
}
|
|
1259
|
-
Object.defineProperty(DeclaredRecord, "recordName", {
|
|
1260
|
-
get() {
|
|
1261
|
-
return declaredName ?? this.name;
|
|
1262
|
-
},
|
|
1263
|
-
configurable: true
|
|
1264
|
-
});
|
|
1265
|
-
exposeRecordKeys(DeclaredRecord.prototype, keys);
|
|
1266
|
-
for (const [member, descriptor] of Object.entries(applied.descriptors)) {
|
|
1267
|
-
Object.defineProperty(DeclaredRecord.prototype, member, descriptor);
|
|
1268
|
-
}
|
|
1269
|
-
if (change.length > 0) {
|
|
1270
|
-
Object.defineProperty(DeclaredRecord.prototype, CHANGE_MEMBER, {
|
|
1271
|
-
get() {
|
|
1272
|
-
let namespace = changeNamespaces.get(this);
|
|
1273
|
-
if (namespace === undefined) {
|
|
1274
|
-
namespace = Object.freeze(Object.fromEntries(change.map((key) => [
|
|
1275
|
-
key,
|
|
1276
|
-
(value) => this.set(key, value)
|
|
1277
|
-
])));
|
|
1278
|
-
changeNamespaces.set(this, namespace);
|
|
1279
|
-
}
|
|
1280
|
-
return namespace;
|
|
1281
|
-
},
|
|
1282
|
-
configurable: true
|
|
1283
|
-
});
|
|
1249
|
+
class Property extends AbstractProperty2 {
|
|
1250
|
+
static type = type;
|
|
1251
|
+
createDefinition() {
|
|
1252
|
+
return new DefineProperty;
|
|
1253
|
+
}
|
|
1284
1254
|
}
|
|
1285
|
-
|
|
1286
|
-
return DeclaredRecord;
|
|
1255
|
+
return Property;
|
|
1287
1256
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1257
|
+
|
|
1258
|
+
// src/core/blueprint/exceptions.ts
|
|
1259
|
+
var ReservedBlueprintKey2 = exceptionOf2({
|
|
1260
|
+
layer: "blueprint" /* Blueprint */,
|
|
1261
|
+
name: "ReservedBlueprintKey",
|
|
1262
|
+
message: ({ key }) => `"${key}" is reserved and cannot be a plugin property.`
|
|
1263
|
+
});
|
|
1264
|
+
var UndeclaredBlueprintProperty2 = exceptionOf2({
|
|
1265
|
+
layer: "blueprint" /* Blueprint */,
|
|
1266
|
+
name: "UndeclaredBlueprintProperty",
|
|
1267
|
+
message: ({ key }) => `Property "${key}" of the blueprint is not declared.`
|
|
1268
|
+
});
|
|
1290
1269
|
|
|
1291
1270
|
// src/core/blueprint/optional.ts
|
|
1292
|
-
import { Type } from "typebox";
|
|
1271
|
+
import { Type as Type2 } from "typebox";
|
|
1293
1272
|
var cache2 = new WeakMap;
|
|
1294
1273
|
function optionalOf2(given) {
|
|
1295
1274
|
const field = fieldOf(given);
|
|
@@ -1330,7 +1309,7 @@ function optionalOf2(given) {
|
|
|
1330
1309
|
if (Property.type.optional)
|
|
1331
1310
|
return Property;
|
|
1332
1311
|
const base = Property.type;
|
|
1333
|
-
const SchemaConstructor = schemaOf2(base.name,
|
|
1312
|
+
const SchemaConstructor = schemaOf2(base.name, Type2.Optional(base.schema.type.Type()));
|
|
1334
1313
|
const type = {
|
|
1335
1314
|
...base,
|
|
1336
1315
|
schema: new SchemaConstructor,
|
|
@@ -1342,380 +1321,401 @@ function optionalOf2(given) {
|
|
|
1342
1321
|
return Optional;
|
|
1343
1322
|
}
|
|
1344
1323
|
|
|
1345
|
-
// src/core/blueprint/exceptions.ts
|
|
1346
|
-
var ReservedBlueprintKey2 = exceptionOf2({
|
|
1347
|
-
layer: "blueprint" /* Blueprint */,
|
|
1348
|
-
name: "ReservedBlueprintKey",
|
|
1349
|
-
message: ({ key }) => `"${key}" is reserved and cannot be a plugin property.`
|
|
1350
|
-
});
|
|
1351
|
-
var UndeclaredBlueprintProperty2 = exceptionOf2({
|
|
1352
|
-
layer: "blueprint" /* Blueprint */,
|
|
1353
|
-
name: "UndeclaredBlueprintProperty",
|
|
1354
|
-
message: ({ key }) => `Property "${key}" of the blueprint is not declared.`
|
|
1355
|
-
});
|
|
1356
|
-
|
|
1357
|
-
// src/core/property/exceptions.ts
|
|
1358
|
-
var PropertyRequired2 = exceptionOf2({
|
|
1359
|
-
layer: "property" /* Property */,
|
|
1360
|
-
name: "PropertyRequired",
|
|
1361
|
-
message: (_, source) => `Property "${source}" is required.`
|
|
1362
|
-
});
|
|
1363
|
-
var InvalidPropertyValue2 = exceptionOf2({
|
|
1364
|
-
layer: "property" /* Property */,
|
|
1365
|
-
name: "InvalidPropertyValue",
|
|
1366
|
-
message: ({ errors }, source) => `Invalid value for property "${source}": ${errors.join("; ")}`
|
|
1367
|
-
});
|
|
1368
|
-
|
|
1369
1324
|
// src/core/blueprint/blueprint.ts
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
var parsingDefinitions = new WeakMap;
|
|
1380
|
-
function parsingDefinitionOf(Class) {
|
|
1381
|
-
let definition = parsingDefinitions.get(Class);
|
|
1382
|
-
if (!definition) {
|
|
1383
|
-
definition = Object.create(Class.prototype).createDefinition();
|
|
1384
|
-
parsingDefinitions.set(Class, definition);
|
|
1385
|
-
}
|
|
1386
|
-
return definition;
|
|
1325
|
+
function blueprintBuilderOf2(...base) {
|
|
1326
|
+
return (sourcesOrDefine, maybeDefine) => {
|
|
1327
|
+
const [sources, define] = typeof sourcesOrDefine === "function" ? [[], sourcesOrDefine] : [
|
|
1328
|
+
sourcesOrDefine,
|
|
1329
|
+
maybeDefine
|
|
1330
|
+
];
|
|
1331
|
+
const all = [...base, ...sources];
|
|
1332
|
+
return create(all.flatMap((source) => isBlueprint2(source) ? source.plugins : [source]), { ...define(contextOf(all)) });
|
|
1333
|
+
};
|
|
1387
1334
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
get [State2]() {
|
|
1391
|
-
return this.definition[State2];
|
|
1392
|
-
}
|
|
1393
|
-
definition;
|
|
1394
|
-
value;
|
|
1395
|
-
constructor(value) {
|
|
1396
|
-
this.definition = this.createDefinition();
|
|
1397
|
-
this.value = this.definition.make(value === Demo2 ? this.definition.type[Demo2] : value);
|
|
1398
|
-
}
|
|
1399
|
-
static demo() {
|
|
1400
|
-
return new this(Demo2);
|
|
1401
|
-
}
|
|
1402
|
-
static safeParse(value) {
|
|
1403
|
-
return parsingDefinitionOf(this).parse(value);
|
|
1404
|
-
}
|
|
1405
|
-
static with(options) {
|
|
1406
|
-
return refinePropertyOf(this, options);
|
|
1407
|
-
}
|
|
1408
|
-
static get "~standard"() {
|
|
1409
|
-
return standardOfClass(this);
|
|
1410
|
-
}
|
|
1335
|
+
function blueprintFromProperties(plugins, properties) {
|
|
1336
|
+
return create(plugins, { ...properties });
|
|
1411
1337
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
(
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
return () => {
|
|
1428
|
-
result ??= build();
|
|
1429
|
-
return result;
|
|
1338
|
+
function create(plugins, properties) {
|
|
1339
|
+
const shape = {};
|
|
1340
|
+
for (const [key, field] of Object.entries(properties)) {
|
|
1341
|
+
properties[key] = fieldOf(field);
|
|
1342
|
+
shape[key] = schemaOfField(key, properties[key]);
|
|
1343
|
+
}
|
|
1344
|
+
const SchemaConstructor = schemaOf2("blueprint", Type3.Object(shape));
|
|
1345
|
+
const blueprint = {
|
|
1346
|
+
[Kind2]: "blueprint",
|
|
1347
|
+
plugins: Object.freeze([...new Set(plugins)]),
|
|
1348
|
+
properties: Object.freeze(properties),
|
|
1349
|
+
schema: new SchemaConstructor,
|
|
1350
|
+
optional: false,
|
|
1351
|
+
safeParse: (value) => parseCollection(properties, value, [], "blueprint"),
|
|
1352
|
+
join: (...others) => create([blueprint, ...others].flatMap((source) => source.plugins), Object.assign({}, ...[blueprint, ...others].map((source) => source.properties)))
|
|
1430
1353
|
};
|
|
1354
|
+
return Object.freeze(withStandard(blueprint, (value) => blueprint.safeParse(value)));
|
|
1431
1355
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
make(value) {
|
|
1444
|
-
const attempt = this.attempt(value);
|
|
1445
|
-
if ("failure" in attempt)
|
|
1446
|
-
throw attempt.failure.exception();
|
|
1447
|
-
return attempt.value;
|
|
1356
|
+
var HELPERS = { listOf: listOf2, optionalOf: optionalOf2, propertyOf: propertyOf2 };
|
|
1357
|
+
var RESERVED_KEYS = ["optional", "list", ...Object.keys(HELPERS)];
|
|
1358
|
+
function contextOf(sources) {
|
|
1359
|
+
for (const key of RESERVED_KEYS) {
|
|
1360
|
+
const reserving = sources.find((source) => Object.hasOwn(source.properties, key));
|
|
1361
|
+
if (reserving) {
|
|
1362
|
+
throw new ReservedBlueprintKey2({
|
|
1363
|
+
source: isBlueprint2(reserving) ? "blueprint" : reserving.name,
|
|
1364
|
+
details: { key }
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1448
1367
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
if (
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1368
|
+
const factories = Object.assign({}, ...sources.map((source) => isBlueprint2(source) ? {} : source.factories ?? {}));
|
|
1369
|
+
for (const key of RESERVED_KEYS) {
|
|
1370
|
+
if (Object.hasOwn(factories, key)) {
|
|
1371
|
+
const reserving = sources.find((source) => !isBlueprint2(source) && Object.hasOwn(source.factories ?? {}, key));
|
|
1372
|
+
throw new ReservedBlueprintKey2({
|
|
1373
|
+
source: reserving.name,
|
|
1374
|
+
details: { key }
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const available = Object.assign({}, ...sources.map((source) => source.properties));
|
|
1379
|
+
for (const key of Object.keys(factories))
|
|
1380
|
+
delete available[key];
|
|
1381
|
+
const mirror = (fields, map) => Object.fromEntries(Object.entries(fields).map(([key, field]) => [key, map(field)]));
|
|
1382
|
+
const list = mirror(available, (field) => listOf2(field));
|
|
1383
|
+
const callable = (field) => isProperty2(field) ? callableOf(field) : field;
|
|
1384
|
+
return Object.freeze({
|
|
1385
|
+
...mirror(available, callable),
|
|
1386
|
+
...factories,
|
|
1387
|
+
...HELPERS,
|
|
1388
|
+
optional: Object.freeze(mirror(available, (field) => callable(optionalOf2(field)))),
|
|
1389
|
+
list: Object.freeze({
|
|
1390
|
+
...list,
|
|
1391
|
+
optional: Object.freeze(mirror(list, optionalOf2))
|
|
1392
|
+
})
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
function schemaOfField(key, field) {
|
|
1396
|
+
if (isBlueprintList2(field)) {
|
|
1397
|
+
const { item, minItems, maxItems } = field;
|
|
1398
|
+
const schema = Type3.Array(schemaOfField(key, item), {
|
|
1399
|
+
...minItems === undefined ? {} : { minItems },
|
|
1400
|
+
...maxItems === undefined ? {} : { maxItems }
|
|
1401
|
+
});
|
|
1402
|
+
return field.optional ? Type3.Optional(schema) : schema;
|
|
1457
1403
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1404
|
+
if (isBlueprint2(field)) {
|
|
1405
|
+
const schema = field.schema.type.Type();
|
|
1406
|
+
return field.optional ? Type3.Optional(schema) : schema;
|
|
1460
1407
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1408
|
+
const record = recordFieldOf2(field);
|
|
1409
|
+
if (record) {
|
|
1410
|
+
const schema = record.record.blueprint.schema.type.Type();
|
|
1411
|
+
return record.optional ? Type3.Optional(schema) : schema;
|
|
1463
1412
|
}
|
|
1464
|
-
|
|
1465
|
-
return
|
|
1413
|
+
if (isProperty2(field)) {
|
|
1414
|
+
return field.type.schema.type.Type();
|
|
1466
1415
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1416
|
+
throw new UndeclaredBlueprintProperty2({
|
|
1417
|
+
source: "blueprint",
|
|
1418
|
+
details: { key }
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// src/core/record/plugin.ts
|
|
1423
|
+
var RecordPlugins = Symbol("recordPlugins");
|
|
1424
|
+
var IdentifiedRecord = Symbol("identifiedRecord");
|
|
1425
|
+
var SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
1426
|
+
function isVersion(version) {
|
|
1427
|
+
return typeof version === "string" && SEMVER.test(version);
|
|
1428
|
+
}
|
|
1429
|
+
function versionParts(version) {
|
|
1430
|
+
const [, major, minor, patch] = SEMVER.exec(version);
|
|
1431
|
+
return [Number(major), Number(minor), Number(patch)];
|
|
1432
|
+
}
|
|
1433
|
+
function satisfies(available, requested) {
|
|
1434
|
+
const [major, minor, patch] = versionParts(available);
|
|
1435
|
+
const [wantedMajor, wantedMinor, wantedPatch] = versionParts(requested);
|
|
1436
|
+
if (major !== wantedMajor)
|
|
1437
|
+
return false;
|
|
1438
|
+
if (major === 0 && minor !== wantedMinor)
|
|
1439
|
+
return false;
|
|
1440
|
+
if (minor !== wantedMinor)
|
|
1441
|
+
return minor > wantedMinor;
|
|
1442
|
+
return patch >= wantedPatch;
|
|
1443
|
+
}
|
|
1444
|
+
var HOOKS = ["onSet", "onSetAll"];
|
|
1445
|
+
var internals = new WeakMap;
|
|
1446
|
+
function pluginsOf2(value) {
|
|
1447
|
+
const Class = typeof value === "function" ? value : typeof value === "object" && value !== null ? value.constructor : undefined;
|
|
1448
|
+
return Class?.[RecordPlugins] ?? [];
|
|
1449
|
+
}
|
|
1450
|
+
function isRecordPlugin2(value) {
|
|
1451
|
+
return typeof value === "object" && value !== null && value[Kind2] === "record-plugin";
|
|
1452
|
+
}
|
|
1453
|
+
function hasPlugin2(value, plugin) {
|
|
1454
|
+
const plugins = pluginsOf2(value);
|
|
1455
|
+
if (typeof plugin === "string") {
|
|
1456
|
+
return plugins.some((applied) => applied.name === plugin);
|
|
1475
1457
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
}
|
|
1492
|
-
]
|
|
1493
|
-
}
|
|
1494
|
-
};
|
|
1458
|
+
if (plugins.includes(plugin))
|
|
1459
|
+
return true;
|
|
1460
|
+
return typeof value === "function" ? value === plugin.record || value.prototype instanceof plugin.record : value instanceof plugin.record;
|
|
1461
|
+
}
|
|
1462
|
+
function membersOf(Record, name) {
|
|
1463
|
+
const descriptors = {};
|
|
1464
|
+
const hooks = {};
|
|
1465
|
+
for (let prototype = Record.prototype;prototype !== null && !Object.hasOwn(prototype.constructor, "blueprint"); prototype = Object.getPrototypeOf(prototype)) {
|
|
1466
|
+
for (const member of Object.getOwnPropertyNames(prototype)) {
|
|
1467
|
+
if (member === "constructor")
|
|
1468
|
+
continue;
|
|
1469
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, member);
|
|
1470
|
+
if (HOOKS.includes(member)) {
|
|
1471
|
+
hooks[member] ??= descriptor.value;
|
|
1472
|
+
continue;
|
|
1495
1473
|
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
this[State2] = 1 /* PreHandling */;
|
|
1504
|
-
value = this.runHandler(() => this.preHandle(value));
|
|
1505
|
-
this[State2] = 2 /* Handling */;
|
|
1506
|
-
const handled = this.handle(value);
|
|
1507
|
-
if (handled === MISMATCH) {
|
|
1508
|
-
return { failure: this.mismatch(value) };
|
|
1474
|
+
if (RESERVED_RECORD_KEYS2.includes(member)) {
|
|
1475
|
+
throw new InvalidRecordPlugin2({
|
|
1476
|
+
source: name,
|
|
1477
|
+
details: {
|
|
1478
|
+
reason: `"${member}" is a member of every record and cannot be replaced`
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1509
1481
|
}
|
|
1510
|
-
|
|
1511
|
-
this[State2] = 3 /* AfterHandling */;
|
|
1512
|
-
value = this.runHandler(() => this.afterHandle(value));
|
|
1513
|
-
} catch (error) {
|
|
1514
|
-
if (error instanceof Exception2)
|
|
1515
|
-
return { failure: this.raise(error) };
|
|
1516
|
-
throw error;
|
|
1482
|
+
descriptors[member] ??= descriptor;
|
|
1517
1483
|
}
|
|
1518
|
-
this[State2] = 4 /* Done */;
|
|
1519
|
-
return { value };
|
|
1520
1484
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
}
|
|
1485
|
+
return { descriptors: Object.freeze(descriptors), hooks };
|
|
1486
|
+
}
|
|
1487
|
+
function recordPluginOf2(name, Record, { version = "1.0.0", description } = {}) {
|
|
1488
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
1489
|
+
throw new InvalidRecordPlugin2({
|
|
1490
|
+
source: String(name),
|
|
1491
|
+
details: { reason: "its name must be a non-empty string" }
|
|
1492
|
+
});
|
|
1529
1493
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
source:
|
|
1533
|
-
details: {
|
|
1534
|
-
errors: [error instanceof Error ? error.message : String(error)]
|
|
1535
|
-
},
|
|
1536
|
-
cause: error
|
|
1494
|
+
if (!isRecordClass2(Record)) {
|
|
1495
|
+
throw new InvalidRecordPlugin2({
|
|
1496
|
+
source: name,
|
|
1497
|
+
details: { reason: "it must be made from a class of `recordOf`" }
|
|
1537
1498
|
});
|
|
1538
1499
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
path: [],
|
|
1547
|
-
code: "invalid_value",
|
|
1548
|
-
source: this.type.name
|
|
1549
|
-
}
|
|
1550
|
-
]
|
|
1551
|
-
};
|
|
1500
|
+
if (Record[IdentifiedRecord]) {
|
|
1501
|
+
throw new InvalidRecordPlugin2({
|
|
1502
|
+
source: name,
|
|
1503
|
+
details: {
|
|
1504
|
+
reason: "it must be made from a record, not an entity: plugins have no identity"
|
|
1505
|
+
}
|
|
1506
|
+
});
|
|
1552
1507
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
path: segmentsOf(error.instancePath),
|
|
1559
|
-
code: "invalid_value",
|
|
1560
|
-
source: name
|
|
1561
|
-
}));
|
|
1562
|
-
return {
|
|
1563
|
-
exception: once(() => new InvalidPropertyValue2({
|
|
1564
|
-
source: name,
|
|
1565
|
-
details: { errors: errors.map(describeError) }
|
|
1566
|
-
})),
|
|
1567
|
-
raised: false,
|
|
1568
|
-
issues: issues.length > 0 ? issues : [
|
|
1569
|
-
{
|
|
1570
|
-
message: "is invalid",
|
|
1571
|
-
path: [],
|
|
1572
|
-
code: "invalid_value",
|
|
1573
|
-
source: name
|
|
1574
|
-
}
|
|
1575
|
-
]
|
|
1576
|
-
};
|
|
1508
|
+
if (!isVersion(version)) {
|
|
1509
|
+
throw new InvalidRecordPlugin2({
|
|
1510
|
+
source: name,
|
|
1511
|
+
details: { reason: `"${version}" is not a semantic version` }
|
|
1512
|
+
});
|
|
1577
1513
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
name
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
sensitive = false,
|
|
1586
|
-
unique = false,
|
|
1587
|
-
default: _default,
|
|
1588
|
-
preHandle: onPreHandle,
|
|
1589
|
-
afterHandle: onAfterHandle
|
|
1590
|
-
}) {
|
|
1591
|
-
const valueSchema = optional ? Type2.Optional(schema) : schema;
|
|
1592
|
-
const SchemaConstructor = schemaOf2(name, valueSchema);
|
|
1593
|
-
const type = {
|
|
1594
|
-
[Demo2]: _default,
|
|
1514
|
+
const requires = pluginsOf2(Record);
|
|
1515
|
+
const inherited = new Set(requires.flatMap((required) => required.keys));
|
|
1516
|
+
const declaration = Record;
|
|
1517
|
+
const keys = Object.freeze(Object.keys(declaration.blueprint.properties).filter((key) => !inherited.has(key)));
|
|
1518
|
+
const own = membersOf(Record, name);
|
|
1519
|
+
const plugin = Object.freeze({
|
|
1520
|
+
[Kind2]: "record-plugin",
|
|
1595
1521
|
name,
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1522
|
+
version,
|
|
1523
|
+
...description === undefined ? {} : { description },
|
|
1524
|
+
record: Record,
|
|
1525
|
+
keys,
|
|
1526
|
+
members: Object.freeze(Object.keys(own.descriptors)),
|
|
1527
|
+
options: declaration.options,
|
|
1528
|
+
requires,
|
|
1529
|
+
is: (value) => hasPlugin2(value, plugin),
|
|
1530
|
+
toJSON: () => descriptorOf(plugin)
|
|
1531
|
+
});
|
|
1532
|
+
internals.set(plugin, own);
|
|
1533
|
+
return plugin;
|
|
1534
|
+
}
|
|
1535
|
+
function descriptorOf(plugin) {
|
|
1536
|
+
return Object.freeze({
|
|
1537
|
+
kind: "record-plugin",
|
|
1538
|
+
name: plugin.name,
|
|
1539
|
+
version: plugin.version,
|
|
1540
|
+
...plugin.description === undefined ? {} : { description: plugin.description },
|
|
1541
|
+
keys: plugin.keys,
|
|
1542
|
+
sensitive: plugin.options.sensitive,
|
|
1543
|
+
unique: plugin.options.unique,
|
|
1544
|
+
change: plugin.options.change,
|
|
1545
|
+
members: plugin.members,
|
|
1546
|
+
requires: Object.freeze(plugin.requires.map(({ name, version }) => Object.freeze({ name, version })))
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
function applyPlugins(blueprint, plugins, name, reserved) {
|
|
1550
|
+
const flat = [];
|
|
1551
|
+
for (const plugin of plugins) {
|
|
1552
|
+
if (!isRecordPlugin2(plugin)) {
|
|
1553
|
+
throw new InvalidRecordPlugin2({
|
|
1554
|
+
source: name,
|
|
1555
|
+
details: {
|
|
1556
|
+
reason: "`options.plugins` takes plugins made by `recordPluginOf`"
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1608
1559
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1560
|
+
for (const applied of [...plugin.requires, plugin]) {
|
|
1561
|
+
if (flat.includes(applied))
|
|
1562
|
+
continue;
|
|
1563
|
+
if (flat.some((other) => other.name === applied.name)) {
|
|
1564
|
+
throw new RecordPluginConflict2({
|
|
1565
|
+
source: name,
|
|
1566
|
+
details: {
|
|
1567
|
+
plugin: applied.name,
|
|
1568
|
+
key: applied.name,
|
|
1569
|
+
owner: "another plugin"
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
flat.push(applied);
|
|
1611
1574
|
}
|
|
1612
1575
|
}
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1576
|
+
const owners = new Map(Object.keys(blueprint.properties).map((key) => [key, `record "${name}"`]));
|
|
1577
|
+
for (const member of reserved)
|
|
1578
|
+
owners.set(member, `record "${name}"`);
|
|
1579
|
+
const claim = (plugin, key) => {
|
|
1580
|
+
const owner = owners.get(key);
|
|
1581
|
+
if (owner !== undefined) {
|
|
1582
|
+
throw new RecordPluginConflict2({
|
|
1583
|
+
source: name,
|
|
1584
|
+
details: { plugin: plugin.name, key, owner }
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
owners.set(key, `plugin "${plugin.name}"`);
|
|
1588
|
+
};
|
|
1589
|
+
const descriptors = {};
|
|
1590
|
+
const hooks = [];
|
|
1591
|
+
for (const plugin of flat) {
|
|
1592
|
+
for (const key of plugin.keys)
|
|
1593
|
+
claim(plugin, key);
|
|
1594
|
+
const own = internals.get(plugin);
|
|
1595
|
+
for (const member of plugin.members) {
|
|
1596
|
+
claim(plugin, member);
|
|
1597
|
+
descriptors[member] = own.descriptors[member];
|
|
1598
|
+
}
|
|
1599
|
+
if (own.hooks.onSet || own.hooks.onSetAll) {
|
|
1600
|
+
hooks.push(Object.freeze({
|
|
1601
|
+
plugin,
|
|
1602
|
+
keys: Object.freeze(Object.keys(plugin.record.blueprint.properties)),
|
|
1603
|
+
...own.hooks
|
|
1604
|
+
}));
|
|
1618
1605
|
}
|
|
1619
1606
|
}
|
|
1620
|
-
return
|
|
1607
|
+
return {
|
|
1608
|
+
blueprint: flat.length === 0 ? blueprint : blueprint.join(...flat.map((plugin) => plugin.record.blueprint)),
|
|
1609
|
+
plugins: Object.freeze(flat),
|
|
1610
|
+
sensitive: flat.flatMap((plugin) => plugin.options.sensitive),
|
|
1611
|
+
unique: flat.flatMap((plugin) => plugin.options.unique),
|
|
1612
|
+
change: flat.flatMap((plugin) => plugin.options.change),
|
|
1613
|
+
descriptors,
|
|
1614
|
+
hooks: Object.freeze(hooks)
|
|
1615
|
+
};
|
|
1621
1616
|
}
|
|
1622
1617
|
|
|
1623
|
-
// src/core/
|
|
1624
|
-
function
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
sourcesOrDefine,
|
|
1628
|
-
maybeDefine
|
|
1629
|
-
];
|
|
1630
|
-
const all = [...base, ...sources];
|
|
1631
|
-
return create(all.flatMap((source) => isBlueprint2(source) ? source.plugins : [source]), { ...define(contextOf(all)) });
|
|
1632
|
-
};
|
|
1618
|
+
// src/core/record/record.ts
|
|
1619
|
+
function recordBuilderOf2(...catalogs) {
|
|
1620
|
+
const context = pluginContextOf(catalogs);
|
|
1621
|
+
return (blueprint, options = {}) => declareRecord(AbstractRecord2, blueprint, options, "record", [], context);
|
|
1633
1622
|
}
|
|
1634
|
-
function
|
|
1635
|
-
return
|
|
1623
|
+
function pluginContextOf(catalogs) {
|
|
1624
|
+
return Object.freeze(Object.assign({}, ...catalogs.map((catalog) => catalog.plugins)));
|
|
1636
1625
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1626
|
+
var recordOf3 = recordBuilderOf2();
|
|
1627
|
+
function declareRecord(Base, declared, { plugins = [], name: declaredName, ...declaredOptions }, fallback, reserved = [], context = {}) {
|
|
1628
|
+
if (declaredName !== undefined && !isRecordName(declaredName)) {
|
|
1629
|
+
throw new InvalidRecordDeclaration2({
|
|
1630
|
+
source: fallback,
|
|
1631
|
+
details: `"name" must be an identifier, got ${JSON.stringify(declaredName)}.`
|
|
1632
|
+
});
|
|
1642
1633
|
}
|
|
1643
|
-
const
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
for (const key of RESERVED_KEYS) {
|
|
1659
|
-
const reserving = sources.find((source) => Object.hasOwn(source.properties, key));
|
|
1660
|
-
if (reserving) {
|
|
1661
|
-
throw new ReservedBlueprintKey2({
|
|
1662
|
-
source: isBlueprint2(reserving) ? "blueprint" : reserving.name,
|
|
1634
|
+
const name = declaredName ?? fallback;
|
|
1635
|
+
const applied = applyPlugins(declared, typeof plugins === "function" ? plugins(context) : plugins, name, reserved);
|
|
1636
|
+
const blueprint = applied.blueprint;
|
|
1637
|
+
const sensitive = [
|
|
1638
|
+
...declaredOptions.sensitive ?? [],
|
|
1639
|
+
...applied.sensitive
|
|
1640
|
+
];
|
|
1641
|
+
const unique = [...declaredOptions.unique ?? [], ...applied.unique];
|
|
1642
|
+
const declaredChange = declaredOptions.change ?? [];
|
|
1643
|
+
const keys = Object.keys(blueprint.properties);
|
|
1644
|
+
const change = keys.filter((key) => declaredChange.includes(key) || applied.change.includes(key));
|
|
1645
|
+
for (const key of [...sensitive, ...unique, ...declaredChange]) {
|
|
1646
|
+
if (!keys.includes(key)) {
|
|
1647
|
+
throw new UndeclaredRecordProperty2({
|
|
1648
|
+
source: name,
|
|
1663
1649
|
details: { key }
|
|
1664
1650
|
});
|
|
1665
1651
|
}
|
|
1666
1652
|
}
|
|
1667
|
-
const
|
|
1668
|
-
for (const
|
|
1669
|
-
if (
|
|
1670
|
-
const
|
|
1671
|
-
throw new
|
|
1672
|
-
source:
|
|
1673
|
-
details: {
|
|
1653
|
+
const methods = change.length > 0 ? [CHANGE_MEMBER] : [];
|
|
1654
|
+
for (const member of Object.keys(applied.descriptors)) {
|
|
1655
|
+
if (methods.includes(member)) {
|
|
1656
|
+
const plugin = applied.plugins.find((plugin) => plugin.members.includes(member));
|
|
1657
|
+
throw new RecordPluginConflict2({
|
|
1658
|
+
source: name,
|
|
1659
|
+
details: {
|
|
1660
|
+
plugin: plugin.name,
|
|
1661
|
+
key: member,
|
|
1662
|
+
owner: `record "${name}" (the \`change\` namespace)`
|
|
1663
|
+
}
|
|
1674
1664
|
});
|
|
1675
1665
|
}
|
|
1676
1666
|
}
|
|
1677
|
-
const
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
...
|
|
1686
|
-
...HELPERS,
|
|
1687
|
-
optional: Object.freeze(mirror(available, (field) => callable(optionalOf2(field)))),
|
|
1688
|
-
list: Object.freeze({
|
|
1689
|
-
...list,
|
|
1690
|
-
optional: Object.freeze(mirror(list, optionalOf2))
|
|
1691
|
-
})
|
|
1667
|
+
for (const key of keys) {
|
|
1668
|
+
if (RESERVED_RECORD_KEYS2.includes(key) || reserved.includes(key) || methods.includes(key)) {
|
|
1669
|
+
throw new ReservedRecordKey2({ source: name, details: { key } });
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
const options = Object.freeze({
|
|
1673
|
+
sensitive: Object.freeze(keys.filter((key) => sensitive.includes(key) || isMarked(blueprint.properties[key], "sensitive", { lists: true }))),
|
|
1674
|
+
unique: Object.freeze(keys.filter((key) => unique.includes(key) || isMarked(blueprint.properties[key], "unique"))),
|
|
1675
|
+
change: Object.freeze([...change])
|
|
1692
1676
|
});
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
return field.optional ? Type3.Optional(schema) : schema;
|
|
1677
|
+
|
|
1678
|
+
class DeclaredRecord extends Base {
|
|
1679
|
+
static [Kind2] = "record";
|
|
1680
|
+
static blueprint = blueprint;
|
|
1681
|
+
static options = options;
|
|
1682
|
+
static plugins = applied.plugins;
|
|
1683
|
+
static [RecordPlugins] = applied.plugins;
|
|
1684
|
+
static [RecordPluginHooks] = applied.hooks;
|
|
1702
1685
|
}
|
|
1703
|
-
if (
|
|
1704
|
-
|
|
1705
|
-
return field.optional ? Type3.Optional(schema) : schema;
|
|
1686
|
+
if (declaredName !== undefined) {
|
|
1687
|
+
declareRecordName(DeclaredRecord, declaredName);
|
|
1706
1688
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1689
|
+
Object.defineProperty(DeclaredRecord, "recordName", {
|
|
1690
|
+
get() {
|
|
1691
|
+
return declaredName ?? this.name;
|
|
1692
|
+
},
|
|
1693
|
+
configurable: true
|
|
1694
|
+
});
|
|
1695
|
+
exposeRecordKeys(DeclaredRecord.prototype, keys);
|
|
1696
|
+
for (const [member, descriptor] of Object.entries(applied.descriptors)) {
|
|
1697
|
+
Object.defineProperty(DeclaredRecord.prototype, member, descriptor);
|
|
1711
1698
|
}
|
|
1712
|
-
if (
|
|
1713
|
-
|
|
1699
|
+
if (change.length > 0) {
|
|
1700
|
+
Object.defineProperty(DeclaredRecord.prototype, CHANGE_MEMBER, {
|
|
1701
|
+
get() {
|
|
1702
|
+
let namespace = changeNamespaces.get(this);
|
|
1703
|
+
if (namespace === undefined) {
|
|
1704
|
+
namespace = Object.freeze(Object.fromEntries(change.map((key) => [
|
|
1705
|
+
key,
|
|
1706
|
+
(value) => this.set(key, value)
|
|
1707
|
+
])));
|
|
1708
|
+
changeNamespaces.set(this, namespace);
|
|
1709
|
+
}
|
|
1710
|
+
return namespace;
|
|
1711
|
+
},
|
|
1712
|
+
configurable: true
|
|
1713
|
+
});
|
|
1714
1714
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
details: { key }
|
|
1718
|
-
});
|
|
1715
|
+
Object.defineProperty(DeclaredRecord, "name", { value: name });
|
|
1716
|
+
return DeclaredRecord;
|
|
1719
1717
|
}
|
|
1718
|
+
var CHANGE_MEMBER = "change";
|
|
1719
|
+
var changeNamespaces = new WeakMap;
|
|
1720
1720
|
|
|
1721
|
-
export { __export, isProperty2, schemaOf2, Demo2, recordPropertyLineage, propertyLineageOf2, fieldOf, Kind2, isBlueprint2, isRecordClass2, isOptionalRecord2, recordFieldOf2, recordNameOf2, declaredRecordNameOf, listOf2, isBlueprintList2, ExceptionLayers2, UNEXPECTED_ERROR2, Exception2, isDeclaredException, declaredMessageOf, exceptionOf2, Meta2, InvalidRecordValue2, InvalidRecordDeclaration2, UndeclaredRecordProperty2, ReservedRecordKey2, InvalidRecordPlugin2, RecordPluginConflict2, UnknownRecordPlugin2, IncompatibleRecordPlugin2, exports_exceptions, MASK2, RESERVED_RECORD_KEYS2, recordDataOf, recordFieldDataOf, storeRecordValue, runRecordEffects, AbstractRecord2,
|
|
1721
|
+
export { __export, isProperty2, schemaOf2, Demo2, recordPropertyLineage, propertyLineageOf2, fieldOf, Kind2, isBlueprint2, isRecordClass2, isOptionalRecord2, recordFieldOf2, recordNameOf2, declaredRecordNameOf, fieldsOf, isPlainObject, listOf2, isBlueprintList2, ExceptionLayers2, UNEXPECTED_ERROR2, Exception2, isDeclaredException, declaredMessageOf, exceptionOf2, Meta2, InvalidRecordValue2, InvalidRecordDeclaration2, UndeclaredRecordProperty2, ReservedRecordKey2, InvalidRecordPlugin2, RecordPluginConflict2, UnknownRecordPlugin2, IncompatibleRecordPlugin2, exports_exceptions, MASK2, RESERVED_RECORD_KEYS2, recordDataOf, recordFieldDataOf, storeRecordValue, runRecordEffects, AbstractRecord2, State2, AbstractProperty2, PropertyStates2, PropertyRequired2, InvalidPropertyValue2, exports_exceptions2, AbstractDefineProperty2, propertyOf2, ReservedBlueprintKey2, UndeclaredBlueprintProperty2, exports_exceptions3, optionalOf2, blueprintBuilderOf2, blueprintFromProperties, IdentifiedRecord, isVersion, satisfies, pluginsOf2, isRecordPlugin2, hasPlugin2, recordPluginOf2, recordBuilderOf2, pluginContextOf, recordOf3, declareRecord };
|