@formspec/build 0.1.0-alpha.37 → 0.1.0-alpha.39

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.cjs CHANGED
@@ -37,10 +37,14 @@ __export(index_exports, {
37
37
  createStaticBuildContextFromProgram: () => createStaticBuildContextFromProgram,
38
38
  generateJsonSchema: () => generateJsonSchema,
39
39
  generateSchemas: () => generateSchemas,
40
+ generateSchemasBatch: () => generateSchemasBatch,
41
+ generateSchemasBatchFromProgram: () => generateSchemasBatchFromProgram,
42
+ generateSchemasDetailed: () => generateSchemasDetailed,
40
43
  generateSchemasFromClass: () => generateSchemasFromClass,
41
44
  generateSchemasFromDeclaration: () => generateSchemasFromDeclaration,
42
45
  generateSchemasFromParameter: () => generateSchemasFromParameter,
43
46
  generateSchemasFromProgram: () => generateSchemasFromProgram,
47
+ generateSchemasFromProgramDetailed: () => generateSchemasFromProgramDetailed,
44
48
  generateSchemasFromReturnType: () => generateSchemasFromReturnType,
45
49
  generateSchemasFromType: () => generateSchemasFromType,
46
50
  generateUiSchema: () => generateUiSchema,
@@ -2019,7 +2023,7 @@ var jsonSchema7Schema = import_zod3.z.lazy(
2019
2023
  );
2020
2024
 
2021
2025
  // src/generators/class-schema.ts
2022
- var ts5 = require("typescript");
2026
+ var ts5 = __toESM(require("typescript"), 1);
2023
2027
 
2024
2028
  // src/analyzer/program.ts
2025
2029
  var ts4 = __toESM(require("typescript"), 1);
@@ -2166,6 +2170,16 @@ function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
2166
2170
  return true;
2167
2171
  }).map((statement) => statement.getText(sourceFile));
2168
2172
  }
