@formspec/build 0.1.0-alpha.31 → 0.1.0-alpha.33

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
@@ -33,12 +33,20 @@ __export(index_exports, {
33
33
  buildFormSchemas: () => buildFormSchemas,
34
34
  buildMixedAuthoringSchemas: () => buildMixedAuthoringSchemas,
35
35
  createExtensionRegistry: () => createExtensionRegistry,
36
+ createStaticBuildContext: () => createStaticBuildContext,
37
+ createStaticBuildContextFromProgram: () => createStaticBuildContextFromProgram,
36
38
  generateJsonSchema: () => generateJsonSchema,
37
39
  generateSchemas: () => generateSchemas,
38
40
  generateSchemasFromClass: () => generateSchemasFromClass,
41
+ generateSchemasFromDeclaration: () => generateSchemasFromDeclaration,
42
+ generateSchemasFromParameter: () => generateSchemasFromParameter,
39
43
  generateSchemasFromProgram: () => generateSchemasFromProgram,
44
+ generateSchemasFromReturnType: () => generateSchemasFromReturnType,
45
+ generateSchemasFromType: () => generateSchemasFromType,
40
46
  generateUiSchema: () => generateUiSchema,
41
47
  jsonSchema7Schema: () => jsonSchema7Schema,
48
+ resolveModuleExport: () => resolveModuleExport,
49
+ resolveModuleExportDeclaration: () => resolveModuleExportDeclaration,
42
50
  uiSchemaSchema: () => uiSchema,
43
51
  writeSchemas: () => writeSchemas
44
52
  });
@@ -1811,13 +1819,29 @@ var fs = __toESM(require("fs"), 1);
1811
1819
  var path2 = __toESM(require("path"), 1);
1812
1820
 
1813
1821
  // src/extensions/registry.ts
