@formspec/build 0.1.0-alpha.30 → 0.1.0-alpha.31

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/browser.js CHANGED
@@ -707,9 +707,9 @@ function collectFields(elements, properties, required, ctx) {
707
707
  for (const element of elements) {
708
708
  switch (element.kind) {
709
709
  case "field":
710
- properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
710
+ properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
711
711
  if (element.required) {
712
- required.push(getSerializedName(element.name, element.metadata));
712
+ required.push(getSerializedFieldName(element));
713
713
  }
714
714
  break;
715
715
  case "group":
@@ -780,19 +780,21 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
780
780
  schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
781
781
  return schema;
782
782
  }
783
- const byTarget = /* @__PURE__ */ new Map();
784
- for (const c of pathConstraints) {
785
- const target = c.path?.segments[0];
786
- if (!target) continue;
787
- const group = byTarget.get(target) ?? [];
788
- group.push(c);
789
- byTarget.set(target, group);
790
- }
791
- const propertyOverrides = {};
792
- for (const [target, constraints] of byTarget) {
793
- const subSchema = {};
794
- applyConstraints(subSchema, constraints, ctx);
795
- propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;
783
+ const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
784
+ const nullableValueBranch = getNullableUnionValueSchema(schema);
785
+ if (nullableValueBranch !== void 0) {
786
+ const updatedNullableValueBranch = applyPathTargetedConstraints(
787
+ nullableValueBranch,
788
+ pathConstraints,
789
+ ctx,
790
+ resolveTraversableTypeNode(typeNode, ctx)
791
+ );
792
+ if (schema.oneOf !== void 0) {
793
+ schema.oneOf = schema.oneOf.map(
794
+ (branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
795
+ );
796
+ }
797
+ return schema;
796
798
  }
797
799
  if (schema.$ref) {
798
800
  const { $ref, ...rest } = schema;
@@ -807,7 +809,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
807
809
  const missingOverrides = {};
808
810
  for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
809
811
  if (schema.properties[target]) {
810
- Object.assign(schema.properties[target], overrideSchema);
812
+ mergeSchemaOverride(schema.properties[target], overrideSchema);
811
813
  } else {
812
814
  missingOverrides[target] = overrideSchema;
813
815
  }
@@ -881,7 +883,7 @@ function generateObjectType(type, ctx) {
881
883
  const properties = {};
882
884
  const required = [];
883
885
  for (const prop of type.properties) {
884
- const propertyName = getSerializedName(prop.name, prop.metadata);
886
+ const propertyName = getSerializedObjectPropertyName(prop);
885
887
  properties[propertyName] = generatePropertySchema(prop, ctx);
886
888
  if (!prop.optional) {
887
889
  required.push(propertyName);
@@ -935,7 +937,16 @@ function isNullableUnion(type) {
935
937
  return nullCount === 1;
936
938
  }
937
939
  function generateReferenceType(type, ctx) {
938
- return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
940
+ return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
941
+ }
942
+ function getSerializedFieldName(field) {
943
+ return getSerializedName(field.name, field.metadata);
944
+ }
945
+ function getSerializedObjectPropertyName(property) {
946
+ return getSerializedName(property.name, property.metadata);
947
+ }
948
+ function getSerializedTypeName(logicalName, ctx) {
949
+ return ctx.typeNameMap[logicalName] ?? logicalName;
939
950
  }
940
951
  function applyResolvedMetadata(schema, metadata) {
941
952
  const displayName = getDisplayName(metadata);
@@ -946,17 +957,148 @@ function applyResolvedMetadata(schema, metadata) {
946
957
  function resolveReferencedType(type, ctx) {
947
958
  return ctx.typeRegistry[type.name]?.type;
948
959
  }
960
+ function dereferenceTypeNode(typeNode, ctx) {
961
+ if (typeNode?.kind !== "reference") {
962
+ return typeNode;
963
+ }
964
+ return resolveReferencedType(typeNode, ctx);
965
+ }
966
+ function unwrapNullableTypeNode(typeNode) {
967
+ if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
968
+ return typeNode;
969
+ }
970
+ return typeNode.members.find(
971
+ (member) => !(member.kind === "primitive" && member.primitiveKind === "null")
972
+ );
973
+ }
974
+ function resolveTraversableTypeNode(typeNode, ctx) {
975
+ const dereferenced = dereferenceTypeNode(typeNode, ctx);
976
+ const unwrapped = unwrapNullableTypeNode(dereferenced);
977
+ if (unwrapped !== dereferenced) {
978
+ return resolveTraversableTypeNode(unwrapped, ctx);
979
+ }
980
+ return dereferenced;
981
+ }
949
982
  function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
950
- if (typeNode?.kind === "object") {
951
- const property = typeNode.properties.find((candidate) => candidate.name === logicalName);
952
- return property === void 0 ? logicalName : getSerializedName(property.name, property.metadata);
983
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
984
+ if (effectiveType?.kind === "array") {
985
+ return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
953
986
  }
954
- if (typeNode?.kind === "reference") {
955
- const referencedType = resolveReferencedType(typeNode, ctx);
956
- return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
987
+ if (effectiveType?.kind === "object") {
988
+ const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
989
+ return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
957
990
  }
958
991
  return logicalName;
959
992
  }
993
+ function resolveTargetTypeNode(logicalName, typeNode, ctx) {
994
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
995
+ if (effectiveType?.kind === "array") {
996
+ return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
997
+ }
998
+ if (effectiveType?.kind !== "object") {
999
+ return void 0;
1000
+ }
1001
+ return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
1002
+ }
1003
+ function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
1004
+ const byTarget = /* @__PURE__ */ new Map();
1005
+ for (const constraint of pathConstraints) {
1006
+ const target = constraint.path?.segments[0];
1007
+ if (!target) {
1008
+ continue;
1009
+ }
1010
+ const grouped = byTarget.get(target) ?? [];
1011
+ grouped.push(constraint);
1012
+ byTarget.set(target, grouped);
1013
+ }
1014
+ const overrides = {};
1015
+ for (const [target, constraints] of byTarget) {
1016
+ overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
1017
+ constraints.map(stripLeadingPathSegment),
1018
+ resolveTargetTypeNode(target, typeNode, ctx),
1019
+ ctx
1020
+ );
1021
+ }
1022
+ return overrides;
1023
+ }
1024
+ function buildPathOverrideSchema(constraints, typeNode, ctx) {
1025
+ const schema = {};
1026
+ const directConstraints = [];
1027
+ const nestedConstraints = [];
1028
+ for (const constraint of constraints) {
1029
+ if (constraint.path === void 0 || constraint.path.segments.length === 0) {
1030
+ directConstraints.push(constraint);
1031
+ } else {
1032
+ nestedConstraints.push(constraint);
1033
+ }
1034
+ }
1035
+ applyConstraints(schema, directConstraints, ctx);
1036
+ if (nestedConstraints.length === 0) {
1037
+ return schema;
1038
+ }
1039
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
1040
+ if (effectiveType?.kind === "array") {
1041
+ schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
1042
+ return schema;
1043
+ }
1044
+ schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
1045
+ return schema;
1046
+ }
1047
+ function mergeSchemaOverride(target, override) {
1048
+ const nullableValueBranch = getNullableUnionValueSchema(target);
1049
+ if (nullableValueBranch !== void 0) {
1050
+ mergeSchemaOverride(nullableValueBranch, override);
1051
+ return;
1052
+ }
1053
+ if (override.properties !== void 0) {
1054
+ const mergedProperties = target.properties ?? {};
1055
+ for (const [name, propertyOverride] of Object.entries(override.properties)) {
1056
+ const existing = mergedProperties[name];
1057
+ if (existing === void 0) {
1058
+ mergedProperties[name] = propertyOverride;
1059
+ } else {
1060
+ mergeSchemaOverride(existing, propertyOverride);
1061
+ }
1062
+ }
1063
+ target.properties = mergedProperties;
1064
+ }
1065
+ if (override.items !== void 0) {
1066
+ if (target.items === void 0) {
1067
+ target.items = override.items;
1068
+ } else {
1069
+ mergeSchemaOverride(target.items, override.items);
1070
+ }
1071
+ }
1072
+ for (const [key, value] of Object.entries(override)) {
1073
+ if (key === "properties" || key === "items") {
1074
+ continue;
1075
+ }
1076
+ target[key] = value;
1077
+ }
1078
+ }
1079
+ function stripLeadingPathSegment(constraint) {
1080
+ const segments = constraint.path?.segments;
1081
+ if (segments === void 0 || segments.length === 0) {
1082
+ return constraint;
1083
+ }
1084
+ const [, ...rest] = segments;
1085
+ if (rest.length === 0) {
1086
+ const { path: _path, ...stripped } = constraint;
1087
+ return stripped;
1088
+ }
1089
+ return {
1090
+ ...constraint,
1091
+ path: { segments: rest }
1092
+ };
1093
+ }
1094
+ function getNullableUnionValueSchema(schema) {
1095
+ if (schema.oneOf?.length !== 2) {
1096
+ return void 0;
1097
+ }
1098
+ const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
1099
+ const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
1100
+ return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
1101
+ }
960
1102
  function generateDynamicType(type) {
961
1103
  if (type.dynamicKind === "enum") {
962
1104
  const schema = {