@formspec/build 0.1.0-alpha.55 → 0.1.0-alpha.58

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/index.js CHANGED
@@ -944,20 +944,29 @@ function assertNoSerializedNameCollisions(ir) {
944
944
  }
945
945
 
946
946
  // src/json-schema/ir-generator.ts
947
+ function parseEnumSerialization(value) {
948
+ switch (value) {
949
+ case void 0:
950
+ case "enum":
951
+ return "enum";
952
+ case "oneOf":
953
+ return "oneOf";
954
+ case "smart-size":
955
+ return "smart-size";
956
+ default:
957
+ throw new Error(
958
+ `Invalid enumSerialization "${String(value)}". Expected "enum", "oneOf", or "smart-size".`
959
+ );
960
+ }
961
+ }
947
962
  function makeContext(options) {
948
963
  const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
949
- const rawEnumSerialization = options?.enumSerialization;
964
+ const enumSerialization = parseEnumSerialization(options?.enumSerialization);
950
965
  if (!vendorPrefix.startsWith("x-")) {
951
966
  throw new Error(
952
967
  `Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
953
968
  );
954
969
  }
955
- if (rawEnumSerialization !== void 0 && rawEnumSerialization !== "enum" && rawEnumSerialization !== "oneOf") {
956
- throw new Error(
957
- `Invalid enumSerialization "${rawEnumSerialization}". Expected "enum" or "oneOf".`
958
- );
959
- }
960
- const enumSerialization = rawEnumSerialization ?? "enum";
961
970
  return {
962
971
  defs: {},
963
972
  typeNameMap: {},
@@ -1165,7 +1174,7 @@ function generatePrimitiveType(type) {
1165
1174
  };
1166
1175
  }
1167
1176
  function generateEnumType(type, ctx) {
1168
- if (ctx.enumSerialization === "oneOf") {
1177
+ if (ctx.enumSerialization === "oneOf" || ctx.enumSerialization === "smart-size" && shouldSerializeEnumAsOneOf(type)) {
1169
1178
  return {
1170
1179
  oneOf: type.members.map((m) => {
1171
1180
  const stringValue = String(m.value);
@@ -1175,12 +1184,21 @@ function generateEnumType(type, ctx) {
1175
1184
  };
1176
1185
  }
1177
1186
  const schema = { enum: type.members.map((m) => m.value) };
1187
+ if (ctx.enumSerialization === "smart-size") {
1188
+ return schema;
1189
+ }
1178
1190
  const displayNames = buildEnumDisplayNameExtension(type);
1179
1191
  if (displayNames !== void 0) {
1180
1192
  schema[`${ctx.vendorPrefix}-display-names`] = displayNames;
1181
1193
  }
1182
1194
  return schema;
1183
1195
  }
1196
+ function shouldSerializeEnumAsOneOf(type) {
1197
+ return type.members.some((member) => {
1198
+ const title = member.displayName ?? String(member.value);
1199
+ return title !== String(member.value);
1200
+ });
1201
+ }
1184
1202
  function buildEnumDisplayNameExtension(type) {
1185
1203
  if (!type.members.some((member) => member.displayName !== void 0)) {
1186
1204
  return void 0;
@@ -2370,6 +2388,8 @@ import {
2370
2388
  getBuildLogger,
2371
2389
  getBroadeningLogger,
2372
2390
  getSyntheticLogger as getSyntheticLogger2,
2391
+ getTypedParserLogger,
2392
+ parseTagArgument,
2373
2393
  describeTypeKind,
2374
2394
  elapsedMicros,
2375
2395
  nowMicros,
@@ -2526,6 +2546,7 @@ function processConstraintTag(tagName, text, parsedTag, provenance, node, source
2526
2546
  sourceFile,
2527
2547
  tagName,
2528
2548
  parsedTag,
2549
+ text,
2529
2550
  provenance,
2530
2551
  supportingDeclarations,
2531
2552
  options
@@ -2553,6 +2574,9 @@ function renderSyntheticArgumentExpression(valueKind, argumentText) {
2553
2574
  case "number":
2554
2575
  case "integer":
2555
2576
  case "signedInteger":
2577
+ if (trimmed === "Infinity" || trimmed === "-Infinity" || trimmed === "NaN") {
2578
+ return trimmed;
2579
+ }
2556
2580
  return Number.isFinite(Number(trimmed)) ? trimmed : JSON.stringify(trimmed);
2557
2581
  case "string":
2558
2582
  return JSON.stringify(argumentText);
@@ -2764,7 +2788,7 @@ function hasBuiltinConstraintBroadening(tagName, options) {
2764
2788
  const broadenedTypeId = getBroadenedCustomTypeId(options?.fieldType);
2765
2789
  return broadenedTypeId !== void 0 && options?.extensionRegistry?.findBuiltinConstraintBroadening(broadenedTypeId, tagName) !== void 0;
2766
2790
  }
2767
- function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, provenance, supportingDeclarations, options) {
2791
+ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, rawText, provenance, supportingDeclarations, options) {
2768
2792
  if (!isBuiltinConstraintName(tagName)) {
2769
2793
  return [];
2770
2794
  }
@@ -2785,8 +2809,10 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2785
2809
  const log = getBuildLogger();
2786
2810
  const broadeningLog = getBroadeningLogger();
2787
2811
  const syntheticLog = getSyntheticLogger2();
2812
+ const typedParserLog = getTypedParserLogger();
2788
2813
  const logsEnabled = log !== noopLogger3 || broadeningLog !== noopLogger3;
2789
2814
  const syntheticTraceEnabled = syntheticLog !== noopLogger3;
2815
+ const typedParserTraceEnabled = typedParserLog !== noopLogger3;
2790
2816
  const logStart = logsEnabled ? nowMicros() : 0;
2791
2817
  const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
2792
2818
  function emit(outcome, result2) {
@@ -2894,16 +2920,57 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2894
2920
  ]);
2895
2921
  }
2896
2922
  }
2897
- const argumentExpression = renderSyntheticArgumentExpression(
2898
- definition.valueKind,
2899
- parsedTag?.argumentText ?? ""
2900
- );
2901
- if (definition.requiresArgument && argumentExpression === null) {
2902
- return emit("A-pass", []);
2903
- }
2923
+ const effectiveArgumentText = parsedTag !== null ? parseTagSyntax(tagName, rawText).argumentText : rawText;
2904
2924
  if (hasBroadening) {
2905
2925
  return emit("bypass", []);
2906
2926
  }
2927
+ const typedParseResult = parseTagArgument(tagName, effectiveArgumentText, "build");
2928
+ if (!typedParseResult.ok) {
2929
+ if (typedParserTraceEnabled) {
2930
+ typedParserLog.trace("typed-parser C-reject", {
2931
+ consumer: "build",
2932
+ tag: tagName,
2933
+ placement: nonNullPlacement,
2934
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
2935
+ roleOutcome: "C-reject",
2936
+ diagnosticCode: typedParseResult.diagnostic.code
2937
+ });
2938
+ }
2939
+ let mappedCode;
2940
+ switch (typedParseResult.diagnostic.code) {
2941
+ case "MISSING_TAG_ARGUMENT":
2942
+ mappedCode = "MISSING_TAG_ARGUMENT";
2943
+ break;
2944
+ case "INVALID_TAG_ARGUMENT":
2945
+ mappedCode = "INVALID_TAG_ARGUMENT";
2946
+ break;
2947
+ case "UNKNOWN_TAG":
2948
+ throw new Error(
2949
+ `Unexpected UNKNOWN_TAG from parseTagArgument("${tagName}") \u2014 tag was resolved via getTagDefinition.`
2950
+ );
2951
+ default: {
2952
+ const _exhaustive = typedParseResult.diagnostic.code;
2953
+ throw new Error(`Unknown diagnostic code: ${String(_exhaustive)}`);
2954
+ }
2955
+ }
2956
+ return emit("C-reject", [
2957
+ makeDiagnostic(mappedCode, typedParseResult.diagnostic.message, provenance)
2958
+ ]);
2959
+ }
2960
+ if (typedParserTraceEnabled) {
2961
+ typedParserLog.trace("typed-parser C-pass", {
2962
+ consumer: "build",
2963
+ tag: tagName,
2964
+ placement: nonNullPlacement,
2965
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
2966
+ roleOutcome: "C-pass",
2967
+ valueKind: typedParseResult.value.kind
2968
+ });
2969
+ }
2970
+ const argumentExpression = renderSyntheticArgumentExpression(
2971
+ definition.valueKind,
2972
+ effectiveArgumentText
2973
+ );
2907
2974
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2908
2975
  const hostType = options?.hostType ?? subjectType;
2909
2976
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);