1822
+ var import_internals3 = require("@formspec/core/internals");
1823
+ var import_internal = require("@formspec/analysis/internal");
1824
+ var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
1825
+ function buildConstraintTagSources(extensions) {
1826
+ return extensions.map((extension) => ({
1827
+ extensionId: extension.extensionId,
1828
+ ...extension.constraintTags !== void 0 ? {
1829
+ constraintTags: extension.constraintTags.map((tag) => ({
1830
+ tagName: (0, import_internal.normalizeFormSpecTagName)(tag.tagName)
1831
+ }))
1832
+ } : {}
1833
+ }));
1834
+ }
1814
1835
  function createExtensionRegistry(extensions) {
1836
+ const reservedTagSources = buildConstraintTagSources(extensions);
1815
1837
  const typeMap = /* @__PURE__ */ new Map();
1816
1838
  const typeNameMap = /* @__PURE__ */ new Map();
1817
1839
  const constraintMap = /* @__PURE__ */ new Map();
1818
1840
  const constraintTagMap = /* @__PURE__ */ new Map();
1819
1841
  const builtinBroadeningMap = /* @__PURE__ */ new Map();
1820
1842
  const annotationMap = /* @__PURE__ */ new Map();
1843
+ const metadataSlotMap = /* @__PURE__ */ new Map();
1844
+ const metadataTagMap = /* @__PURE__ */ new Map();
1821
1845
  for (const ext of extensions) {
1822
1846
  if (ext.types !== void 0) {
1823
1847
  for (const type of ext.types) {
@@ -1860,10 +1884,11 @@ function createExtensionRegistry(extensions) {
1860
1884
  }
1861
1885
  if (ext.constraintTags !== void 0) {
1862
1886
  for (const tag of ext.constraintTags) {
1863
- if (constraintTagMap.has(tag.tagName)) {
1864
- throw new Error(`Duplicate custom constraint tag: "@${tag.tagName}"`);
1887
+ const canonicalTagName = (0, import_internal.normalizeFormSpecTagName)(tag.tagName);
1888
+ if (constraintTagMap.has(canonicalTagName)) {
1889
+ throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
1865
1890
  }
1866
- constraintTagMap.set(tag.tagName, {
1891
+ constraintTagMap.set(canonicalTagName, {
1867
1892
  extensionId: ext.extensionId,
1868
1893
  registration: tag
1869
1894
  });
@@ -1878,13 +1903,54 @@ function createExtensionRegistry(extensions) {
1878
1903
  annotationMap.set(qualifiedId, annotation);
1879
1904
  }
1880
1905
  }
1906
+ if (ext.metadataSlots !== void 0) {
1907
+ for (const slot of ext.metadataSlots) {
1908
+ if (metadataSlotMap.has(slot.slotId)) {
1909
+ throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
1910
+ }
1911
+ metadataSlotMap.set(slot.slotId, true);
1912
+ const canonicalTagName = (0, import_internal.normalizeFormSpecTagName)(slot.tagName);
1913
+ if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
1914
+ throw new Error(
1915
+ `Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
1916
+ );
1917
+ }
1918
+ if (metadataTagMap.has(canonicalTagName)) {
1919
+ throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
1920
+ }
1921
+ if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
1922
+ throw new Error(
1923
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
1924
+ );
1925
+ }
1926
+ if (constraintTagMap.has(canonicalTagName)) {
1927
+ throw new Error(
1928
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
1929
+ );
1930
+ }
1931
+ if (Object.hasOwn(import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals3.normalizeConstraintTagName)(canonicalTagName))) {
1932
+ throw new Error(
1933
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals3.normalizeConstraintTagName)(canonicalTagName)}".`
1934
+ );
1935
+ }
1936
+ const existingTag = (0, import_internal.getTagDefinition)(canonicalTagName, reservedTagSources);
1937
+ if (existingTag !== null) {
1938
+ throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
1939
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
1940
+ ) : new Error(
1941
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
1942
+ );
1943
+ }
1944
+ metadataTagMap.set(canonicalTagName, true);
1945
+ }
1946
+ }
1881
1947
  }
1882
1948
  return {
1883
1949
  extensions,
1884
1950
  findType: (typeId) => typeMap.get(typeId),
1885
1951
  findTypeByName: (typeName) => typeNameMap.get(typeName),
1886
1952
  findConstraint: (constraintId) => constraintMap.get(constraintId),
1887
- findConstraintTag: (tagName) => constraintTagMap.get(tagName),
1953
+ findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal.normalizeFormSpecTagName)(tagName)),
1888
1954
  findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
1889
1955
  findAnnotation: (annotationId) => annotationMap.get(annotationId)
1890
1956
  };
@@ -1961,21 +2027,21 @@ var path = __toESM(require("path"), 1);
1961
2027
 
1962
2028
  // src/analyzer/class-analyzer.ts
1963
2029
  var ts3 = __toESM(require("typescript"), 1);
1964
- var import_internal2 = require("@formspec/analysis/internal");
2030
+ var import_internal3 = require("@formspec/analysis/internal");
1965
2031
 
1966
2032
  // src/analyzer/jsdoc-constraints.ts
1967
2033
  var ts2 = __toESM(require("typescript"), 1);
1968
2034
 
1969
2035
  // src/analyzer/tsdoc-parser.ts
1970
2036
  var ts = __toESM(require("typescript"), 1);
1971
- var import_internal = require("@formspec/analysis/internal");
2037
+ var import_internal2 = require("@formspec/analysis/internal");
1972
2038
  var import_tsdoc = require("@microsoft/tsdoc");
1973
- var import_internals3 = require("@formspec/core/internals");
1974
2039
  var import_internals4 = require("@formspec/core/internals");
2040
+ var import_internals5 = require("@formspec/core/internals");
1975
2041
  var TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["pattern", "enumOptions", "defaultValue"]);
1976
2042
  function createFormSpecTSDocConfig(extensionTagNames = []) {
1977
2043
  const config = new import_tsdoc.TSDocConfiguration();
1978
- for (const tagName of Object.keys(import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS)) {
2044
+ for (const tagName of Object.keys(import_internals4.BUILTIN_CONSTRAINT_DEFINITIONS)) {
1979
2045
  config.addTagDefinition(
1980
2046
  new import_tsdoc.TSDocTagDefinition({
1981
2047
  tagName: "@" + tagName,
@@ -1984,7 +2050,7 @@ function createFormSpecTSDocConfig(extensionTagNames = []) {
1984
2050
  })
1985
2051
  );
1986
2052
  }
1987
- for (const tagName of ["displayName", "format", "placeholder"]) {
2053
+ for (const tagName of ["apiName", "displayName", "format", "placeholder"]) {
1988
2054
  config.addTagDefinition(
1989
2055
  new import_tsdoc.TSDocTagDefinition({
1990
2056
  tagName: "@" + tagName,
@@ -2018,6 +2084,16 @@ function sharedTagValueOptions(options) {
2018
2084
  };
2019
2085
  }
2020
2086
  var SYNTHETIC_TYPE_FORMAT_FLAGS = ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope;
2087
+ function getExtensionTypeNames(registry) {
2088
+ if (registry === void 0) {
2089
+ return /* @__PURE__ */ new Set();
2090
+ }
2091
+ return new Set(
2092
+ registry.extensions.flatMap(
2093
+ (ext) => (ext.types ?? []).flatMap((t) => t.tsTypeNames ?? [t.typeName])
2094
+ )
2095
+ );
2096
+ }
2021
2097
  function collectImportedNames(sourceFile) {
2022
2098
  const importedNames = /* @__PURE__ */ new Set();
2023
2099
  for (const statement of sourceFile.statements) {
@@ -2057,6 +2133,9 @@ function isNonReferenceIdentifier(node) {
2057
2133
  return false;
2058
2134
  }
2059
2135
  function statementReferencesImportedName(statement, importedNames) {
2136
+ if (importedNames.size === 0) {
2137
+ return false;
2138
+ }
2060
2139
  let referencesImportedName = false;
2061
2140
  const visit = (node) => {
2062
2141
  if (referencesImportedName) {
@@ -2071,14 +2150,17 @@ function statementReferencesImportedName(statement, importedNames) {
2071
2150
  visit(statement);
2072
2151
  return referencesImportedName;
2073
2152
  }
2074
- function buildSupportingDeclarations(sourceFile) {
2153
+ function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
2075
2154
  const importedNames = collectImportedNames(sourceFile);
2155
+ const importedNamesToSkip = new Set(
2156
+ [...importedNames].filter((name) => !extensionTypeNames.has(name))
2157
+ );
2076
2158
  return sourceFile.statements.filter((statement) => {
2077
2159
  if (ts.isImportDeclaration(statement)) return false;
2078
2160
  if (ts.isImportEqualsDeclaration(statement)) return false;
2079
2161
  if (ts.isExportDeclaration(statement) && statement.moduleSpecifier !== void 0)
2080
2162
  return false;
2081
- if (importedNames.size > 0 && statementReferencesImportedName(statement, importedNames)) {
2163
+ if (statementReferencesImportedName(statement, importedNamesToSkip)) {
2082
2164
  return false;
2083
2165
  }
2084
2166
  return true;
@@ -2124,12 +2206,12 @@ function supportsConstraintCapability(type, checker, capability) {
2124
2206
  if (capability === void 0) {
2125
2207
  return true;
2126
2208
  }
2127
- if ((0, import_internal.hasTypeSemanticCapability)(type, checker, capability)) {
2209
+ if ((0, import_internal2.hasTypeSemanticCapability)(type, checker, capability)) {
2128
2210
  return true;
2129
2211
  }
2130
2212
  if (capability === "string-like") {
2131
2213
  const itemType = getArrayElementType(type, checker);
2132
- return itemType !== null && (0, import_internal.hasTypeSemanticCapability)(itemType, checker, capability);
2214
+ return itemType !== null && (0, import_internal2.hasTypeSemanticCapability)(itemType, checker, capability);
2133
2215
  }
2134
2216
  return false;
2135
2217
  }
@@ -2219,7 +2301,7 @@ function hasBuiltinConstraintBroadening(tagName, options) {
2219
2301
  return broadenedTypeId !== void 0 && options?.extensionRegistry?.findBuiltinConstraintBroadening(broadenedTypeId, tagName) !== void 0;
2220
2302
  }
2221
2303
  function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, parsedTag, provenance, supportingDeclarations, options) {
2222
- if (!(0, import_internals3.isBuiltinConstraintName)(tagName)) {
2304
+ if (!(0, import_internals4.isBuiltinConstraintName)(tagName)) {
2223
2305
  return [];
2224
2306
  }
2225
2307
  const checker = options?.checker;
@@ -2227,11 +2309,11 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2227
2309
  if (checker === void 0 || subjectType === void 0) {
2228
2310
  return [];
2229
2311
  }
2230
- const placement = (0, import_internal.resolveDeclarationPlacement)(node);
2312
+ const placement = (0, import_internal2.resolveDeclarationPlacement)(node);
2231
2313
  if (placement === null) {
2232
2314
  return [];
2233
2315
  }
2234
- const definition = (0, import_internal.getTagDefinition)(tagName, options?.extensionRegistry?.extensions);
2316
+ const definition = (0, import_internal2.getTagDefinition)(tagName, options?.extensionRegistry?.extensions);
2235
2317
  if (definition === null) {
2236
2318
  return [];
2237
2319
  }
@@ -2265,7 +2347,7 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2265
2347
  )
2266
2348
  ];
2267
2349
  }
2268
- const resolution = (0, import_internal.resolvePathTargetType)(subjectType, checker, target.path.segments);
2350
+ const resolution = (0, import_internal2.resolvePathTargetType)(subjectType, checker, target.path.segments);
2269
2351
  if (resolution.kind === "missing-property") {
2270
2352
  return [
2271
2353
  makeDiagnostic(
@@ -2322,7 +2404,7 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2322
2404
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2323
2405
  const hostType = options?.hostType ?? subjectType;
2324
2406
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2325
- const result = (0, import_internal.checkSyntheticTagApplication)({
2407
+ const result = (0, import_internal2.checkSyntheticTagApplication)({
2326
2408
  tagName,
2327
2409
  placement,
2328
2410
  hostType: hostTypeText,
@@ -2335,6 +2417,14 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2335
2417
  extensionId: extension.extensionId,
2336
2418
  ...extension.constraintTags !== void 0 ? {
2337
2419
  constraintTags: extension.constraintTags.map((tag) => ({ tagName: tag.tagName }))
2420
+ } : {},
2421
+ ...extension.metadataSlots !== void 0 ? {
2422
+ metadataSlots: extension.metadataSlots
2423
+ } : {},
2424
+ ...extension.types !== void 0 ? {
2425
+ customTypes: extension.types.map((t) => ({
2426
+ tsTypeNames: t.tsTypeNames ?? [t.typeName]
2427
+ }))
2338
2428
  } : {}
2339
2429
  }))
2340
2430
  } : {}
@@ -2356,7 +2446,10 @@ var parseResultCache = /* @__PURE__ */ new Map();
2356
2446
  function getParser(options) {
2357
2447
  const extensionTagNames = [
2358
2448
  ...options?.extensionRegistry?.extensions.flatMap(
2359
- (extension) => (extension.constraintTags ?? []).map((tag) => tag.tagName)
2449
+ (extension) => (extension.constraintTags ?? []).map((tag) => (0, import_internal2.normalizeFormSpecTagName)(tag.tagName))
2450
+ ) ?? [],
2451
+ ...options?.extensionRegistry?.extensions.flatMap(
2452
+ (extension) => (extension.metadataSlots ?? []).map((slot) => (0, import_internal2.normalizeFormSpecTagName)(slot.tagName))
2360
2453
  ) ?? []
2361
2454
  ].sort();
2362
2455
  const cacheKey = extensionTagNames.join("|");
@@ -2376,7 +2469,16 @@ function getExtensionRegistryCacheKey(registry) {
2376
2469
  (extension) => JSON.stringify({
2377
2470
  extensionId: extension.extensionId,
2378
2471
  typeNames: extension.types?.map((type) => type.typeName) ?? [],
2379
- constraintTags: extension.constraintTags?.map((tag) => tag.tagName) ?? []
2472
+ constraintTags: extension.constraintTags?.map((tag) => (0, import_internal2.normalizeFormSpecTagName)(tag.tagName)) ?? [],
2473
+ metadataSlots: extension.metadataSlots?.map((slot) => ({
2474
+ tagName: (0, import_internal2.normalizeFormSpecTagName)(slot.tagName),
2475
+ declarationKinds: [...slot.declarationKinds].sort(),
2476
+ allowBare: slot.allowBare !== false,
2477
+ qualifiers: (slot.qualifiers ?? []).map((qualifier) => ({
2478
+ qualifier: qualifier.qualifier,
2479
+ ...qualifier.sourceQualifier !== void 0 ? { sourceQualifier: qualifier.sourceQualifier } : {}
2480
+ })).sort((left, right) => left.qualifier.localeCompare(right.qualifier))
2481
+ })) ?? []
2380
2482
  })
2381
2483
  ).join("|");
2382
2484
  }
@@ -2411,7 +2513,8 @@ function parseTSDocTags(node, file = "", options) {
2411
2513
  const rawTextTags = [];
2412
2514
  const sourceFile = node.getSourceFile();
2413
2515
  const sourceText = sourceFile.getFullText();
2414
- const supportingDeclarations = buildSupportingDeclarations(sourceFile);
2516
+ const extensionTypeNames = getExtensionTypeNames(options?.extensionRegistry);
2517
+ const supportingDeclarations = buildSupportingDeclarations(sourceFile, extensionTypeNames);
2415
2518
  const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
2416
2519
  const rawTextFallbacks = collectRawTextFallbacks(node, file);
2417
2520
  if (commentRanges) {
@@ -2428,7 +2531,7 @@ function parseTSDocTags(node, file = "", options) {
2428
2531
  import_tsdoc.TextRange.fromStringRange(sourceText, range.pos, range.end)
2429
2532
  );
2430
2533
  const docComment = parserContext.docComment;
2431
- const parsedComment = (0, import_internal.parseCommentBlock)(
2534
+ const parsedComment = (0, import_internal2.parseCommentBlock)(
2432
2535
  commentText,
2433
2536
  sharedCommentSyntaxOptions(options, range.pos)
2434
2537
  );
@@ -2449,7 +2552,7 @@ function parseTSDocTags(node, file = "", options) {
2449
2552
  }
2450
2553
  }
2451
2554
  for (const block of docComment.customBlocks) {
2452
- const tagName = (0, import_internals3.normalizeConstraintTagName)(block.blockTag.tagName.substring(1));
2555
+ const tagName = (0, import_internals4.normalizeConstraintTagName)(block.blockTag.tagName.substring(1));
2453
2556
  const parsedTag = nextParsedTag(tagName);
2454
2557
  if (tagName === "displayName" || tagName === "format" || tagName === "placeholder") {
2455
2558
  const text2 = getBestBlockPayloadText(parsedTag, commentText, range.pos, block);
@@ -2481,7 +2584,7 @@ function parseTSDocTags(node, file = "", options) {
2481
2584
  }
2482
2585
  if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
2483
2586
  const text = getBestBlockPayloadText(parsedTag, commentText, range.pos, block);
2484
- const expectedType = (0, import_internals3.isBuiltinConstraintName)(tagName) ? import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS[tagName] : void 0;
2587
+ const expectedType = (0, import_internals4.isBuiltinConstraintName)(tagName) ? import_internals4.BUILTIN_CONSTRAINT_DEFINITIONS[tagName] : void 0;
2485
2588
  if (text === "" && expectedType !== "boolean") continue;
2486
2589
  const provenance = parsedTag !== null ? provenanceForParsedTag(parsedTag, sourceFile, file) : provenanceForComment(range, sourceFile, file, tagName);
2487
2590
  const compilerDiagnostics = buildCompilerBackedConstraintDiagnostics(
@@ -2497,7 +2600,7 @@ function parseTSDocTags(node, file = "", options) {
2497
2600
  diagnostics.push(...compilerDiagnostics);
2498
2601
  continue;
2499
2602
  }
2500
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
2603
+ const constraintNode = (0, import_internal2.parseConstraintTagValue)(
2501
2604
  tagName,
2502
2605
  text,
2503
2606
  provenance,
@@ -2567,7 +2670,7 @@ function parseTSDocTags(node, file = "", options) {
2567
2670
  if (text === "") continue;
2568
2671
  const provenance = provenanceForParsedTag(rawTextTag.tag, sourceFile, file);
2569
2672
  if (rawTextTag.tag.normalizedTagName === "defaultValue") {
2570
- const defaultValueNode = (0, import_internal.parseDefaultValueTagValue)(text, provenance);
2673
+ const defaultValueNode = (0, import_internal2.parseDefaultValueTagValue)(text, provenance);
2571
2674
  annotations.push(defaultValueNode);
2572
2675
  continue;
2573
2676
  }
@@ -2584,7 +2687,7 @@ function parseTSDocTags(node, file = "", options) {
2584
2687
  diagnostics.push(...compilerDiagnostics);
2585
2688
  continue;
2586
2689
  }
2587
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
2690
+ const constraintNode = (0, import_internal2.parseConstraintTagValue)(
2588
2691
  rawTextTag.tag.normalizedTagName,
2589
2692
  text,
2590
2693
  provenance,
@@ -2601,7 +2704,7 @@ function parseTSDocTags(node, file = "", options) {
2601
2704
  if (text === "") continue;
2602
2705
  const provenance = fallback.provenance;
2603
2706
  if (tagName === "defaultValue") {
2604
- const defaultValueNode = (0, import_internal.parseDefaultValueTagValue)(text, provenance);
2707
+ const defaultValueNode = (0, import_internal2.parseDefaultValueTagValue)(text, provenance);
2605
2708
  annotations.push(defaultValueNode);
2606
2709
  continue;
2607
2710
  }
@@ -2618,7 +2721,7 @@ function parseTSDocTags(node, file = "", options) {
2618
2721
  diagnostics.push(...compilerDiagnostics);
2619
2722
  continue;
2620
2723
  }
2621
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
2724
+ const constraintNode = (0, import_internal2.parseConstraintTagValue)(
2622
2725
  tagName,
2623
2726
  text,
2624
2727
  provenance,
@@ -2644,7 +2747,7 @@ function extractDisplayNameMetadata(node) {
2644
2747
  if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) continue;
2645
2748
  const commentText = sourceText.substring(range.pos, range.end);
2646
2749
  if (!commentText.startsWith("/**")) continue;
2647
- const parsed = (0, import_internal.parseCommentBlock)(commentText);
2750
+ const parsed = (0, import_internal2.parseCommentBlock)(commentText);
2648
2751
  for (const tag of parsed.tags) {
2649
2752
  if (tag.normalizedTagName !== "displayName") {
2650
2753
  continue;
@@ -2700,7 +2803,7 @@ function getSharedPayloadText(tag, commentText, commentOffset) {
2700
2803
  if (tag.payloadSpan === null) {
2701
2804
  return "";
2702
2805
  }
2703
- return (0, import_internal.sliceCommentSpan)(commentText, tag.payloadSpan, {
2806
+ return (0, import_internal2.sliceCommentSpan)(commentText, tag.payloadSpan, {
2704
2807
  offset: commentOffset
2705
2808
  }).trim();
2706
2809
  }
@@ -2712,7 +2815,7 @@ function getBestBlockPayloadText(tag, commentText, commentOffset, block) {
2712
2815
  function collectRawTextFallbacks(node, file) {
2713
2816
  const fallbacks = /* @__PURE__ */ new Map();
2714
2817
  for (const tag of ts.getJSDocTags(node)) {
2715
- const tagName = (0, import_internals3.normalizeConstraintTagName)(tag.tagName.text);
2818
+ const tagName = (0, import_internals4.normalizeConstraintTagName)(tag.tagName.text);
2716
2819
  if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
2717
2820
  const commentText = getTagCommentText(tag)?.trim() ?? "";
2718
2821
  if (commentText === "") continue;
@@ -2726,7 +2829,7 @@ function collectRawTextFallbacks(node, file) {
2726
2829
  return fallbacks;
2727
2830
  }
2728
2831
  function isMemberTargetDisplayName(text) {
2729
- return (0, import_internal.parseTagSyntax)("displayName", text).target !== null;
2832
+ return (0, import_internal2.parseTagSyntax)("displayName", text).target !== null;
2730
2833
  }
2731
2834
  function provenanceForComment(range, sourceFile, file, tagName) {
2732
2835
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(range.pos);
@@ -2839,76 +2942,79 @@ function makeParseOptions(extensionRegistry, fieldType, checker, subjectType, ho
2839
2942
  ...hostType !== void 0 && { hostType }
2840
2943
  };
2841
2944
  }
2842
- function makeExplicitScalarMetadata(value) {
2843
- return value === void 0 || value === "" ? void 0 : { value, source: "explicit" };
2945
+ function createAnalyzerMetadataPolicy(input) {
2946
+ return {
2947
+ raw: input,
2948
+ normalized: normalizeMetadataPolicy(input)
2949
+ };
2844
2950
  }
2845
- function extractExplicitMetadata(node) {
2846
- let apiName;
2847
- let displayName;
2848
- let apiNamePlural;
2849
- let displayNamePlural;
2850
- for (const tag of getLeadingParsedTags(node)) {
2851
- const value = tag.argumentText.trim();
2852
- if (value === "") {
2853
- continue;
2854
- }
2855
- if (tag.normalizedTagName === "apiName") {
2856
- if (tag.target === null) {
2857
- apiName ??= value;
2858
- } else if (tag.target.kind === "variant") {
2859
- if (tag.target.rawText === "singular") {
2860
- apiName ??= value;
2861
- } else if (tag.target.rawText === "plural") {
2862
- apiNamePlural ??= value;
2863
- }
2864
- }
2865
- continue;
2866
- }
2867
- if (tag.normalizedTagName === "displayName") {
2868
- if (tag.target === null) {
2869
- displayName ??= value;
2870
- } else if (tag.target.kind === "variant") {
2871
- if (tag.target.rawText === "singular") {
2872
- displayName ??= value;
2873
- } else if (tag.target.rawText === "plural") {
2874
- displayNamePlural ??= value;
2875
- }
2876
- }
2877
- }
2951
+ function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, checker, extensionRegistry, buildContext) {
2952
+ const analysis = (0, import_internal3.analyzeMetadataForNodeWithChecker)({
2953
+ checker,
2954
+ node,
2955
+ logicalName,
2956
+ metadata: metadataPolicy.raw,
2957
+ extensions: extensionRegistry?.extensions,
2958
+ ...buildContext !== void 0 && { buildContext }
2959
+ });
2960
+ const resolvedMetadata = analysis?.resolvedMetadata;
2961
+ const declarationPolicy = getDeclarationMetadataPolicy(
2962
+ metadataPolicy.normalized,
2963
+ declarationKind
2964
+ );
2965
+ if (resolvedMetadata?.apiName === void 0 && declarationPolicy.apiName.mode === "require-explicit") {
2966
+ throw new Error(
2967
+ `Metadata policy requires explicit apiName for ${declarationKind} "${logicalName}" on the tsdoc surface.`
2968
+ );
2878
2969
  }
2879
- const resolvedApiName = makeExplicitScalarMetadata(apiName);
2880
- const resolvedDisplayName = makeExplicitScalarMetadata(displayName);
2881
- const resolvedApiNamePlural = makeExplicitScalarMetadata(apiNamePlural);
2882
- const resolvedDisplayNamePlural = makeExplicitScalarMetadata(displayNamePlural);
2883
- const metadata = {
2884
- ...resolvedApiName !== void 0 && { apiName: resolvedApiName },
2885
- ...resolvedDisplayName !== void 0 && { displayName: resolvedDisplayName },
2886
- ...resolvedApiNamePlural !== void 0 && { apiNamePlural: resolvedApiNamePlural },
2887
- ...resolvedDisplayNamePlural !== void 0 && {
2888
- displayNamePlural: resolvedDisplayNamePlural
2889
- }
2890
- };
2891
- return Object.keys(metadata).length === 0 ? void 0 : metadata;
2970
+ if (resolvedMetadata?.displayName === void 0 && declarationPolicy.displayName.mode === "require-explicit") {
2971
+ throw new Error(
2972
+ `Metadata policy requires explicit displayName for ${declarationKind} "${logicalName}" on the tsdoc surface.`
2973
+ );
2974
+ }
2975
+ if (resolvedMetadata?.apiNamePlural === void 0 && declarationPolicy.apiName.pluralization.mode === "require-explicit") {
2976
+ throw new Error(
2977
+ `Metadata policy requires explicit apiNamePlural for ${declarationKind} "${logicalName}" on the tsdoc surface.`
2978
+ );
2979
+ }
2980
+ if (resolvedMetadata?.displayNamePlural === void 0 && declarationPolicy.displayName.pluralization.mode === "require-explicit") {
2981
+ throw new Error(
2982
+ `Metadata policy requires explicit displayNamePlural for ${declarationKind} "${logicalName}" on the tsdoc surface.`
2983
+ );
2984
+ }
2985
+ return resolvedMetadata;
2892
2986
  }
2893
- function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, buildContext) {
2894
- const explicit = extractExplicitMetadata(node);
2895
- return resolveMetadata(
2987
+ function analyzeDeclarationRootInfo(declaration, checker, file = "", extensionRegistry, metadataPolicy) {
2988
+ const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
2989
+ const declarationType = checker.getTypeAtLocation(declaration);
2990
+ const logicalName = ts3.isClassDeclaration(declaration) ? declaration.name?.text ?? "AnonymousClass" : declaration.name.text;
2991
+ const docResult = extractJSDocParseResult(
2992
+ declaration,
2993
+ file,
2994
+ makeParseOptions(extensionRegistry, void 0, checker, declarationType, declarationType)
2995
+ );
2996
+ const metadata = resolveNodeMetadata(
2997
+ normalizedMetadataPolicy,
2998
+ "type",
2999
+ logicalName,
3000
+ declaration,
3001
+ checker,
3002
+ extensionRegistry,
2896
3003
  {
2897
- ...explicit?.apiName !== void 0 && { apiName: explicit.apiName.value },
2898
- ...explicit?.displayName !== void 0 && { displayName: explicit.displayName.value },
2899
- ...explicit?.apiNamePlural !== void 0 && {
2900
- apiNamePlural: explicit.apiNamePlural.value
2901
- },
2902
- ...explicit?.displayNamePlural !== void 0 && {
2903
- displayNamePlural: explicit.displayNamePlural.value
2904
- }
2905
- },
2906
- getDeclarationMetadataPolicy(metadataPolicy, declarationKind),
2907
- makeMetadataContext("tsdoc", declarationKind, logicalName, buildContext)
3004
+ checker,
3005
+ declaration,
3006
+ subjectType: declarationType,
3007
+ hostType: declarationType
3008
+ }
2908
3009
  );
3010
+ return {
3011
+ ...metadata !== void 0 && { metadata },
3012
+ annotations: docResult.annotations,
3013
+ diagnostics: docResult.diagnostics
3014
+ };
2909
3015
  }
2910
3016
  function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy) {
2911
- const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
3017
+ const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
2912
3018
  const name = classDecl.name?.text ?? "AnonymousClass";
2913
3019
  const fields = [];
2914
3020
  const fieldLayouts = [];
@@ -2963,12 +3069,20 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, meta
2963
3069
  diagnostics,
2964
3070
  normalizedMetadataPolicy
2965
3071
  );
2966
- const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, classDecl, {
3072
+ const metadata = resolveNodeMetadata(
3073
+ normalizedMetadataPolicy,
3074
+ "type",
3075
+ name,
3076
+ classDecl,
2967
3077
  checker,
2968
- declaration: classDecl,
2969
- subjectType: classType,
2970
- hostType: classType
2971
- });
3078
+ extensionRegistry,
3079
+ {
3080
+ checker,
3081
+ declaration: classDecl,
3082
+ subjectType: classType,
3083
+ hostType: classType
3084
+ }
3085
+ );
2972
3086
  return {
2973
3087
  name,
2974
3088
  ...metadata !== void 0 && { metadata },
@@ -2982,7 +3096,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, meta
2982
3096
  };
2983
3097
  }
2984
3098
  function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry, metadataPolicy) {
2985
- const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
3099
+ const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
2986
3100
  const name = interfaceDecl.name.text;
2987
3101
  const fields = [];
2988
3102
  const typeRegistry = {};
@@ -3024,12 +3138,20 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
3024
3138
  normalizedMetadataPolicy
3025
3139
  );
3026
3140
  const fieldLayouts = specializedFields.map(() => ({}));
3027
- const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, interfaceDecl, {
3141
+ const metadata = resolveNodeMetadata(
3142
+ normalizedMetadataPolicy,
3143
+ "type",
3144
+ name,
3145
+ interfaceDecl,
3028
3146
  checker,
3029
- declaration: interfaceDecl,
3030
- subjectType: interfaceType,
3031
- hostType: interfaceType
3032
- });
3147
+ extensionRegistry,
3148
+ {
3149
+ checker,
3150
+ declaration: interfaceDecl,
3151
+ subjectType: interfaceType,
3152
+ hostType: interfaceType
3153
+ }
3154
+ );
3033
3155
  return {
3034
3156
  name,
3035
3157
  ...metadata !== void 0 && { metadata },
@@ -3053,7 +3175,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
3053
3175
  };
3054
3176
  }
3055
3177
  const typeLiteral = typeAlias.type;
3056
- const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
3178
+ const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
3057
3179
  const name = typeAlias.name.text;
3058
3180
  const fields = [];
3059
3181
  const typeRegistry = {};
@@ -3094,12 +3216,20 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
3094
3216
  diagnostics,
3095
3217
  normalizedMetadataPolicy
3096
3218
  );
3097
- const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, typeAlias, {
3219
+ const metadata = resolveNodeMetadata(
3220
+ normalizedMetadataPolicy,
3221
+ "type",
3222
+ name,
3223
+ typeAlias,
3098
3224
  checker,
3099
- declaration: typeAlias,
3100
- subjectType: aliasType,
3101
- hostType: aliasType
3102
- });
3225
+ extensionRegistry,
3226
+ {
3227
+ checker,
3228
+ declaration: typeAlias,
3229
+ subjectType: aliasType,
3230
+ hostType: aliasType
3231
+ }
3232
+ );
3103
3233
  return {
3104
3234
  ok: true,
3105
3235
  analysis: {
@@ -3140,7 +3270,7 @@ function getLeadingParsedTags(node) {
3140
3270
  if (!commentText.startsWith("/**")) {
3141
3271
  continue;
3142
3272
  }
3143
- parsedTags.push(...(0, import_internal2.parseCommentBlock)(commentText, { offset: range.pos }).tags);
3273
+ parsedTags.push(...(0, import_internal3.parseCommentBlock)(commentText, { offset: range.pos }).tags);
3144
3274
  }
3145
3275
  return parsedTags;
3146
3276
  }
@@ -3321,10 +3451,7 @@ function resolveLiteralDiscriminatorPropertyValue(boundType, fieldName, checker,
3321
3451
  if (resolvedAnchorNode === null) {
3322
3452
  return void 0;
3323
3453
  }
3324
- const propertyType = checker.getTypeOfSymbolAtLocation(
3325
- propertySymbol,
3326
- resolvedAnchorNode
3327
- );
3454
+ const propertyType = checker.getTypeOfSymbolAtLocation(propertySymbol, resolvedAnchorNode);
3328
3455
  if (propertyType.isStringLiteral()) {
3329
3456
  return propertyType.value;
3330
3457
  }
@@ -3355,6 +3482,8 @@ function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
3355
3482
  "type",
3356
3483
  getDiscriminatorLogicalName(boundType, declaration, checker),
3357
3484
  declaration,
3485
+ checker,
3486
+ void 0,
3358
3487
  {
3359
3488
  checker,
3360
3489
  declaration,
@@ -3591,12 +3720,20 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
3591
3720
  annotations.push(defaultAnnotation);
3592
3721
  }
3593
3722
  ({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
3594
- const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
3723
+ const metadata = resolveNodeMetadata(
3724
+ metadataPolicy,
3725
+ "field",
3726
+ name,
3727
+ prop,
3595
3728
  checker,
3596
- declaration: prop,
3597
- subjectType: tsType,
3598
- hostType
3599
- });
3729
+ extensionRegistry,
3730
+ {
3731
+ checker,
3732
+ declaration: prop,
3733
+ subjectType: tsType,
3734
+ hostType
3735
+ }
3736
+ );
3600
3737
  return {
3601
3738
  kind: "field",
3602
3739
  name,
@@ -3643,12 +3780,20 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
3643
3780
  let annotations = [];
3644
3781
  annotations.push(...docResult.annotations);
3645
3782
  ({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
3646
- const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
3783
+ const metadata = resolveNodeMetadata(
3784
+ metadataPolicy,
3785
+ "field",
3786
+ name,
3787
+ prop,
3647
3788
  checker,
3648
- declaration: prop,
3649
- subjectType: tsType,
3650
- hostType
3651
- });
3789
+ extensionRegistry,
3790
+ {
3791
+ checker,
3792
+ declaration: prop,
3793
+ subjectType: tsType,
3794
+ hostType
3795
+ }
3796
+ );
3652
3797
  return {
3653
3798
  kind: "field",
3654
3799
  name,
@@ -3777,7 +3922,7 @@ function getTypeNodeRegistrationName(typeNode) {
3777
3922
  }
3778
3923
  return null;
3779
3924
  }
3780
- function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3925
+ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3781
3926
  const customType = resolveRegisteredCustomType(sourceNode, extensionRegistry, checker);
3782
3927
  if (customType) {
3783
3928
  return customType;
@@ -3867,7 +4012,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
3867
4012
  }
3868
4013
  return { kind: "primitive", primitiveKind: "string" };
3869
4014
  }
3870
- function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4015
+ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3871
4016
  if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
3872
4017
  return null;
3873
4018
  }
@@ -3887,11 +4032,19 @@ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiti
3887
4032
  file,
3888
4033
  makeParseOptions(extensionRegistry)
3889
4034
  );
3890
- const metadata = resolveNodeMetadata(metadataPolicy, "type", aliasName, aliasDecl, {
4035
+ const metadata = resolveNodeMetadata(
4036
+ metadataPolicy,
4037
+ "type",
4038
+ aliasName,
4039
+ aliasDecl,
3891
4040
  checker,
3892
- declaration: aliasDecl,
3893
- subjectType: aliasType
3894
- });
4041
+ extensionRegistry,
4042
+ {
4043
+ checker,
4044
+ declaration: aliasDecl,
4045
+ subjectType: aliasType
4046
+ }
4047
+ );
3895
4048
  typeRegistry[aliasName] = {
3896
4049
  name: aliasName,
3897
4050
  ...metadata !== void 0 && { metadata },
@@ -3930,7 +4083,7 @@ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
3930
4083
  const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
3931
4084
  return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
3932
4085
  }
3933
- function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4086
+ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3934
4087
  const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
3935
4088
  if (nestedAliasDecl !== void 0) {
3936
4089
  return resolveAliasedPrimitiveTarget(
@@ -3956,7 +4109,7 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
3956
4109
  diagnostics
3957
4110
  );
3958
4111
  }
3959
- function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4112
+ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3960
4113
  const typeName = getNamedTypeName(type);
3961
4114
  const namedDecl = getNamedTypeDeclaration(type);
3962
4115
  if (typeName && typeName in typeRegistry) {
@@ -3991,11 +4144,19 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
3991
4144
  return result;
3992
4145
  }
3993
4146
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
3994
- const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", typeName, namedDecl, {
4147
+ const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4148
+ metadataPolicy,
4149
+ "type",
4150
+ typeName,
4151
+ namedDecl,
3995
4152
  checker,
3996
- declaration: namedDecl,
3997
- subjectType: type
3998
- }) : void 0;
4153
+ extensionRegistry,
4154
+ {
4155
+ checker,
4156
+ declaration: namedDecl,
4157
+ subjectType: type
4158
+ }
4159
+ ) : void 0;
3999
4160
  typeRegistry[typeName] = {
4000
4161
  name: typeName,
4001
4162
  ...metadata !== void 0 && { metadata },
@@ -4080,7 +4241,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
4080
4241
  }
4081
4242
  return registerNamed({ kind: "union", members });
4082
4243
  }
4083
- function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4244
+ function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4084
4245
  const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
4085
4246
  const elementType = typeArgs?.[0];
4086
4247
  const elementSourceNode = extractArrayElementTypeNode(sourceNode, checker);
@@ -4097,7 +4258,7 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNod
4097
4258
  ) : { kind: "primitive", primitiveKind: "string" };
4098
4259
  return { kind: "array", items };
4099
4260
  }
4100
- function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4261
+ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4101
4262
  if (type.getProperties().length > 0) {
4102
4263
  return null;
4103
4264
  }
@@ -4158,7 +4319,7 @@ function shouldEmitResolvedObjectProperty(property, declaration) {
4158
4319
  }
4159
4320
  return true;
4160
4321
  }
4161
- function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4322
+ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4162
4323
  const collectedDiagnostics = diagnostics ?? [];
4163
4324
  const typeName = getNamedTypeName(type);
4164
4325
  const namedTypeName = typeName ?? void 0;
@@ -4234,11 +4395,19 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
4234
4395
  return recordNode;
4235
4396
  }
4236
4397
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
4237
- const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
4398
+ const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4399
+ metadataPolicy,
4400
+ "type",
4401
+ registryTypeName,
4402
+ namedDecl,
4238
4403
  checker,
4239
- declaration: namedDecl,
4240
- subjectType: type
4241
- }) : void 0;
4404
+ extensionRegistry,
4405
+ {
4406
+ checker,
4407
+ declaration: namedDecl,
4408
+ subjectType: type
4409
+ }
4410
+ ) : void 0;
4242
4411
  typeRegistry[registryTypeName] = {
4243
4412
  name: registryTypeName,
4244
4413
  ...metadata !== void 0 && { metadata },
@@ -4283,14 +4452,39 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
4283
4452
  collectedDiagnostics
4284
4453
  );
4285
4454
  const fieldNodeInfo = fieldInfoMap?.get(prop.name);
4455
+ const inlineFieldNodeInfo = fieldNodeInfo === void 0 ? ts3.isPropertySignature(declaration) ? analyzeInterfacePropertyToIR(
4456
+ declaration,
4457
+ checker,
4458
+ file,
4459
+ typeRegistry,
4460
+ visiting,
4461
+ collectedDiagnostics,
4462
+ type,
4463
+ metadataPolicy,
4464
+ extensionRegistry
4465
+ ) : ts3.isPropertyDeclaration(declaration) ? analyzeFieldToIR(
4466
+ declaration,
4467
+ checker,
4468
+ file,
4469
+ typeRegistry,
4470
+ visiting,
4471
+ collectedDiagnostics,
4472
+ type,
4473
+ metadataPolicy,
4474
+ extensionRegistry
4475
+ ) : null : null;
4476
+ const resolvedFieldNodeInfo = fieldNodeInfo ?? inlineFieldNodeInfo;
4477
+ const resolvedPropertyType = inlineFieldNodeInfo?.type ?? propTypeNode;
4286
4478
  properties.push({
4287
4479
  name: prop.name,
4288
- ...fieldNodeInfo?.metadata !== void 0 && { metadata: fieldNodeInfo.metadata },
4289
- type: propTypeNode,
4480
+ ...resolvedFieldNodeInfo?.metadata !== void 0 && {
4481
+ metadata: resolvedFieldNodeInfo.metadata
4482
+ },
4483
+ type: resolvedPropertyType,
4290
4484
  optional,
4291
- constraints: fieldNodeInfo?.constraints ?? [],
4292
- annotations: fieldNodeInfo?.annotations ?? [],
4293
- provenance: fieldNodeInfo?.provenance ?? provenanceForFile(file)
4485
+ constraints: resolvedFieldNodeInfo?.constraints ?? [],
4486
+ annotations: resolvedFieldNodeInfo?.annotations ?? [],
4487
+ provenance: resolvedFieldNodeInfo?.provenance ?? provenanceForFile(file)
4294
4488
  });
4295
4489
  }
4296
4490
  visiting.delete(type);
@@ -4309,11 +4503,19 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNo
4309
4503
  };
4310
4504
  if (registryTypeName !== void 0 && shouldRegisterNamedType) {
4311
4505
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
4312
- const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
4506
+ const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4507
+ metadataPolicy,
4508
+ "type",
4509
+ registryTypeName,
4510
+ namedDecl,
4313
4511
  checker,
4314
- declaration: namedDecl,
4315
- subjectType: type
4316
- }) : void 0;
4512
+ extensionRegistry,
4513
+ {
4514
+ checker,
4515
+ declaration: namedDecl,
4516
+ subjectType: type
4517
+ }
4518
+ ) : void 0;
4317
4519
  typeRegistry[registryTypeName] = {
4318
4520
  name: registryTypeName,
4319
4521
  ...metadata !== void 0 && { metadata },
@@ -4725,9 +4927,9 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
4725
4927
  }
4726
4928
 
4727
4929
  // src/validate/constraint-validator.ts
4728
- var import_internal3 = require("@formspec/analysis/internal");
4930
+ var import_internal4 = require("@formspec/analysis/internal");
4729
4931
  function validateFieldNode(ctx, field) {
4730
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
4932
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
4731
4933
  field.name,
4732
4934
  field.type,
4733
4935
  field.constraints,
@@ -4745,7 +4947,7 @@ function validateFieldNode(ctx, field) {
4745
4947
  }
4746
4948
  function validateObjectProperty(ctx, parentName, property) {
4747
4949
  const qualifiedName = `${parentName}.${property.name}`;
4748
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
4950
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
4749
4951
  qualifiedName,
4750
4952
  property.type,
4751
4953
  property.constraints,
@@ -4886,6 +5088,345 @@ function generateSchemasFromProgram(options) {
4886
5088
  );
4887
5089
  }
4888
5090
 
5091
+ // src/static-build.ts
5092
+ var ts6 = __toESM(require("typescript"), 1);
5093
+ function toStaticBuildContext(context) {
5094
+ return context;
5095
+ }
5096
+ function createStaticBuildContext(filePath) {
5097
+ return toStaticBuildContext(createProgramContext(filePath));
5098
+ }
5099
+ function createStaticBuildContextFromProgram(program, filePath) {
5100
+ return toStaticBuildContext(createProgramContextFromProgram(program, filePath));
5101
+ }
5102
+ function getModuleSymbol(context) {
5103
+ const sourceFileWithSymbol = context.sourceFile;
5104
+ return context.checker.getSymbolAtLocation(context.sourceFile) ?? sourceFileWithSymbol.symbol;
5105
+ }
5106
+ function isSchemaSourceDeclaration(declaration) {
5107
+ return ts6.isClassDeclaration(declaration) || ts6.isInterfaceDeclaration(declaration) || ts6.isTypeAliasDeclaration(declaration);
5108
+ }
5109
+ function resolveModuleExport(context, exportName = "default") {
5110
+ const moduleSymbol = getModuleSymbol(context);
5111
+ if (moduleSymbol === void 0) {
5112
+ return null;
5113
+ }
5114
+ const exportSymbol = context.checker.getExportsOfModule(moduleSymbol).find((candidate) => candidate.name === exportName) ?? null;
5115
+ if (exportSymbol === null) {
5116
+ return null;
5117
+ }
5118
+ return exportSymbol.flags & ts6.SymbolFlags.Alias ? context.checker.getAliasedSymbol(exportSymbol) : exportSymbol;
5119
+ }
5120
+ function resolveModuleExportDeclaration(context, exportName = "default") {
5121
+ return resolveModuleExport(context, exportName)?.declarations?.find(isSchemaSourceDeclaration) ?? null;
5122
+ }
5123
+
5124
+ // src/generators/discovered-schema.ts
5125
+ var ts7 = __toESM(require("typescript"), 1);
5126
+ var import_internals6 = require("@formspec/core/internals");
5127
+ function toDiscoveredTypeSchemas(result) {
5128
+ return result;
5129
+ }
5130
+ function isNamedTypeDeclaration(declaration) {
5131
+ return ts7.isClassDeclaration(declaration) || ts7.isInterfaceDeclaration(declaration) || ts7.isTypeAliasDeclaration(declaration);
5132
+ }
5133
+ function hasConcreteTypeArguments(type, checker) {
5134
+ if ("aliasTypeArguments" in type && Array.isArray(type.aliasTypeArguments) && type.aliasTypeArguments.length > 0) {
5135
+ return true;
5136
+ }
5137
+ if ((type.flags & ts7.TypeFlags.Object) === 0) {
5138
+ return false;
5139
+ }
5140
+ const objectType = type;
5141
+ if ((objectType.objectFlags & ts7.ObjectFlags.Reference) === 0) {
5142
+ return false;
5143
+ }
5144
+ return checker.getTypeArguments(objectType).length > 0;
5145
+ }
5146
+ function getNamedTypeDeclaration2(type) {
5147
+ const symbol = type.getSymbol();
5148
+ if (symbol?.declarations !== void 0) {
5149
+ const declaration = symbol.declarations[0];
5150
+ if (declaration !== void 0 && isNamedTypeDeclaration(declaration)) {
5151
+ return declaration;
5152
+ }
5153
+ }
5154
+ const aliasDeclaration = type.aliasSymbol?.declarations?.find(ts7.isTypeAliasDeclaration);
5155
+ return aliasDeclaration;
5156
+ }
5157
+ function getFallbackName(sourceNode, fallback = "AnonymousType") {
5158
+ if (sourceNode !== void 0 && "name" in sourceNode) {
5159
+ const namedNode = sourceNode;
5160
+ if (namedNode.name !== void 0 && ts7.isIdentifier(namedNode.name)) {
5161
+ return namedNode.name.text;
5162
+ }
5163
+ }
5164
+ return fallback;
5165
+ }
5166
+ function createObjectRootAnalysis(name, properties, typeRegistry, metadata, annotations) {
5167
+ const fields = properties.map((property) => ({
5168
+ kind: "field",
5169
+ name: property.name,
5170
+ ...property.metadata !== void 0 && { metadata: property.metadata },
5171
+ type: property.type,
5172
+ required: !property.optional,
5173
+ constraints: property.constraints,
5174
+ annotations: property.annotations,
5175
+ provenance: property.provenance
5176
+ }));
5177
+ return {
5178
+ name,
5179
+ ...metadata !== void 0 && { metadata },
5180
+ fields,
5181
+ fieldLayouts: fields.map(() => ({})),
5182
+ typeRegistry,
5183
+ ...annotations !== void 0 && annotations.length > 0 && { annotations },
5184
+ instanceMethods: [],
5185
+ staticMethods: [],
5186
+ diagnostics: []
5187
+ };
5188
+ }
5189
+ function omitApiName(metadata) {
5190
+ if (metadata?.apiName === void 0) {
5191
+ return metadata;
5192
+ }
5193
+ const { apiName: _apiName, ...rest } = metadata;
5194
+ return Object.keys(rest).length > 0 ? rest : void 0;
5195
+ }
5196
+ function describeRootType(rootType, typeRegistry, fallbackName) {
5197
+ if (rootType.kind !== "reference") {
5198
+ return {
5199
+ name: fallbackName,
5200
+ type: rootType
5201
+ };
5202
+ }
5203
+ const definition = typeRegistry[rootType.name];
5204
+ if (definition === void 0) {
5205
+ return {
5206
+ name: rootType.name,
5207
+ type: rootType
5208
+ };
5209
+ }
5210
+ return {
5211
+ name: definition.name,
5212
+ ...definition.metadata !== void 0 && { metadata: definition.metadata },
5213
+ ...definition.annotations !== void 0 && definition.annotations.length > 0 && { annotations: definition.annotations },
5214
+ type: definition.type
5215
+ };
5216
+ }
5217
+ function toStandaloneJsonSchema(root, typeRegistry, options) {
5218
+ const syntheticFieldMetadata = omitApiName(root.metadata);
5219
+ const syntheticField = {
5220
+ kind: "field",
5221
+ name: "__result",
5222
+ ...syntheticFieldMetadata !== void 0 && { metadata: syntheticFieldMetadata },
5223
+ type: root.type,
5224
+ required: true,
5225
+ constraints: [],
5226
+ annotations: [...root.annotations ?? []],
5227
+ provenance: {
5228
+ surface: "tsdoc",
5229
+ file: "",
5230
+ line: 1,
5231
+ column: 0
5232
+ }
5233
+ };
5234
+ const schema = generateJsonSchemaFromIR(
5235
+ {
5236
+ kind: "form-ir",
5237
+ name: root.name,
5238
+ irVersion: import_internals6.IR_VERSION,
5239
+ elements: [syntheticField],
5240
+ ...root.metadata !== void 0 && { metadata: root.metadata },
5241
+ ...root.annotations !== void 0 && root.annotations.length > 0 && { rootAnnotations: root.annotations },
5242
+ typeRegistry,
5243
+ provenance: syntheticField.provenance
5244
+ },
5245
+ {
5246
+ extensionRegistry: options?.extensionRegistry,
5247
+ vendorPrefix: options?.vendorPrefix
5248
+ }
5249
+ );
5250
+ const result = schema.properties?.["__result"];
5251
+ if (result === void 0) {
5252
+ throw new Error("FormSpec failed to extract the standalone schema root from the synthetic IR.");
5253
+ }
5254
+ if (schema.$defs === void 0 || Object.keys(schema.$defs).length === 0) {
5255
+ return {
5256
+ ...schema.$schema !== void 0 && { $schema: schema.$schema },
5257
+ ...result
5258
+ };
5259
+ }
5260
+ return {
5261
+ ...schema.$schema !== void 0 && { $schema: schema.$schema },
5262
+ ...result,
5263
+ $defs: schema.$defs
5264
+ };
5265
+ }
5266
+ function generateSchemasFromAnalysis(analysis, filePath, options) {
5267
+ return toDiscoveredTypeSchemas(
5268
+ generateClassSchemas(
5269
+ analysis,
5270
+ { file: filePath },
5271
+ {
5272
+ extensionRegistry: options?.extensionRegistry,
5273
+ metadata: options?.metadata,
5274
+ vendorPrefix: options?.vendorPrefix
5275
+ }
5276
+ )
5277
+ );
5278
+ }
5279
+ function generateSchemasFromResolvedType(options, skipNamedDeclaration = false, rootOverride) {
5280
+ const namedDeclaration = skipNamedDeclaration || hasConcreteTypeArguments(options.type, options.context.checker) ? void 0 : getNamedTypeDeclaration2(options.type);
5281
+ if (namedDeclaration !== void 0) {
5282
+ return generateSchemasFromDeclaration({
5283
+ ...options,
5284
+ declaration: namedDeclaration
5285
+ });
5286
+ }
5287
+ const filePath = options.sourceNode?.getSourceFile().fileName ?? options.context.sourceFile.fileName;
5288
+ const typeRegistry = {};
5289
+ const diagnostics = [];
5290
+ const rootType = resolveTypeNode(
5291
+ options.type,
5292
+ options.context.checker,
5293
+ filePath,
5294
+ typeRegistry,
5295
+ /* @__PURE__ */ new Set(),
5296
+ options.sourceNode,
5297
+ createAnalyzerMetadataPolicy(options.metadata),
5298
+ options.extensionRegistry,
5299
+ diagnostics
5300
+ );
5301
+ if (diagnostics.length > 0) {
5302
+ const diagnosticDetails = diagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`).join("; ");
5303
+ throw new Error(
5304
+ `FormSpec validation failed while generating discovered type schemas. ${diagnosticDetails}`
5305
+ );
5306
+ }
5307
+ const describedRoot = describeRootType(
5308
+ rootType,
5309
+ typeRegistry,
5310
+ options.name ?? getFallbackName(options.sourceNode)
5311
+ );
5312
+ const mergedMetadata = mergeResolvedMetadata(describedRoot.metadata, rootOverride?.metadata);
5313
+ const root = {
5314
+ ...describedRoot,
5315
+ ...rootOverride?.name !== void 0 && { name: rootOverride.name },
5316
+ ...mergedMetadata !== void 0 && { metadata: mergedMetadata },
5317
+ ...rootOverride?.annotations !== void 0 && { annotations: rootOverride.annotations }
5318
+ };
5319
+ if (root.type.kind === "object") {
5320
+ return generateSchemasFromAnalysis(
5321
+ createObjectRootAnalysis(
5322
+ options.name ?? root.name,
5323
+ root.type.properties,
5324
+ typeRegistry,
5325
+ root.metadata,
5326
+ root.annotations
5327
+ ),
5328
+ filePath,
5329
+ options
5330
+ );
5331
+ }
5332
+ return {
5333
+ jsonSchema: toStandaloneJsonSchema(root, typeRegistry, options),
5334
+ uiSchema: null
5335
+ };
5336
+ }
5337
+ function generateSchemasFromDeclaration(options) {
5338
+ const filePath = options.declaration.getSourceFile().fileName;
5339
+ if (ts7.isClassDeclaration(options.declaration)) {
5340
+ return generateSchemasFromAnalysis(
5341
+ analyzeClassToIR(
5342
+ options.declaration,
5343
+ options.context.checker,
5344
+ filePath,
5345
+ options.extensionRegistry,
5346
+ options.metadata
5347
+ ),
5348
+ filePath,
5349
+ options
5350
+ );
5351
+ }
5352
+ if (ts7.isInterfaceDeclaration(options.declaration)) {
5353
+ return generateSchemasFromAnalysis(
5354
+ analyzeInterfaceToIR(
5355
+ options.declaration,
5356
+ options.context.checker,
5357
+ filePath,
5358
+ options.extensionRegistry,
5359
+ options.metadata
5360
+ ),
5361
+ filePath,
5362
+ options
5363
+ );
5364
+ }
5365
+ if (ts7.isTypeAliasDeclaration(options.declaration)) {
5366
+ const analyzedAlias = analyzeTypeAliasToIR(
5367
+ options.declaration,
5368
+ options.context.checker,
5369
+ filePath,
5370
+ options.extensionRegistry,
5371
+ options.metadata
5372
+ );
5373
+ if (analyzedAlias.ok) {
5374
+ return generateSchemasFromAnalysis(analyzedAlias.analysis, filePath, options);
5375
+ }
5376
+ const aliasRootInfo = analyzeDeclarationRootInfo(
5377
+ options.declaration,
5378
+ options.context.checker,
5379
+ filePath,
5380
+ options.extensionRegistry,
5381
+ options.metadata
5382
+ );
5383
+ if (aliasRootInfo.diagnostics.length > 0) {
5384
+ const diagnosticDetails = aliasRootInfo.diagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`).join("; ");
5385
+ throw new Error(
5386
+ `FormSpec validation failed while generating discovered type schemas. ${diagnosticDetails}`
5387
+ );
5388
+ }
5389
+ return generateSchemasFromResolvedType(
5390
+ {
5391
+ ...options,
5392
+ type: options.context.checker.getTypeAtLocation(options.declaration),
5393
+ sourceNode: options.declaration,
5394
+ name: options.declaration.name.text
5395
+ },
5396
+ true,
5397
+ {
5398
+ name: options.declaration.name.text,
5399
+ ...aliasRootInfo.metadata !== void 0 && { metadata: aliasRootInfo.metadata },
5400
+ ...aliasRootInfo.annotations.length > 0 && { annotations: aliasRootInfo.annotations }
5401
+ }
5402
+ );
5403
+ }
5404
+ const _exhaustive = options.declaration;
5405
+ return _exhaustive;
5406
+ }
5407
+ function generateSchemasFromType(options) {
5408
+ return generateSchemasFromResolvedType(options);
5409
+ }
5410
+ function generateSchemasFromParameter(options) {
5411
+ return generateSchemasFromResolvedType({
5412
+ ...options,
5413
+ type: options.context.checker.getTypeAtLocation(options.parameter),
5414
+ sourceNode: options.parameter,
5415
+ name: getFallbackName(options.parameter, "Parameter")
5416
+ });
5417
+ }
5418
+ function generateSchemasFromReturnType(options) {
5419
+ const signature = options.context.checker.getSignatureFromDeclaration(options.declaration);
5420
+ const type = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
5421
+ const fallbackName = options.declaration.name !== void 0 && ts7.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
5422
+ return generateSchemasFromResolvedType({
5423
+ ...options,
5424
+ type,
5425
+ sourceNode: options.declaration.type ?? options.declaration,
5426
+ name: fallbackName
5427
+ });
5428
+ }
5429
+
4889
5430
  // src/generators/mixed-authoring.ts
4890
5431
  function buildMixedAuthoringSchemas(options) {
4891
5432
  const { filePath, typeName, overlays, ...schemaOptions } = options;
@@ -5101,12 +5642,20 @@ function writeSchemas(form, options) {
5101
5642
  buildFormSchemas,
5102
5643
  buildMixedAuthoringSchemas,
5103
5644
  createExtensionRegistry,
5645
+ createStaticBuildContext,
5646
+ createStaticBuildContextFromProgram,
5104
5647
  generateJsonSchema,
5105
5648
  generateSchemas,
5106
5649
  generateSchemasFromClass,
5650
+ generateSchemasFromDeclaration,
5651
+ generateSchemasFromParameter,
5107
5652
  generateSchemasFromProgram,
5653
+ generateSchemasFromReturnType,
5654
+ generateSchemasFromType,
5108
5655
  generateUiSchema,
5109
5656
  jsonSchema7Schema,
5657
+ resolveModuleExport,
5658
+ resolveModuleExportDeclaration,
5110
5659
  uiSchemaSchema,
5111
5660
  writeSchemas
5112
5661
  });