@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/cli.js CHANGED
@@ -996,20 +996,29 @@ var init_collision_guards = __esm({
996
996
  });
997
997
 
998
998
  // src/json-schema/ir-generator.ts
999
+ function parseEnumSerialization(value) {
1000
+ switch (value) {
1001
+ case void 0:
1002
+ case "enum":
1003
+ return "enum";
1004
+ case "oneOf":
1005
+ return "oneOf";
1006
+ case "smart-size":
1007
+ return "smart-size";
1008
+ default:
1009
+ throw new Error(
1010
+ `Invalid enumSerialization "${String(value)}". Expected "enum", "oneOf", or "smart-size".`
1011
+ );
1012
+ }
1013
+ }
999
1014
  function makeContext(options) {
1000
1015
  const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
1001
- const rawEnumSerialization = options?.enumSerialization;
1016
+ const enumSerialization = parseEnumSerialization(options?.enumSerialization);
1002
1017
  if (!vendorPrefix.startsWith("x-")) {
1003
1018
  throw new Error(
1004
1019
  `Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
1005
1020
  );
1006
1021
  }
1007
- if (rawEnumSerialization !== void 0 && rawEnumSerialization !== "enum" && rawEnumSerialization !== "oneOf") {
1008
- throw new Error(
1009
- `Invalid enumSerialization "${rawEnumSerialization}". Expected "enum" or "oneOf".`
1010
- );
1011
- }
1012
- const enumSerialization = rawEnumSerialization ?? "enum";
1013
1022
  return {
1014
1023
  defs: {},
1015
1024
  typeNameMap: {},
@@ -1217,7 +1226,7 @@ function generatePrimitiveType(type) {
1217
1226
  };
1218
1227
  }
1219
1228
  function generateEnumType(type, ctx) {
1220
- if (ctx.enumSerialization === "oneOf") {
1229
+ if (ctx.enumSerialization === "oneOf" || ctx.enumSerialization === "smart-size" && shouldSerializeEnumAsOneOf(type)) {
1221
1230
  return {
1222
1231
  oneOf: type.members.map((m) => {
1223
1232
  const stringValue = String(m.value);
@@ -1227,12 +1236,21 @@ function generateEnumType(type, ctx) {
1227
1236
  };
1228
1237
  }
1229
1238
  const schema = { enum: type.members.map((m) => m.value) };
1239
+ if (ctx.enumSerialization === "smart-size") {
1240
+ return schema;
1241
+ }
1230
1242
  const displayNames = buildEnumDisplayNameExtension(type);
1231
1243
  if (displayNames !== void 0) {
1232
1244
  schema[`${ctx.vendorPrefix}-display-names`] = displayNames;
1233
1245
  }
1234
1246
  return schema;
1235
1247
  }
1248
+ function shouldSerializeEnumAsOneOf(type) {
1249
+ return type.members.some((member) => {
1250
+ const title = member.displayName ?? String(member.value);
1251
+ return title !== String(member.value);
1252
+ });
1253
+ }
1236
1254
  function buildEnumDisplayNameExtension(type) {
1237
1255
  if (!type.members.some((member) => member.displayName !== void 0)) {
1238
1256
  return void 0;
@@ -2469,6 +2487,8 @@ import {
2469
2487
  getBuildLogger,
2470
2488
  getBroadeningLogger,
2471
2489
  getSyntheticLogger as getSyntheticLogger2,
2490
+ getTypedParserLogger,
2491
+ parseTagArgument,
2472
2492
  describeTypeKind,
2473
2493
  elapsedMicros,
2474
2494
  nowMicros,
@@ -2624,6 +2644,7 @@ function processConstraintTag(tagName, text, parsedTag, provenance, node, source
2624
2644
  sourceFile,
2625
2645
  tagName,
2626
2646
  parsedTag,
2647
+ text,
2627
2648
  provenance,
2628
2649
  supportingDeclarations,
2629
2650
  options
@@ -2651,6 +2672,9 @@ function renderSyntheticArgumentExpression(valueKind, argumentText) {
2651
2672
  case "number":
2652
2673
  case "integer":
2653
2674
  case "signedInteger":
2675
+ if (trimmed === "Infinity" || trimmed === "-Infinity" || trimmed === "NaN") {
2676
+ return trimmed;
2677
+ }
2654
2678
  return Number.isFinite(Number(trimmed)) ? trimmed : JSON.stringify(trimmed);
2655
2679
  case "string":
2656
2680
  return JSON.stringify(argumentText);
@@ -2860,7 +2884,7 @@ function hasBuiltinConstraintBroadening(tagName, options) {
2860
2884
  const broadenedTypeId = getBroadenedCustomTypeId(options?.fieldType);
2861
2885
  return broadenedTypeId !== void 0 && options?.extensionRegistry?.findBuiltinConstraintBroadening(broadenedTypeId, tagName) !== void 0;
2862
2886
  }
2863
- function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, provenance, supportingDeclarations, options) {
2887
+ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, rawText, provenance, supportingDeclarations, options) {
2864
2888
  if (!isBuiltinConstraintName(tagName)) {
2865
2889
  return [];
2866
2890
  }
@@ -2881,8 +2905,10 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2881
2905
  const log2 = getBuildLogger();
2882
2906
  const broadeningLog = getBroadeningLogger();
2883
2907
  const syntheticLog = getSyntheticLogger2();
2908
+ const typedParserLog = getTypedParserLogger();
2884
2909
  const logsEnabled = log2 !== noopLogger4 || broadeningLog !== noopLogger4;
2885
2910
  const syntheticTraceEnabled = syntheticLog !== noopLogger4;
2911
+ const typedParserTraceEnabled = typedParserLog !== noopLogger4;
2886
2912
  const logStart = logsEnabled ? nowMicros() : 0;
2887
2913
  const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
2888
2914
  function emit(outcome, result2) {
@@ -2990,16 +3016,57 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2990
3016
  ]);
2991
3017
  }
2992
3018
  }
2993
- const argumentExpression = renderSyntheticArgumentExpression(
2994
- definition.valueKind,
2995
- parsedTag?.argumentText ?? ""
2996
- );
2997
- if (definition.requiresArgument && argumentExpression === null) {
2998
- return emit("A-pass", []);
2999
- }
3019
+ const effectiveArgumentText = parsedTag !== null ? parseTagSyntax(tagName, rawText).argumentText : rawText;
3000
3020
  if (hasBroadening) {
3001
3021
  return emit("bypass", []);
3002
3022
  }
3023
+ const typedParseResult = parseTagArgument(tagName, effectiveArgumentText, "build");
3024
+ if (!typedParseResult.ok) {
3025
+ if (typedParserTraceEnabled) {
3026
+ typedParserLog.trace("typed-parser C-reject", {
3027
+ consumer: "build",
3028
+ tag: tagName,
3029
+ placement: nonNullPlacement,
3030
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
3031
+ roleOutcome: "C-reject",
3032
+ diagnosticCode: typedParseResult.diagnostic.code
3033
+ });
3034
+ }
3035
+ let mappedCode;
3036
+ switch (typedParseResult.diagnostic.code) {
3037
+ case "MISSING_TAG_ARGUMENT":
3038
+ mappedCode = "MISSING_TAG_ARGUMENT";
3039
+ break;
3040
+ case "INVALID_TAG_ARGUMENT":
3041
+ mappedCode = "INVALID_TAG_ARGUMENT";
3042
+ break;
3043
+ case "UNKNOWN_TAG":
3044
+ throw new Error(
3045
+ `Unexpected UNKNOWN_TAG from parseTagArgument("${tagName}") \u2014 tag was resolved via getTagDefinition.`
3046
+ );
3047
+ default: {
3048
+ const _exhaustive = typedParseResult.diagnostic.code;
3049
+ throw new Error(`Unknown diagnostic code: ${String(_exhaustive)}`);
3050
+ }
3051
+ }
3052
+ return emit("C-reject", [
3053
+ makeDiagnostic(mappedCode, typedParseResult.diagnostic.message, provenance)
3054
+ ]);
3055
+ }
3056
+ if (typedParserTraceEnabled) {
3057
+ typedParserLog.trace("typed-parser C-pass", {
3058
+ consumer: "build",
3059
+ tag: tagName,
3060
+ placement: nonNullPlacement,
3061
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
3062
+ roleOutcome: "C-pass",
3063
+ valueKind: typedParseResult.value.kind
3064
+ });
3065
+ }
3066
+ const argumentExpression = renderSyntheticArgumentExpression(
3067
+ definition.valueKind,
3068
+ effectiveArgumentText
3069
+ );
3003
3070
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
3004
3071
  const hostType = options?.hostType ?? subjectType;
3005
3072
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
@@ -7194,7 +7261,7 @@ Usage:
7194
7261
  Options:
7195
7262
  -o, --out-dir <dir> Output directory (default: ./generated)
7196
7263
  -n, --name <name> Base name for output files (default: derived from input)
7197
- --enum-serialization <enum|oneOf>
7264
+ --enum-serialization <enum|oneOf|smart-size>
7198
7265
  Enum JSON Schema representation (default: enum)
7199
7266
  -h, --help Show this help message
7200
7267
 
@@ -7246,8 +7313,10 @@ function parseArgs(args) {
7246
7313
  console.error("Error: --enum-serialization requires a value");
7247
7314
  return null;
7248
7315
  }
7249
- if (nextArg !== "enum" && nextArg !== "oneOf") {
7250
- console.error('Error: --enum-serialization must be "enum" or "oneOf"');
7316
+ if (nextArg !== "enum" && nextArg !== "oneOf" && nextArg !== "smart-size") {
7317
+ console.error(
7318
+ 'Error: --enum-serialization must be "enum", "oneOf", or "smart-size"'
7319
+ );
7251
7320
  return null;
7252
7321
  }
7253
7322
  enumSerialization = nextArg;