@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.
package/dist/internals.js CHANGED
@@ -3688,9 +3688,9 @@ function collectFields(elements, properties, required, ctx) {
3688
3688
  for (const element of elements) {
3689
3689
  switch (element.kind) {
3690
3690
  case "field":
3691
- properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
3691
+ properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
3692
3692
  if (element.required) {
3693
- required.push(getSerializedName(element.name, element.metadata));
3693
+ required.push(getSerializedFieldName(element));
3694
3694
  }
3695
3695
  break;
3696
3696
  case "group":
@@ -3761,19 +3761,21 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3761
3761
  schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
3762
3762
  return schema;
3763
3763
  }
3764
- const byTarget = /* @__PURE__ */ new Map();
3765
- for (const c of pathConstraints) {
3766
- const target = c.path?.segments[0];
3767
- if (!target) continue;
3768
- const group = byTarget.get(target) ?? [];
3769
- group.push(c);
3770
- byTarget.set(target, group);
3771
- }
3772
- const propertyOverrides = {};
3773
- for (const [target, constraints] of byTarget) {
3774
- const subSchema = {};
3775
- applyConstraints(subSchema, constraints, ctx);
3776
- propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;
3764
+ const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
3765
+ const nullableValueBranch = getNullableUnionValueSchema(schema);
3766
+ if (nullableValueBranch !== void 0) {
3767
+ const updatedNullableValueBranch = applyPathTargetedConstraints(
3768
+ nullableValueBranch,
3769
+ pathConstraints,
3770
+ ctx,
3771
+ resolveTraversableTypeNode(typeNode, ctx)
3772
+ );
3773
+ if (schema.oneOf !== void 0) {
3774
+ schema.oneOf = schema.oneOf.map(
3775
+ (branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
3776
+ );
3777
+ }
3778
+ return schema;
3777
3779
  }
3778
3780
  if (schema.$ref) {
3779
3781
  const { $ref, ...rest } = schema;
@@ -3788,7 +3790,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3788
3790
  const missingOverrides = {};
3789
3791
  for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
3790
3792
  if (schema.properties[target]) {
3791
- Object.assign(schema.properties[target], overrideSchema);
3793
+ mergeSchemaOverride(schema.properties[target], overrideSchema);
3792
3794
  } else {
3793
3795
  missingOverrides[target] = overrideSchema;
3794
3796
  }
@@ -3862,7 +3864,7 @@ function generateObjectType(type, ctx) {
3862
3864
  const properties = {};
3863
3865
  const required = [];
3864
3866
  for (const prop of type.properties) {
3865
- const propertyName = getSerializedName(prop.name, prop.metadata);
3867
+ const propertyName = getSerializedObjectPropertyName(prop);
3866
3868
  properties[propertyName] = generatePropertySchema(prop, ctx);
3867
3869
  if (!prop.optional) {
3868
3870
  required.push(propertyName);
@@ -3916,7 +3918,16 @@ function isNullableUnion(type) {
3916
3918
  return nullCount === 1;
3917
3919
  }
3918
3920
  function generateReferenceType(type, ctx) {
3919
- return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
3921
+ return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
3922
+ }
3923
+ function getSerializedFieldName(field) {
3924
+ return getSerializedName(field.name, field.metadata);
3925
+ }
3926
+ function getSerializedObjectPropertyName(property) {
3927
+ return getSerializedName(property.name, property.metadata);
3928
+ }
3929
+ function getSerializedTypeName(logicalName, ctx) {
3930
+ return ctx.typeNameMap[logicalName] ?? logicalName;
3920
3931
  }
3921
3932
  function applyResolvedMetadata(schema, metadata) {
3922
3933
  const displayName = getDisplayName(metadata);
@@ -3927,17 +3938,148 @@ function applyResolvedMetadata(schema, metadata) {
3927
3938
  function resolveReferencedType(type, ctx) {
3928
3939
  return ctx.typeRegistry[type.name]?.type;
3929
3940
  }
3941
+ function dereferenceTypeNode(typeNode, ctx) {
3942
+ if (typeNode?.kind !== "reference") {
3943
+ return typeNode;
3944
+ }
3945
+ return resolveReferencedType(typeNode, ctx);
3946
+ }
3947
+ function unwrapNullableTypeNode(typeNode) {
3948
+ if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
3949
+ return typeNode;
3950
+ }
3951
+ return typeNode.members.find(
3952
+ (member) => !(member.kind === "primitive" && member.primitiveKind === "null")
3953
+ );
3954
+ }
3955
+ function resolveTraversableTypeNode(typeNode, ctx) {
3956
+ const dereferenced = dereferenceTypeNode(typeNode, ctx);
3957
+ const unwrapped = unwrapNullableTypeNode(dereferenced);
3958
+ if (unwrapped !== dereferenced) {
3959
+ return resolveTraversableTypeNode(unwrapped, ctx);
3960
+ }
3961
+ return dereferenced;
3962
+ }
3930
3963
  function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
3931
- if (typeNode?.kind === "object") {
3932
- const property = typeNode.properties.find((candidate) => candidate.name === logicalName);
3933
- return property === void 0 ? logicalName : getSerializedName(property.name, property.metadata);
3964
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
3965
+ if (effectiveType?.kind === "array") {
3966
+ return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
3934
3967
  }
3935
- if (typeNode?.kind === "reference") {
3936
- const referencedType = resolveReferencedType(typeNode, ctx);
3937
- return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
3968
+ if (effectiveType?.kind === "object") {
3969
+ const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
3970
+ return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
3938
3971
  }
3939
3972
  return logicalName;
3940
3973
  }
3974
+ function resolveTargetTypeNode(logicalName, typeNode, ctx) {
3975
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
3976
+ if (effectiveType?.kind === "array") {
3977
+ return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
3978
+ }
3979
+ if (effectiveType?.kind !== "object") {
3980
+ return void 0;
3981
+ }
3982
+ return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
3983
+ }
3984
+ function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
3985
+ const byTarget = /* @__PURE__ */ new Map();
3986
+ for (const constraint of pathConstraints) {
3987
+ const target = constraint.path?.segments[0];
3988
+ if (!target) {
3989
+ continue;
3990
+ }
3991
+ const grouped = byTarget.get(target) ?? [];
3992
+ grouped.push(constraint);
3993
+ byTarget.set(target, grouped);
3994
+ }
3995
+ const overrides = {};
3996
+ for (const [target, constraints] of byTarget) {
3997
+ overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
3998
+ constraints.map(stripLeadingPathSegment),
3999
+ resolveTargetTypeNode(target, typeNode, ctx),
4000
+ ctx
4001
+ );
4002
+ }
4003
+ return overrides;
4004
+ }
4005
+ function buildPathOverrideSchema(constraints, typeNode, ctx) {
4006
+ const schema = {};
4007
+ const directConstraints = [];
4008
+ const nestedConstraints = [];
4009
+ for (const constraint of constraints) {
4010
+ if (constraint.path === void 0 || constraint.path.segments.length === 0) {
4011
+ directConstraints.push(constraint);
4012
+ } else {
4013
+ nestedConstraints.push(constraint);
4014
+ }
4015
+ }
4016
+ applyConstraints(schema, directConstraints, ctx);
4017
+ if (nestedConstraints.length === 0) {
4018
+ return schema;
4019
+ }
4020
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4021
+ if (effectiveType?.kind === "array") {
4022
+ schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
4023
+ return schema;
4024
+ }
4025
+ schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
4026
+ return schema;
4027
+ }
4028
+ function mergeSchemaOverride(target, override) {
4029
+ const nullableValueBranch = getNullableUnionValueSchema(target);
4030
+ if (nullableValueBranch !== void 0) {
4031
+ mergeSchemaOverride(nullableValueBranch, override);
4032
+ return;
4033
+ }
4034
+ if (override.properties !== void 0) {
4035
+ const mergedProperties = target.properties ?? {};
4036
+ for (const [name, propertyOverride] of Object.entries(override.properties)) {
4037
+ const existing = mergedProperties[name];
4038
+ if (existing === void 0) {
4039
+ mergedProperties[name] = propertyOverride;
4040
+ } else {
4041
+ mergeSchemaOverride(existing, propertyOverride);
4042
+ }
4043
+ }
4044
+ target.properties = mergedProperties;
4045
+ }
4046
+ if (override.items !== void 0) {
4047
+ if (target.items === void 0) {
4048
+ target.items = override.items;
4049
+ } else {
4050
+ mergeSchemaOverride(target.items, override.items);
4051
+ }
4052
+ }
4053
+ for (const [key, value] of Object.entries(override)) {
4054
+ if (key === "properties" || key === "items") {
4055
+ continue;
4056
+ }
4057
+ target[key] = value;
4058
+ }
4059
+ }
4060
+ function stripLeadingPathSegment(constraint) {
4061
+ const segments = constraint.path?.segments;
4062
+ if (segments === void 0 || segments.length === 0) {
4063
+ return constraint;
4064
+ }
4065
+ const [, ...rest] = segments;
4066
+ if (rest.length === 0) {
4067
+ const { path: _path, ...stripped } = constraint;
4068
+ return stripped;
4069
+ }
4070
+ return {
4071
+ ...constraint,
4072
+ path: { segments: rest }
4073
+ };
4074
+ }
4075
+ function getNullableUnionValueSchema(schema) {
4076
+ if (schema.oneOf?.length !== 2) {
4077
+ return void 0;
4078
+ }
4079
+ const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
4080
+ const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
4081
+ return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
4082
+ }
3941
4083
  function generateDynamicType(type) {
3942
4084
  if (type.dynamicKind === "enum") {
3943
4085
  const schema = {