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

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.
@@ -2142,10 +2142,7 @@ function resolveLiteralDiscriminatorPropertyValue(boundType, fieldName, checker,
2142
2142
  if (resolvedAnchorNode === null) {
2143
2143
  return void 0;
2144
2144
  }
2145
- const propertyType = checker.getTypeOfSymbolAtLocation(
2146
- propertySymbol,
2147
- resolvedAnchorNode
2148
- );
2145
+ const propertyType = checker.getTypeOfSymbolAtLocation(propertySymbol, resolvedAnchorNode);
2149
2146
  if (propertyType.isStringLiteral()) {
2150
2147
  return propertyType.value;
2151
2148
  }
@@ -3104,14 +3101,39 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
3104
3101
  collectedDiagnostics
3105
3102
  );
3106
3103
  const fieldNodeInfo = fieldInfoMap?.get(prop.name);
3104
+ const inlineFieldNodeInfo = fieldNodeInfo === void 0 ? ts3.isPropertySignature(declaration) ? analyzeInterfacePropertyToIR(
3105
+ declaration,
3106
+ checker,
3107
+ file,
3108
+ typeRegistry,
3109
+ visiting,
3110
+ collectedDiagnostics,
3111
+ type,
3112
+ metadataPolicy,
3113
+ extensionRegistry
3114
+ ) : ts3.isPropertyDeclaration(declaration) ? analyzeFieldToIR(
3115
+ declaration,
3116
+ checker,
3117
+ file,
3118
+ typeRegistry,
3119
+ visiting,
3120
+ collectedDiagnostics,
3121
+ type,
3122
+ metadataPolicy,
3123
+ extensionRegistry
3124
+ ) : null : null;
3125
+ const resolvedFieldNodeInfo = fieldNodeInfo ?? inlineFieldNodeInfo;
3126
+ const resolvedPropertyType = inlineFieldNodeInfo?.type ?? propTypeNode;
3107
3127
  properties.push({
3108
3128
  name: prop.name,
3109
- ...fieldNodeInfo?.metadata !== void 0 && { metadata: fieldNodeInfo.metadata },
3110
- type: propTypeNode,
3129
+ ...resolvedFieldNodeInfo?.metadata !== void 0 && {
3130
+ metadata: resolvedFieldNodeInfo.metadata
3131
+ },
3132
+ type: resolvedPropertyType,
3111
3133
  optional,
3112
- constraints: fieldNodeInfo?.constraints ?? [],
3113
- annotations: fieldNodeInfo?.annotations ?? [],
3114
- provenance: fieldNodeInfo?.provenance ?? provenanceForFile(file)
3134
+ constraints: resolvedFieldNodeInfo?.constraints ?? [],
3135
+ annotations: resolvedFieldNodeInfo?.annotations ?? [],
3136
+ provenance: resolvedFieldNodeInfo?.provenance ?? provenanceForFile(file)
3115
3137
  });
3116
3138
  }
3117
3139
  visiting.delete(type);
