@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/internals.js CHANGED
@@ -960,6 +960,8 @@ import {
960
960
  getBuildLogger,
961
961
  getBroadeningLogger,
962
962
  getSyntheticLogger,
963
+ getTypedParserLogger,
964
+ parseTagArgument,
963
965
  describeTypeKind,
964
966
  elapsedMicros,
965
967
  nowMicros,
@@ -1116,6 +1118,7 @@ function processConstraintTag(tagName, text, parsedTag, provenance, node, source
1116
1118
  sourceFile,
1117
1119
  tagName,
1118
1120
  parsedTag,
1121
+ text,
1119
1122
  provenance,
1120
1123
  supportingDeclarations,
1121
1124
  options
@@ -1143,6 +1146,9 @@ function renderSyntheticArgumentExpression(valueKind, argumentText) {
1143
1146
  case "number":
1144
1147
  case "integer":
1145
1148
  case "signedInteger":
1149
+ if (trimmed === "Infinity" || trimmed === "-Infinity" || trimmed === "NaN") {
1150
+ return trimmed;
1151
+ }
1146
1152
  return Number.isFinite(Number(trimmed)) ? trimmed : JSON.stringify(trimmed);
1147
1153
  case "string":
1148
1154
  return JSON.stringify(argumentText);
@@ -1354,7 +1360,7 @@ function hasBuiltinConstraintBroadening(tagName, options) {
1354
1360
  const broadenedTypeId = getBroadenedCustomTypeId(options?.fieldType);
1355
1361
  return broadenedTypeId !== void 0 && options?.extensionRegistry?.findBuiltinConstraintBroadening(broadenedTypeId, tagName) !== void 0;
1356
1362
  }
1357
- function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, provenance, supportingDeclarations, options) {
1363
+ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, rawText, provenance, supportingDeclarations, options) {
1358
1364
  if (!isBuiltinConstraintName(tagName)) {
1359
1365
  return [];
1360
1366
  }
@@ -1375,8 +1381,10 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1375
1381
  const log = getBuildLogger();
1376
1382
  const broadeningLog = getBroadeningLogger();
1377
1383
  const syntheticLog = getSyntheticLogger();
1384
+ const typedParserLog = getTypedParserLogger();
1378
1385
  const logsEnabled = log !== noopLogger || broadeningLog !== noopLogger;
1379
1386
  const syntheticTraceEnabled = syntheticLog !== noopLogger;
1387
+ const typedParserTraceEnabled = typedParserLog !== noopLogger;
1380
1388
  const logStart = logsEnabled ? nowMicros() : 0;
1381
1389
  const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
1382
1390
  function emit(outcome, result2) {
@@ -1484,16 +1492,57 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1484
1492
  ]);
1485
1493
  }
1486
1494
  }
1487
- const argumentExpression = renderSyntheticArgumentExpression(
1488
- definition.valueKind,
1489
- parsedTag?.argumentText ?? ""
1490
- );
1491
- if (definition.requiresArgument && argumentExpression === null) {
1492
- return emit("A-pass", []);
1493
- }
1495
+ const effectiveArgumentText = parsedTag !== null ? parseTagSyntax(tagName, rawText).argumentText : rawText;
1494
1496
  if (hasBroadening) {
1495
1497
  return emit("bypass", []);
1496
1498
  }
