@formspec/build 0.1.0-alpha.29 → 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.
@@ -3714,9 +3714,9 @@ function collectFields(elements, properties, required, ctx) {
3714
3714
  for (const element of elements) {
3715
3715
  switch (element.kind) {
3716
3716
  case "field":
3717
- properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
3717
+ properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
3718
3718
  if (element.required) {
3719
- required.push(getSerializedName(element.name, element.metadata));
3719
+ required.push(getSerializedFieldName(element));
3720
3720
  }
3721
3721
  break;
3722
3722
  case "group":
@@ -3787,19 +3787,21 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3787
3787
  schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
3788
3788
  return schema;
3789
3789
  }
3790
- const byTarget = /* @__PURE__ */ new Map();
3791
- for (const c of pathConstraints) {
3792
- const target = c.path?.segments[0];
3793
- if (!target) continue;
3794
- const group = byTarget.get(target) ?? [];
3795
- group.push(c);
3796
- byTarget.set(target, group);
3797
- }
3798
- const propertyOverrides = {};
3799
- for (const [target, constraints] of byTarget) {
3800
- const subSchema = {};
3801
- applyConstraints(subSchema, constraints, ctx);
3802
- propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;
3790
+ const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
3791
+ const nullableValueBranch = getNullableUnionValueSchema(schema);
3792
+ if (nullableValueBranch !== void 0) {
3793
+ const updatedNullableValueBranch = applyPathTargetedConstraints(
3794
+ nullableValueBranch,
3795
+ pathConstraints,
3796
+ ctx,
3797
+ resolveTraversableTypeNode(typeNode, ctx)
3798
+ );
3799
+ if (schema.oneOf !== void 0) {
3800
+ schema.oneOf = schema.oneOf.map(
3801
+ (branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
3802
+ );
3803
+ }
3804
+ return schema;
3803
3805
  }
3804
3806
  if (schema.$ref) {
3805
3807
  const { $ref, ...rest } = schema;
@@ -3814,7 +3816,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3814
3816
  const missingOverrides = {};
3815
3817
  for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
3816
3818
  if (schema.properties[target]) {
3817
- Object.assign(schema.properties[target], overrideSchema);
3819
+ mergeSchemaOverride(schema.properties[target], overrideSchema);
3818
3820
  } else {
3819
3821
  missingOverrides[target] = overrideSchema;
3820
3822
  }
@@ -3888,7 +3890,7 @@ function generateObjectType(type, ctx) {
3888
3890
  const properties = {};
3889
3891
  const required = [];
3890
3892
  for (const prop of type.properties) {
3891
- const propertyName = getSerializedName(prop.name, prop.metadata);
3893
+ const propertyName = getSerializedObjectPropertyName(prop);
3892
3894
  properties[propertyName] = generatePropertySchema(prop, ctx);
3893
3895
  if (!prop.optional) {
3894
3896
  required.push(propertyName);
@@ -3942,7 +3944,16 @@ function isNullableUnion(type) {
3942
3944
  return nullCount === 1;
3943
3945
  }
3944
3946
  function generateReferenceType(type, ctx) {
3945
- return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
3947
+ return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
3948
+ }
3949
+ function getSerializedFieldName(field) {
3950
+ return getSerializedName(field.name, field.metadata);
3951
+ }
3952
+ function getSerializedObjectPropertyName(property) {
3953
+ return getSerializedName(property.name, property.metadata);
3954
+ }
3955
+ function getSerializedTypeName(logicalName, ctx) {
3956
+ return ctx.typeNameMap[logicalName] ?? logicalName;
3946
3957
  }
3947
3958
  function applyResolvedMetadata(schema, metadata) {
3948
3959
  const displayName = getDisplayName(metadata);
@@ -3953,17 +3964,148 @@ function applyResolvedMetadata(schema, metadata) {
3953
3964
  function resolveReferencedType(type, ctx) {
3954
3965
  return ctx.typeRegistry[type.name]?.type;
3955
3966
  }
3967
+ function dereferenceTypeNode(typeNode, ctx) {
3968
+ if (typeNode?.kind !== "reference") {
3969
+ return typeNode;
3970
+ }
3971
+ return resolveReferencedType(typeNode, ctx);
3972
+ }
3973
+ function unwrapNullableTypeNode(typeNode) {
3974
+ if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
3975
+ return typeNode;
3976
+ }
3977
+ return typeNode.members.find(
3978
+ (member) => !(member.kind === "primitive" && member.primitiveKind === "null")
3979
+ );
3980
+ }
3981
+ function resolveTraversableTypeNode(typeNode, ctx) {
3982
+ const dereferenced = dereferenceTypeNode(typeNode, ctx);
3983
+ const unwrapped = unwrapNullableTypeNode(dereferenced);
3984
+ if (unwrapped !== dereferenced) {
3985
+ return resolveTraversableTypeNode(unwrapped, ctx);
3986
+ }
3987
+ return dereferenced;
3988
+ }
3956
3989
  function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
3957
- if (typeNode?.kind === "object") {
3958
- const property = typeNode.properties.find((candidate) => candidate.name === logicalName);
3959
- return property === void 0 ? logicalName : getSerializedName(property.name, property.metadata);
3990
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
3991
+ if (effectiveType?.kind === "array") {
3992
+ return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
3960
3993
  }
3961
- if (typeNode?.kind === "reference") {
3962
- const referencedType = resolveReferencedType(typeNode, ctx);
3963
- return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
3994
+ if (effectiveType?.kind === "object") {
3995
+ const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
3996
+ return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
3964
3997
  }
3965
3998
  return logicalName;
3966
3999
  }
4000
+ function resolveTargetTypeNode(logicalName, typeNode, ctx) {
4001
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4002
+ if (effectiveType?.kind === "array") {
4003
+ return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
4004
+ }
4005
+ if (effectiveType?.kind !== "object") {
4006
+ return void 0;
4007
+ }
4008
+ return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
4009
+ }
4010
+ function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
4011
+ const byTarget = /* @__PURE__ */ new Map();
4012
+ for (const constraint of pathConstraints) {
4013
+ const target = constraint.path?.segments[0];
4014
+ if (!target) {
4015
+ continue;
4016
+ }
4017
+ const grouped = byTarget.get(target) ?? [];
4018
+ grouped.push(constraint);
4019
+ byTarget.set(target, grouped);
4020
+ }
4021
+ const overrides = {};
4022
+ for (const [target, constraints] of byTarget) {
4023
+ overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
4024
+ constraints.map(stripLeadingPathSegment),
4025
+ resolveTargetTypeNode(target, typeNode, ctx),
4026
+ ctx
4027
+ );
4028
+ }
4029
+ return overrides;
4030
+ }
4031
+ function buildPathOverrideSchema(constraints, typeNode, ctx) {
4032
+ const schema = {};
4033
+ const directConstraints = [];
4034
+ const nestedConstraints = [];
4035
+ for (const constraint of constraints) {
4036
+ if (constraint.path === void 0 || constraint.path.segments.length === 0) {
4037
+ directConstraints.push(constraint);
4038
+ } else {
4039
+ nestedConstraints.push(constraint);
4040
+ }
4041
+ }
4042
+ applyConstraints(schema, directConstraints, ctx);
4043
+ if (nestedConstraints.length === 0) {
4044
+ return schema;
4045
+ }
4046
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4047
+ if (effectiveType?.kind === "array") {
4048
+ schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
4049
+ return schema;
4050
+ }
4051
+ schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
4052
+ return schema;
4053
+ }
4054
+ function mergeSchemaOverride(target, override) {
4055
+ const nullableValueBranch = getNullableUnionValueSchema(target);
4056
+ if (nullableValueBranch !== void 0) {
4057
+ mergeSchemaOverride(nullableValueBranch, override);
4058
+ return;
4059
+ }
4060
+ if (override.properties !== void 0) {
4061
+ const mergedProperties = target.properties ?? {};
4062
+ for (const [name, propertyOverride] of Object.entries(override.properties)) {
4063
+ const existing = mergedProperties[name];
4064
+ if (existing === void 0) {
4065
+ mergedProperties[name] = propertyOverride;
4066
+ } else {
4067
+ mergeSchemaOverride(existing, propertyOverride);
4068
+ }
4069
+ }
4070
+ target.properties = mergedProperties;
4071
+ }
4072
+ if (override.items !== void 0) {
4073
+ if (target.items === void 0) {
4074
+ target.items = override.items;
4075
+ } else {
4076
+ mergeSchemaOverride(target.items, override.items);
4077
+ }
4078
+ }
4079
+ for (const [key, value] of Object.entries(override)) {
4080
+ if (key === "properties" || key === "items") {
4081
+ continue;
4082
+ }
4083
+ target[key] = value;
4084
+ }
4085
+ }
4086
+ function stripLeadingPathSegment(constraint) {
4087
+ const segments = constraint.path?.segments;
4088
+ if (segments === void 0 || segments.length === 0) {
4089
+ return constraint;
4090
+ }
4091
+ const [, ...rest] = segments;
4092
+ if (rest.length === 0) {
4093
+ const { path: _path, ...stripped } = constraint;
4094
+ return stripped;
4095
+ }
4096
+ return {
4097
+ ...constraint,
4098
+ path: { segments: rest }
4099
+ };
4100
+ }
4101
+ function getNullableUnionValueSchema(schema) {
4102
+ if (schema.oneOf?.length !== 2) {
4103
+ return void 0;
4104
+ }
4105
+ const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
4106
+ const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
4107
+ return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
4108
+ }
3967
4109
  function generateDynamicType(type) {
3968
4110
  if (type.dynamicKind === "enum") {
3969
4111
  const schema = {