@@ -3714,9 +3736,9 @@ function collectFields(elements, properties, required, ctx) {
3714
3736
  for (const element of elements) {
3715
3737
  switch (element.kind) {
3716
3738
  case "field":
3717
- properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
3739
+ properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
3718
3740
  if (element.required) {
3719
- required.push(getSerializedName(element.name, element.metadata));
3741
+ required.push(getSerializedFieldName(element));
3720
3742
  }
3721
3743
  break;
3722
3744
  case "group":
@@ -3787,19 +3809,21 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3787
3809
  schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
3788
3810
  return schema;
3789
3811
  }
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;
3812
+ const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
3813
+ const nullableValueBranch = getNullableUnionValueSchema(schema);
3814
+ if (nullableValueBranch !== void 0) {
3815
+ const updatedNullableValueBranch = applyPathTargetedConstraints(
3816
+ nullableValueBranch,
3817
+ pathConstraints,
3818
+ ctx,
3819
+ resolveTraversableTypeNode(typeNode, ctx)
3820
+ );
3821
+ if (schema.oneOf !== void 0) {
3822
+ schema.oneOf = schema.oneOf.map(
3823
+ (branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
3824
+ );
3825
+ }
3826
+ return schema;
3803
3827
  }
3804
3828
  if (schema.$ref) {
3805
3829
  const { $ref, ...rest } = schema;
@@ -3814,7 +3838,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
3814
3838
  const missingOverrides = {};
3815
3839
  for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
3816
3840
  if (schema.properties[target]) {
3817
- Object.assign(schema.properties[target], overrideSchema);
3841
+ mergeSchemaOverride(schema.properties[target], overrideSchema);
3818
3842
  } else {
3819
3843
  missingOverrides[target] = overrideSchema;
3820
3844
  }
@@ -3888,7 +3912,7 @@ function generateObjectType(type, ctx) {
3888
3912
  const properties = {};
3889
3913
  const required = [];
3890
3914
  for (const prop of type.properties) {
3891
- const propertyName = getSerializedName(prop.name, prop.metadata);
3915
+ const propertyName = getSerializedObjectPropertyName(prop);
3892
3916
  properties[propertyName] = generatePropertySchema(prop, ctx);
3893
3917
  if (!prop.optional) {
3894
3918
  required.push(propertyName);
@@ -3942,7 +3966,16 @@ function isNullableUnion(type) {
3942
3966
  return nullCount === 1;
3943
3967
  }
3944
3968
  function generateReferenceType(type, ctx) {
3945
- return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
3969
+ return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
3970
+ }
3971
+ function getSerializedFieldName(field) {
3972
+ return getSerializedName(field.name, field.metadata);
3973
+ }
3974
+ function getSerializedObjectPropertyName(property) {
3975
+ return getSerializedName(property.name, property.metadata);
3976
+ }
3977
+ function getSerializedTypeName(logicalName, ctx) {
3978
+ return ctx.typeNameMap[logicalName] ?? logicalName;
3946
3979
  }
3947
3980
  function applyResolvedMetadata(schema, metadata) {
3948
3981
  const displayName = getDisplayName(metadata);
@@ -3953,17 +3986,148 @@ function applyResolvedMetadata(schema, metadata) {
3953
3986
  function resolveReferencedType(type, ctx) {
3954
3987
  return ctx.typeRegistry[type.name]?.type;
3955
3988
  }
3989
+ function dereferenceTypeNode(typeNode, ctx) {
3990
+ if (typeNode?.kind !== "reference") {
3991
+ return typeNode;
3992
+ }
3993
+ return resolveReferencedType(typeNode, ctx);
3994
+ }
3995
+ function unwrapNullableTypeNode(typeNode) {
3996
+ if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
3997
+ return typeNode;
3998
+ }
3999
+ return typeNode.members.find(
4000
+ (member) => !(member.kind === "primitive" && member.primitiveKind === "null")
4001
+ );
4002
+ }
4003
+ function resolveTraversableTypeNode(typeNode, ctx) {
4004
+ const dereferenced = dereferenceTypeNode(typeNode, ctx);
4005
+ const unwrapped = unwrapNullableTypeNode(dereferenced);
4006
+ if (unwrapped !== dereferenced) {
4007
+ return resolveTraversableTypeNode(unwrapped, ctx);
4008
+ }
4009
+ return dereferenced;
4010
+ }
3956
4011
  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);
4012
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4013
+ if (effectiveType?.kind === "array") {
4014
+ return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
3960
4015
  }
3961
- if (typeNode?.kind === "reference") {
3962
- const referencedType = resolveReferencedType(typeNode, ctx);
3963
- return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
4016
+ if (effectiveType?.kind === "object") {
4017
+ const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
4018
+ return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
3964
4019
  }
3965
4020
  return logicalName;
3966
4021
  }
4022
+ function resolveTargetTypeNode(logicalName, typeNode, ctx) {
4023
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4024
+ if (effectiveType?.kind === "array") {
4025
+ return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
4026
+ }
4027
+ if (effectiveType?.kind !== "object") {
4028
+ return void 0;
4029
+ }
4030
+ return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
4031
+ }
4032
+ function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
4033
+ const byTarget = /* @__PURE__ */ new Map();
4034
+ for (const constraint of pathConstraints) {
4035
+ const target = constraint.path?.segments[0];
4036
+ if (!target) {
4037
+ continue;
4038
+ }
4039
+ const grouped = byTarget.get(target) ?? [];
4040
+ grouped.push(constraint);
4041
+ byTarget.set(target, grouped);
4042
+ }
4043
+ const overrides = {};
4044
+ for (const [target, constraints] of byTarget) {
4045
+ overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
4046
+ constraints.map(stripLeadingPathSegment),
4047
+ resolveTargetTypeNode(target, typeNode, ctx),
4048
+ ctx
4049
+ );
4050
+ }
4051
+ return overrides;
4052
+ }
4053
+ function buildPathOverrideSchema(constraints, typeNode, ctx) {
4054
+ const schema = {};
4055
+ const directConstraints = [];
4056
+ const nestedConstraints = [];
4057
+ for (const constraint of constraints) {
4058
+ if (constraint.path === void 0 || constraint.path.segments.length === 0) {
4059
+ directConstraints.push(constraint);
4060
+ } else {
4061
+ nestedConstraints.push(constraint);
4062
+ }
4063
+ }
4064
+ applyConstraints(schema, directConstraints, ctx);
4065
+ if (nestedConstraints.length === 0) {
4066
+ return schema;
4067
+ }
4068
+ const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
4069
+ if (effectiveType?.kind === "array") {
4070
+ schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
4071
+ return schema;
4072
+ }
4073
+ schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
4074
+ return schema;
4075
+ }
4076
+ function mergeSchemaOverride(target, override) {
4077
+ const nullableValueBranch = getNullableUnionValueSchema(target);
4078
+ if (nullableValueBranch !== void 0) {
4079
+ mergeSchemaOverride(nullableValueBranch, override);
4080
+ return;
4081
+ }
4082
+ if (override.properties !== void 0) {
4083
+ const mergedProperties = target.properties ?? {};
4084
+ for (const [name, propertyOverride] of Object.entries(override.properties)) {
4085
+ const existing = mergedProperties[name];
4086
+ if (existing === void 0) {
4087
+ mergedProperties[name] = propertyOverride;
4088
+ } else {
4089
+ mergeSchemaOverride(existing, propertyOverride);
4090
+ }
4091
+ }
4092
+ target.properties = mergedProperties;
4093
+ }
4094
+ if (override.items !== void 0) {
4095
+ if (target.items === void 0) {
4096
+ target.items = override.items;
4097
+ } else {
4098
+ mergeSchemaOverride(target.items, override.items);
4099
+ }
4100
+ }
4101
+ for (const [key, value] of Object.entries(override)) {
4102
+ if (key === "properties" || key === "items") {
4103
+ continue;
4104
+ }
4105
+ target[key] = value;
4106
+ }
4107
+ }
4108
+ function stripLeadingPathSegment(constraint) {
4109
+ const segments = constraint.path?.segments;
4110
+ if (segments === void 0 || segments.length === 0) {
4111
+ return constraint;
4112
+ }
4113
+ const [, ...rest] = segments;
4114
+ if (rest.length === 0) {
4115
+ const { path: _path, ...stripped } = constraint;
4116
+ return stripped;
4117
+ }
4118
+ return {
4119
+ ...constraint,
4120
+ path: { segments: rest }
4121
+ };
4122
+ }
4123
+ function getNullableUnionValueSchema(schema) {
4124
+ if (schema.oneOf?.length !== 2) {
4125
+ return void 0;
4126
+ }
4127
+ const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
4128
+ const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
4129
+ return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
4130
+ }
3967
4131
  function generateDynamicType(type) {
3968
4132
  if (type.dynamicKind === "enum") {
3969
4133
  const schema = {