1499
+ const typedParseResult = parseTagArgument(tagName, effectiveArgumentText, "build");
1500
+ if (!typedParseResult.ok) {
1501
+ if (typedParserTraceEnabled) {
1502
+ typedParserLog.trace("typed-parser C-reject", {
1503
+ consumer: "build",
1504
+ tag: tagName,
1505
+ placement: nonNullPlacement,
1506
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
1507
+ roleOutcome: "C-reject",
1508
+ diagnosticCode: typedParseResult.diagnostic.code
1509
+ });
1510
+ }
1511
+ let mappedCode;
1512
+ switch (typedParseResult.diagnostic.code) {
1513
+ case "MISSING_TAG_ARGUMENT":
1514
+ mappedCode = "MISSING_TAG_ARGUMENT";
1515
+ break;
1516
+ case "INVALID_TAG_ARGUMENT":
1517
+ mappedCode = "INVALID_TAG_ARGUMENT";
1518
+ break;
1519
+ case "UNKNOWN_TAG":
1520
+ throw new Error(
1521
+ `Unexpected UNKNOWN_TAG from parseTagArgument("${tagName}") \u2014 tag was resolved via getTagDefinition.`
1522
+ );
1523
+ default: {
1524
+ const _exhaustive = typedParseResult.diagnostic.code;
1525
+ throw new Error(`Unknown diagnostic code: ${String(_exhaustive)}`);
1526
+ }
1527
+ }
1528
+ return emit("C-reject", [
1529
+ makeDiagnostic(mappedCode, typedParseResult.diagnostic.message, provenance)
1530
+ ]);
1531
+ }
1532
+ if (typedParserTraceEnabled) {
1533
+ typedParserLog.trace("typed-parser C-pass", {
1534
+ consumer: "build",
1535
+ tag: tagName,
1536
+ placement: nonNullPlacement,
1537
+ subjectTypeKind: subjectTypeKind !== "" ? subjectTypeKind : "-",
1538
+ roleOutcome: "C-pass",
1539
+ valueKind: typedParseResult.value.kind
1540
+ });
1541
+ }
1542
+ const argumentExpression = renderSyntheticArgumentExpression(
1543
+ definition.valueKind,
1544
+ effectiveArgumentText
1545
+ );
1497
1546
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1498
1547
  const hostType = options?.hostType ?? subjectType;
1499
1548
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
@@ -4413,20 +4462,29 @@ function assertNoSerializedNameCollisions(ir) {
4413
4462
  }
4414
4463
 
4415
4464
  // src/json-schema/ir-generator.ts
4465
+ function parseEnumSerialization(value) {
4466
+ switch (value) {
4467
+ case void 0:
4468
+ case "enum":
4469
+ return "enum";
4470
+ case "oneOf":
4471
+ return "oneOf";
4472
+ case "smart-size":
4473
+ return "smart-size";
4474
+ default:
4475
+ throw new Error(
4476
+ `Invalid enumSerialization "${String(value)}". Expected "enum", "oneOf", or "smart-size".`
4477
+ );
4478
+ }
4479
+ }
4416
4480
  function makeContext(options) {
4417
4481
  const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
4418
- const rawEnumSerialization = options?.enumSerialization;
4482
+ const enumSerialization = parseEnumSerialization(options?.enumSerialization);
4419
4483
  if (!vendorPrefix.startsWith("x-")) {
4420
4484
  throw new Error(
4421
4485
  `Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
4422
4486
  );
4423
4487
  }
4424
- if (rawEnumSerialization !== void 0 && rawEnumSerialization !== "enum" && rawEnumSerialization !== "oneOf") {
4425
- throw new Error(
4426
- `Invalid enumSerialization "${rawEnumSerialization}". Expected "enum" or "oneOf".`
4427
- );
4428
- }
4429
- const enumSerialization = rawEnumSerialization ?? "enum";
4430
4488
  return {
4431
4489
  defs: {},
4432
4490
  typeNameMap: {},
@@ -4634,7 +4692,7 @@ function generatePrimitiveType(type) {
4634
4692
  };
4635
4693
  }
4636
4694
  function generateEnumType(type, ctx) {
4637
- if (ctx.enumSerialization === "oneOf") {
4695
+ if (ctx.enumSerialization === "oneOf" || ctx.enumSerialization === "smart-size" && shouldSerializeEnumAsOneOf(type)) {
4638
4696
  return {
4639
4697
  oneOf: type.members.map((m) => {
4640
4698
  const stringValue = String(m.value);
@@ -4644,12 +4702,21 @@ function generateEnumType(type, ctx) {
4644
4702
  };
4645
4703
  }
4646
4704
  const schema = { enum: type.members.map((m) => m.value) };
4705
+ if (ctx.enumSerialization === "smart-size") {
4706
+ return schema;
4707
+ }
4647
4708
  const displayNames = buildEnumDisplayNameExtension(type);
4648
4709
  if (displayNames !== void 0) {
4649
4710
  schema[`${ctx.vendorPrefix}-display-names`] = displayNames;
4650
4711
  }
4651
4712
  return schema;
4652
4713
  }
4714
+ function shouldSerializeEnumAsOneOf(type) {
4715
+ return type.members.some((member) => {
4716
+ const title = member.displayName ?? String(member.value);
4717
+ return title !== String(member.value);
4718
+ });
4719
+ }
4653
4720
  function buildEnumDisplayNameExtension(type) {
4654
4721
  if (!type.members.some((member) => member.displayName !== void 0)) {
4655
4722
  return void 0;