2173
+ function pushUniqueCompilerDiagnostics(target, additions) {
2174
+ for (const diagnostic of additions) {
2175
+ if ((diagnostic.code === "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" || diagnostic.code === "SYNTHETIC_SETUP_FAILURE") && target.some(
2176
+ (existing) => existing.code === diagnostic.code && existing.message === diagnostic.message
2177
+ )) {
2178
+ continue;
2179
+ }
2180
+ target.push(diagnostic);
2181
+ }
2182
+ }
2169
2183
  function renderSyntheticArgumentExpression(valueKind, argumentText) {
2170
2184
  const trimmed = argumentText.trim();
2171
2185
  if (trimmed === "") {
@@ -2432,6 +2446,16 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2432
2446
  if (result.diagnostics.length === 0) {
2433
2447
  return [];
2434
2448
  }
2449
+ const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
2450
+ if (setupDiagnostic !== void 0) {
2451
+ return [
2452
+ makeDiagnostic(
2453
+ setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
2454
+ setupDiagnostic.message,
2455
+ provenance
2456
+ )
2457
+ ];
2458
+ }
2435
2459
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
2436
2460
  return [
2437
2461
  makeDiagnostic(
@@ -2597,7 +2621,7 @@ function parseTSDocTags(node, file = "", options) {
2597
2621
  options
2598
2622
  );
2599
2623
  if (compilerDiagnostics.length > 0) {
2600
- diagnostics.push(...compilerDiagnostics);
2624
+ pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
2601
2625
  continue;
2602
2626
  }
2603
2627
  const constraintNode = (0, import_internal2.parseConstraintTagValue)(
@@ -2684,7 +2708,7 @@ function parseTSDocTags(node, file = "", options) {
2684
2708
  options
2685
2709
  );
2686
2710
  if (compilerDiagnostics.length > 0) {
2687
- diagnostics.push(...compilerDiagnostics);
2711
+ pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
2688
2712
  continue;
2689
2713
  }
2690
2714
  const constraintNode = (0, import_internal2.parseConstraintTagValue)(
@@ -2718,7 +2742,7 @@ function parseTSDocTags(node, file = "", options) {
2718
2742
  options
2719
2743
  );
2720
2744
  if (compilerDiagnostics.length > 0) {
2721
- diagnostics.push(...compilerDiagnostics);
2745
+ pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
2722
2746
  continue;
2723
2747
  }
2724
2748
  const constraintNode = (0, import_internal2.parseConstraintTagValue)(
@@ -5142,29 +5166,35 @@ function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPol
5142
5166
  discriminatorOptions
5143
5167
  );
5144
5168
  }
5145
- function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
5169
+ function analyzeNamedTypeToIRFromProgramContextDetailed(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
5146
5170
  const analysisFilePath = path.resolve(filePath);
5147
5171
  const classDecl = findClassByName(ctx.sourceFile, typeName);
5148
5172
  if (classDecl !== null) {
5149
- return analyzeClassToIR(
5150
- classDecl,
5151
- ctx.checker,
5152
- analysisFilePath,
5153
- extensionRegistry,
5154
- metadataPolicy,
5155
- discriminatorOptions
5156
- );
5173
+ return {
5174
+ ok: true,
5175
+ analysis: analyzeClassToIR(
5176
+ classDecl,
5177
+ ctx.checker,
5178
+ analysisFilePath,
5179
+ extensionRegistry,
5180
+ metadataPolicy,
5181
+ discriminatorOptions
5182
+ )
5183
+ };
5157
5184
  }
5158
5185
  const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
5159
5186
  if (interfaceDecl !== null) {
5160
- return analyzeInterfaceToIR(
5161
- interfaceDecl,
5162
- ctx.checker,
5163
- analysisFilePath,
5164
- extensionRegistry,
5165
- metadataPolicy,
5166
- discriminatorOptions
5167
- );
5187
+ return {
5188
+ ok: true,
5189
+ analysis: analyzeInterfaceToIR(
5190
+ interfaceDecl,
5191
+ ctx.checker,
5192
+ analysisFilePath,
5193
+ extensionRegistry,
5194
+ metadataPolicy,
5195
+ discriminatorOptions
5196
+ )
5197
+ };
5168
5198
  }
5169
5199
  const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
5170
5200
  if (typeAlias !== null) {
@@ -5177,11 +5207,20 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
5177
5207
  discriminatorOptions
5178
5208
  );
5179
5209
  if (result.ok) {
5180
- return result.analysis;
5210
+ return { ok: true, analysis: result.analysis };
5181
5211
  }
5182
5212
  const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
5183
5213
  if (!fallbackEligible) {
5184
- throw new Error(result.error);
5214
+ return {
5215
+ ok: false,
5216
+ diagnostics: [
5217
+ makeProgramDiagnostic(
5218
+ result.kind === "duplicate-properties" ? "DUPLICATE_ROOT_PROPERTIES" : "UNSUPPORTED_ROOT_TYPE",
5219
+ result.error,
5220
+ makeNodeProvenance(typeAlias, analysisFilePath)
5221
+ )
5222
+ ]
5223
+ };
5185
5224
  }
5186
5225
  const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
5187
5226
  typeAlias.type,
@@ -5190,9 +5229,16 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
5190
5229
  if (duplicatePropertyNames.length > 0) {
5191
5230
  const sourceFile = typeAlias.getSourceFile();
5192
5231
  const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
5193
- throw new Error(
5194
- `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
5195
- );
5232
+ return {
5233
+ ok: false,
5234
+ diagnostics: [
5235
+ makeProgramDiagnostic(
5236
+ "DUPLICATE_ROOT_PROPERTIES",
5237
+ `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`,
5238
+ makeNodeProvenance(typeAlias, analysisFilePath)
5239
+ )
5240
+ ]
5241
+ };
5196
5242
  }
5197
5243
  const rootInfo = analyzeDeclarationRootInfo(
5198
5244
  typeAlias,
@@ -5222,13 +5268,71 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
5222
5268
  diagnostics
5223
5269
  );
5224
5270
  if (fallbackAnalysis !== null) {
5225
- return fallbackAnalysis;
5271
+ return { ok: true, analysis: fallbackAnalysis };
5226
5272
  }
5227
- throw new Error(result.error);
5273
+ return {
5274
+ ok: false,
5275
+ diagnostics: [
5276
+ makeProgramDiagnostic(
5277
+ "UNSUPPORTED_ROOT_TYPE",
5278
+ result.error,
5279
+ makeNodeProvenance(typeAlias, analysisFilePath)
5280
+ )
5281
+ ]
5282
+ };
5228
5283
  }
5229
- throw new Error(
5230
- `Type "${typeName}" not found as a class, interface, or type alias in ${analysisFilePath}`
5284
+ return {
5285
+ ok: false,
5286
+ diagnostics: [
5287
+ makeProgramDiagnostic(
5288
+ "TYPE_NOT_FOUND",
5289
+ `Type "${typeName}" not found as a class, interface, or type alias in ${analysisFilePath}`,
5290
+ makeFileProvenance(analysisFilePath)
5291
+ )
5292
+ ]
5293
+ };
5294
+ }
5295
+ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
5296
+ const result = analyzeNamedTypeToIRFromProgramContextDetailed(
5297
+ ctx,
5298
+ filePath,
5299
+ typeName,
5300
+ extensionRegistry,
5301
+ metadataPolicy,
5302
+ discriminatorOptions
5231
5303
  );
5304
+ if (result.ok) {
5305
+ return result.analysis;
5306
+ }
5307
+ throw new Error(result.diagnostics.map((diagnostic) => diagnostic.message).join("\n"));
5308
+ }
5309
+ function makeProgramDiagnostic(code, message, primaryLocation) {
5310
+ return {
5311
+ code,
5312
+ message,
5313
+ severity: "error",
5314
+ primaryLocation,
5315
+ relatedLocations: []
5316
+ };
5317
+ }
5318
+ function makeNodeProvenance(node, filePath) {
5319
+ const sourceFile = node.getSourceFile();
5320
+ const position = sourceFile.getLineAndCharacterOfPosition(node.getStart());
5321
+ return {
5322
+ surface: "tsdoc",
5323
+ file: filePath,
5324
+ line: position.line + 1,
5325
+ column: position.character,
5326
+ length: node.getWidth()
5327
+ };
5328
+ }
5329
+ function makeFileProvenance(filePath) {
5330
+ return {
5331
+ surface: "tsdoc",
5332
+ file: filePath,
5333
+ line: 1,
5334
+ column: 0
5335
+ };
5232
5336
  }
5233
5337
 
5234
5338
  // src/validate/constraint-validator.ts
@@ -5306,11 +5410,25 @@ function validateIR(ir, options) {
5306
5410
 
5307
5411
  // src/generators/class-schema.ts
5308
5412
  function generateClassSchemas(analysis, source, options) {
5309
- const errorDiagnostics = analysis.diagnostics?.filter(
5413
+ const result = generateClassSchemasDetailed(analysis, source, options);
5414
+ if (!result.ok || result.jsonSchema === void 0 || result.uiSchema === void 0) {
5415
+ throw new Error(formatValidationError(result.diagnostics));
5416
+ }
5417
+ return {
5418
+ jsonSchema: result.jsonSchema,
5419
+ uiSchema: result.uiSchema
5420
+ };
5421
+ }
5422
+ function generateClassSchemasDetailed(analysis, source, options) {
5423
+ const analysisDiagnostics = analysis.diagnostics ?? [];
5424
+ const errorDiagnostics = analysisDiagnostics.filter(
5310
5425
  (diagnostic) => diagnostic.severity === "error"
5311
5426
  );
5312
- if (errorDiagnostics !== void 0 && errorDiagnostics.length > 0) {
5313
- throw new Error(formatValidationError(errorDiagnostics));
5427
+ if (errorDiagnostics.length > 0) {
5428
+ return {
5429
+ ok: false,
5430
+ diagnostics: analysisDiagnostics
5431
+ };
5314
5432
  }
5315
5433
  const ir = canonicalizeTSDoc(
5316
5434
  analysis,
@@ -5324,9 +5442,14 @@ function generateClassSchemas(analysis, source, options) {
5324
5442
  ...options?.vendorPrefix !== void 0 && { vendorPrefix: options.vendorPrefix }
5325
5443
  });
5326
5444
  if (!validationResult.valid) {
5327
- throw new Error(formatValidationError(validationResult.diagnostics));
5445
+ return {
5446
+ ok: false,
5447
+ diagnostics: [...analysisDiagnostics, ...validationResult.diagnostics]
5448
+ };
5328
5449
  }
5329
5450
  return {
5451
+ ok: true,
5452
+ diagnostics: [...analysisDiagnostics, ...validationResult.diagnostics],
5330
5453
  jsonSchema: generateJsonSchemaFromIR(ir, options),
5331
5454
  uiSchema: generateUiSchemaFromIR(ir)
5332
5455
  };
@@ -5368,25 +5491,127 @@ function generateSchemasFromClass(options) {
5368
5491
  );
5369
5492
  }
5370
5493
  function generateSchemas(options) {
5371
- const ctx = createProgramContext(options.filePath);
5494
+ const result = generateSchemasDetailedInternal(options);
5495
+ if (options.errorReporting === "diagnostics") {
5496
+ return result;
5497
+ }
5498
+ if (!result.ok || result.jsonSchema === void 0 || result.uiSchema === void 0) {
5499
+ throw new Error(formatValidationError(result.diagnostics));
5500
+ }
5501
+ return {
5502
+ jsonSchema: result.jsonSchema,
5503
+ uiSchema: result.uiSchema
5504
+ };
5505
+ }
5506
+ function generateSchemasFromProgram(options) {
5507
+ const result = generateSchemasFromProgramDetailedInternal(options);
5508
+ if (options.errorReporting === "diagnostics") {
5509
+ return result;
5510
+ }
5511
+ if (!result.ok || result.jsonSchema === void 0 || result.uiSchema === void 0) {
5512
+ throw new Error(formatValidationError(result.diagnostics));
5513
+ }
5514
+ return {
5515
+ jsonSchema: result.jsonSchema,
5516
+ uiSchema: result.uiSchema
5517
+ };
5518
+ }
5519
+ function generateSchemasDetailed(options) {
5520
+ return generateSchemas({
5521
+ ...options,
5522
+ errorReporting: "diagnostics"
5523
+ });
5524
+ }
5525
+ function generateSchemasDetailedInternal(options) {
5526
+ let ctx;
5527
+ try {
5528
+ ctx = createProgramContext(options.filePath);
5529
+ } catch (error) {
5530
+ return {
5531
+ ok: false,
5532
+ diagnostics: [createProgramContextFailureDiagnostic(options.filePath, error)]
5533
+ };
5534
+ }
5535
+ return generateSchemasFromDetailedProgramContext(ctx, options.filePath, options.typeName, options);
5536
+ }
5537
+ function generateSchemasFromProgramDetailed(options) {
5372
5538
  return generateSchemasFromProgram({
5373
5539
  ...options,
5374
- program: ctx.program
5540
+ errorReporting: "diagnostics"
5375
5541
  });
5376
5542
  }
5377
- function generateSchemasFromProgram(options) {
5378
- const ctx = createProgramContextFromProgram(options.program, options.filePath);
5379
- const analysis = analyzeNamedTypeToIRFromProgramContext(
5543
+ function generateSchemasFromProgramDetailedInternal(options) {
5544
+ let ctx;
5545
+ try {
5546
+ ctx = createProgramContextFromProgram(options.program, options.filePath);
5547
+ } catch (error) {
5548
+ return {
5549
+ ok: false,
5550
+ diagnostics: [createProgramContextFailureDiagnostic(options.filePath, error)]
5551
+ };
5552
+ }
5553
+ return generateSchemasFromDetailedProgramContext(ctx, options.filePath, options.typeName, options);
5554
+ }
5555
+ function generateSchemasBatch(options) {
5556
+ const contextCache = /* @__PURE__ */ new Map();
5557
+ return options.targets.map((target) => {
5558
+ let ctx;
5559
+ try {
5560
+ const cacheKey = ts5.sys.useCaseSensitiveFileNames ? target.filePath : target.filePath.toLowerCase();
5561
+ const cachedContext = contextCache.get(cacheKey);
5562
+ if (cachedContext === void 0) {
5563
+ ctx = createProgramContext(target.filePath);
5564
+ contextCache.set(cacheKey, ctx);
5565
+ } else {
5566
+ ctx = cachedContext;
5567
+ }
5568
+ } catch (error) {
5569
+ return withTarget(target, {
5570
+ ok: false,
5571
+ diagnostics: [createProgramContextFailureDiagnostic(target.filePath, error)]
5572
+ });
5573
+ }
5574
+ return withTarget(
5575
+ target,
5576
+ generateSchemasFromDetailedProgramContext(ctx, target.filePath, target.typeName, options)
5577
+ );
5578
+ });
5579
+ }
5580
+ function generateSchemasBatchFromProgram(options) {
5581
+ return options.targets.map((target) => {
5582
+ let ctx;
5583
+ try {
5584
+ ctx = createProgramContextFromProgram(options.program, target.filePath);
5585
+ } catch (error) {
5586
+ return withTarget(target, {
5587
+ ok: false,
5588
+ diagnostics: [createProgramContextFailureDiagnostic(target.filePath, error)]
5589
+ });
5590
+ }
5591
+ return withTarget(
5592
+ target,
5593
+ generateSchemasFromDetailedProgramContext(ctx, target.filePath, target.typeName, options)
5594
+ );
5595
+ });
5596
+ }
5597
+ function generateSchemasFromDetailedProgramContext(ctx, filePath, typeName, options) {
5598
+ const analysisResult = analyzeNamedTypeToIRFromProgramContextDetailed(
5380
5599
  ctx,
5381
- options.filePath,
5382
- options.typeName,
5600
+ filePath,
5601
+ typeName,
5383
5602
  options.extensionRegistry,
5384
5603
  options.metadata,
5385
5604
  options.discriminator
5386
5605
  );
5387
- return generateClassSchemas(
5388
- analysis,
5389
- { file: options.filePath },
5606
+ if (!analysisResult.ok) {
5607
+ return {
5608
+ ok: false,
5609
+ diagnostics: analysisResult.diagnostics
5610
+ };
5611
+ }
5612
+ return generateClassSchemasDetailed(
5613
+ analysisResult.analysis,
5614
+ { file: filePath },
5390
5615
  {
5391
5616
  extensionRegistry: options.extensionRegistry,
5392
5617
  metadata: options.metadata,
@@ -5394,6 +5619,27 @@ function generateSchemasFromProgram(options) {
5394
5619
  }
5395
5620
  );
5396
5621
  }
5622
+ function withTarget(target, result) {
5623
+ return {
5624
+ filePath: target.filePath,
5625
+ typeName: target.typeName,
5626
+ ...result
5627
+ };
5628
+ }
5629
+ function createProgramContextFailureDiagnostic(filePath, error) {
5630
+ return {
5631
+ code: "PROGRAM_CONTEXT_FAILURE",
5632
+ message: error instanceof Error ? error.message : String(error),
5633
+ severity: "error",
5634
+ primaryLocation: {
5635
+ surface: "tsdoc",
5636
+ file: filePath,
5637
+ line: 1,
5638
+ column: 0
5639
+ },
5640
+ relatedLocations: []
5641
+ };
5642
+ }
5397
5643
 
5398
5644
  // src/static-build.ts
5399
5645
  var ts6 = __toESM(require("typescript"), 1);
@@ -5431,8 +5677,11 @@ function resolveModuleExportDeclaration(context, exportName = "default") {
5431
5677
  // src/generators/discovered-schema.ts
5432
5678
  var ts7 = __toESM(require("typescript"), 1);
5433
5679
  var import_internals6 = require("@formspec/core/internals");
5434
- function toDiscoveredTypeSchemas(result) {
5435
- return result;
5680
+ function toDiscoveredTypeSchemas(result, resolvedMetadata) {
5681
+ return {
5682
+ ...result,
5683
+ ...resolvedMetadata !== void 0 && { resolvedMetadata }
5684
+ };
5436
5685
  }
5437
5686
  function isNamedTypeDeclaration(declaration) {
5438
5687
  return ts7.isClassDeclaration(declaration) || ts7.isInterfaceDeclaration(declaration) || ts7.isTypeAliasDeclaration(declaration);
@@ -5580,7 +5829,8 @@ function generateSchemasFromAnalysis(analysis, filePath, options) {
5580
5829
  metadata: options?.metadata,
5581
5830
  vendorPrefix: options?.vendorPrefix
5582
5831
  }
5583
- )
5832
+ ),
5833
+ analysis.metadata
5584
5834
  );
5585
5835
  }
5586
5836
  function generateSchemasFromResolvedType(options, skipNamedDeclaration = false, rootOverride) {
@@ -5638,7 +5888,8 @@ function generateSchemasFromResolvedType(options, skipNamedDeclaration = false,
5638
5888
  }
5639
5889
  return {
5640
5890
  jsonSchema: toStandaloneJsonSchema(root, typeRegistry, options),
5641
- uiSchema: null
5891
+ uiSchema: null,
5892
+ ...root.metadata !== void 0 && { resolvedMetadata: root.metadata }
5642
5893
  };
5643
5894
  }
5644
5895
  function generateSchemasFromDeclaration(options) {
@@ -5978,10 +6229,14 @@ function writeSchemas(form, options) {
5978
6229
  createStaticBuildContextFromProgram,
5979
6230
  generateJsonSchema,
5980
6231
  generateSchemas,
6232
+ generateSchemasBatch,
6233
+ generateSchemasBatchFromProgram,
6234
+ generateSchemasDetailed,
5981
6235
  generateSchemasFromClass,
5982
6236
  generateSchemasFromDeclaration,
5983
6237
  generateSchemasFromParameter,
5984
6238
  generateSchemasFromProgram,
6239
+ generateSchemasFromProgramDetailed,
5985
6240
  generateSchemasFromReturnType,
5986
6241
  generateSchemasFromType,
5987
6242
  generateUiSchema,