@formspec/build 0.1.0-alpha.26 → 0.1.0-alpha.28
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/LICENSE +21 -0
- package/README.md +3 -2
- package/dist/analyzer/class-analyzer.d.ts +1 -1
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +12 -0
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +48 -22
- package/dist/build-beta.d.ts +48 -22
- package/dist/build-internal.d.ts +48 -22
- package/dist/build.d.ts +151 -21
- package/dist/cli.cjs +609 -41
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +605 -36
- package/dist/cli.js.map +1 -1
- package/dist/generators/class-schema.d.ts +27 -0
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/generators/mixed-authoring.d.ts.map +1 -1
- package/dist/index.cjs +603 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +599 -36
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +552 -34
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.d.ts +1 -1
- package/dist/internals.d.ts.map +1 -1
- package/dist/internals.js +549 -31
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/schema.d.ts +2 -2
- package/dist/json-schema/types.d.ts +4 -4
- package/dist/ui-schema/schema.d.ts +2 -7
- package/dist/ui-schema/schema.d.ts.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,10 @@ __export(index_exports, {
|
|
|
36
36
|
generateJsonSchema: () => generateJsonSchema,
|
|
37
37
|
generateSchemas: () => generateSchemas,
|
|
38
38
|
generateSchemasFromClass: () => generateSchemasFromClass,
|
|
39
|
+
generateSchemasFromProgram: () => generateSchemasFromProgram,
|
|
39
40
|
generateUiSchema: () => generateUiSchema,
|
|
41
|
+
jsonSchema7Schema: () => jsonSchema7Schema,
|
|
42
|
+
uiSchemaSchema: () => uiSchema,
|
|
40
43
|
writeSchemas: () => writeSchemas
|
|
41
44
|
});
|
|
42
45
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -1184,12 +1187,78 @@ function createExtensionRegistry(extensions) {
|
|
|
1184
1187
|
};
|
|
1185
1188
|
}
|
|
1186
1189
|
|
|
1190
|
+
// src/json-schema/schema.ts
|
|
1191
|
+
var import_zod3 = require("zod");
|
|
1192
|
+
var jsonSchemaTypeSchema = import_zod3.z.enum([
|
|
1193
|
+
"string",
|
|
1194
|
+
"number",
|
|
1195
|
+
"integer",
|
|
1196
|
+
"boolean",
|
|
1197
|
+
"object",
|
|
1198
|
+
"array",
|
|
1199
|
+
"null"
|
|
1200
|
+
]);
|
|
1201
|
+
var jsonSchema7Schema = import_zod3.z.lazy(
|
|
1202
|
+
() => import_zod3.z.object({
|
|
1203
|
+
$schema: import_zod3.z.string().optional(),
|
|
1204
|
+
$id: import_zod3.z.string().optional(),
|
|
1205
|
+
$ref: import_zod3.z.string().optional(),
|
|
1206
|
+
// Metadata
|
|
1207
|
+
title: import_zod3.z.string().optional(),
|
|
1208
|
+
description: import_zod3.z.string().optional(),
|
|
1209
|
+
deprecated: import_zod3.z.boolean().optional(),
|
|
1210
|
+
// Type
|
|
1211
|
+
type: import_zod3.z.union([jsonSchemaTypeSchema, import_zod3.z.array(jsonSchemaTypeSchema)]).optional(),
|
|
1212
|
+
// String validation
|
|
1213
|
+
minLength: import_zod3.z.number().optional(),
|
|
1214
|
+
maxLength: import_zod3.z.number().optional(),
|
|
1215
|
+
pattern: import_zod3.z.string().optional(),
|
|
1216
|
+
// Number validation
|
|
1217
|
+
minimum: import_zod3.z.number().optional(),
|
|
1218
|
+
maximum: import_zod3.z.number().optional(),
|
|
1219
|
+
exclusiveMinimum: import_zod3.z.number().optional(),
|
|
1220
|
+
exclusiveMaximum: import_zod3.z.number().optional(),
|
|
1221
|
+
// Enum
|
|
1222
|
+
enum: import_zod3.z.array(import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])).readonly().optional(),
|
|
1223
|
+
const: import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()]).optional(),
|
|
1224
|
+
// Object
|
|
1225
|
+
properties: import_zod3.z.record(import_zod3.z.string(), jsonSchema7Schema).optional(),
|
|
1226
|
+
required: import_zod3.z.array(import_zod3.z.string()).optional(),
|
|
1227
|
+
additionalProperties: import_zod3.z.union([import_zod3.z.boolean(), jsonSchema7Schema]).optional(),
|
|
1228
|
+
// Array
|
|
1229
|
+
items: import_zod3.z.union([jsonSchema7Schema, import_zod3.z.array(jsonSchema7Schema)]).optional(),
|
|
1230
|
+
minItems: import_zod3.z.number().optional(),
|
|
1231
|
+
maxItems: import_zod3.z.number().optional(),
|
|
1232
|
+
// Composition
|
|
1233
|
+
allOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1234
|
+
anyOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1235
|
+
oneOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1236
|
+
not: jsonSchema7Schema.optional(),
|
|
1237
|
+
// Conditional
|
|
1238
|
+
if: jsonSchema7Schema.optional(),
|
|
1239
|
+
then: jsonSchema7Schema.optional(),
|
|
1240
|
+
else: jsonSchema7Schema.optional(),
|
|
1241
|
+
// Format
|
|
1242
|
+
format: import_zod3.z.string().optional(),
|
|
1243
|
+
// Default
|
|
1244
|
+
default: import_zod3.z.unknown().optional(),
|
|
1245
|
+
// FormSpec extensions
|
|
1246
|
+
"x-formspec-source": import_zod3.z.string().optional(),
|
|
1247
|
+
"x-formspec-params": import_zod3.z.array(import_zod3.z.string()).readonly().optional(),
|
|
1248
|
+
"x-formspec-schemaSource": import_zod3.z.string().optional()
|
|
1249
|
+
}).passthrough()
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1252
|
+
// src/generators/class-schema.ts
|
|
1253
|
+
var ts5 = require("typescript");
|
|
1254
|
+
|
|
1187
1255
|
// src/analyzer/program.ts
|
|
1188
1256
|
var ts4 = __toESM(require("typescript"), 1);
|
|
1189
1257
|
var path = __toESM(require("path"), 1);
|
|
1190
1258
|
|
|
1191
1259
|
// src/analyzer/class-analyzer.ts
|
|
1192
1260
|
var ts3 = __toESM(require("typescript"), 1);
|
|
1261
|
+
var import_internal2 = require("@formspec/analysis/internal");
|
|
1193
1262
|
|
|
1194
1263
|
// src/analyzer/jsdoc-constraints.ts
|
|
1195
1264
|
var ts2 = __toESM(require("typescript"), 1);
|
|
@@ -2112,9 +2181,17 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2112
2181
|
}
|
|
2113
2182
|
}
|
|
2114
2183
|
}
|
|
2184
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2185
|
+
fields,
|
|
2186
|
+
classDecl,
|
|
2187
|
+
classType,
|
|
2188
|
+
checker,
|
|
2189
|
+
file,
|
|
2190
|
+
diagnostics
|
|
2191
|
+
);
|
|
2115
2192
|
return {
|
|
2116
2193
|
name,
|
|
2117
|
-
fields,
|
|
2194
|
+
fields: specializedFields,
|
|
2118
2195
|
fieldLayouts,
|
|
2119
2196
|
typeRegistry,
|
|
2120
2197
|
...annotations.length > 0 && { annotations },
|
|
@@ -2154,10 +2231,18 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2154
2231
|
}
|
|
2155
2232
|
}
|
|
2156
2233
|
}
|
|
2157
|
-
const
|
|
2234
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2235
|
+
fields,
|
|
2236
|
+
interfaceDecl,
|
|
2237
|
+
interfaceType,
|
|
2238
|
+
checker,
|
|
2239
|
+
file,
|
|
2240
|
+
diagnostics
|
|
2241
|
+
);
|
|
2242
|
+
const fieldLayouts = specializedFields.map(() => ({}));
|
|
2158
2243
|
return {
|
|
2159
2244
|
name,
|
|
2160
|
-
fields,
|
|
2245
|
+
fields: specializedFields,
|
|
2161
2246
|
fieldLayouts,
|
|
2162
2247
|
typeRegistry,
|
|
2163
2248
|
...annotations.length > 0 && { annotations },
|
|
@@ -2206,12 +2291,20 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2206
2291
|
}
|
|
2207
2292
|
}
|
|
2208
2293
|
}
|
|
2294
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2295
|
+
fields,
|
|
2296
|
+
typeAlias,
|
|
2297
|
+
aliasType,
|
|
2298
|
+
checker,
|
|
2299
|
+
file,
|
|
2300
|
+
diagnostics
|
|
2301
|
+
);
|
|
2209
2302
|
return {
|
|
2210
2303
|
ok: true,
|
|
2211
2304
|
analysis: {
|
|
2212
2305
|
name,
|
|
2213
|
-
fields,
|
|
2214
|
-
fieldLayouts:
|
|
2306
|
+
fields: specializedFields,
|
|
2307
|
+
fieldLayouts: specializedFields.map(() => ({})),
|
|
2215
2308
|
typeRegistry,
|
|
2216
2309
|
...annotations.length > 0 && { annotations },
|
|
2217
2310
|
...diagnostics.length > 0 && { diagnostics },
|
|
@@ -2220,6 +2313,396 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2220
2313
|
}
|
|
2221
2314
|
};
|
|
2222
2315
|
}
|
|
2316
|
+
function makeAnalysisDiagnostic(code, message, primaryLocation, relatedLocations = []) {
|
|
2317
|
+
return {
|
|
2318
|
+
code,
|
|
2319
|
+
message,
|
|
2320
|
+
severity: "error",
|
|
2321
|
+
primaryLocation,
|
|
2322
|
+
relatedLocations
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
function getLeadingParsedTags(node) {
|
|
2326
|
+
const sourceFile = node.getSourceFile();
|
|
2327
|
+
const sourceText = sourceFile.getFullText();
|
|
2328
|
+
const commentRanges = ts3.getLeadingCommentRanges(sourceText, node.getFullStart());
|
|
2329
|
+
if (commentRanges === void 0) {
|
|
2330
|
+
return [];
|
|
2331
|
+
}
|
|
2332
|
+
const parsedTags = [];
|
|
2333
|
+
for (const range of commentRanges) {
|
|
2334
|
+
if (range.kind !== ts3.SyntaxKind.MultiLineCommentTrivia) {
|
|
2335
|
+
continue;
|
|
2336
|
+
}
|
|
2337
|
+
const commentText = sourceText.slice(range.pos, range.end);
|
|
2338
|
+
if (!commentText.startsWith("/**")) {
|
|
2339
|
+
continue;
|
|
2340
|
+
}
|
|
2341
|
+
parsedTags.push(...(0, import_internal2.parseCommentBlock)(commentText, { offset: range.pos }).tags);
|
|
2342
|
+
}
|
|
2343
|
+
return parsedTags;
|
|
2344
|
+
}
|
|
2345
|
+
function findDiscriminatorProperty(node, fieldName) {
|
|
2346
|
+
if (ts3.isClassDeclaration(node)) {
|
|
2347
|
+
for (const member of node.members) {
|
|
2348
|
+
if (ts3.isPropertyDeclaration(member) && ts3.isIdentifier(member.name) && member.name.text === fieldName) {
|
|
2349
|
+
return member;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
return null;
|
|
2353
|
+
}
|
|
2354
|
+
if (ts3.isInterfaceDeclaration(node)) {
|
|
2355
|
+
for (const member of node.members) {
|
|
2356
|
+
if (ts3.isPropertySignature(member) && ts3.isIdentifier(member.name) && member.name.text === fieldName) {
|
|
2357
|
+
return member;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
return null;
|
|
2361
|
+
}
|
|
2362
|
+
if (ts3.isTypeLiteralNode(node.type)) {
|
|
2363
|
+
for (const member of node.type.members) {
|
|
2364
|
+
if (ts3.isPropertySignature(member) && ts3.isIdentifier(member.name) && member.name.text === fieldName) {
|
|
2365
|
+
return member;
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
return null;
|
|
2370
|
+
}
|
|
2371
|
+
function isLocalTypeParameterName(node, typeParameterName) {
|
|
2372
|
+
return node.typeParameters?.some((typeParameter) => typeParameter.name.text === typeParameterName) ?? false;
|
|
2373
|
+
}
|
|
2374
|
+
function isNullishSemanticType(type) {
|
|
2375
|
+
if (type.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined | ts3.TypeFlags.Void | ts3.TypeFlags.Unknown | ts3.TypeFlags.Any)) {
|
|
2376
|
+
return true;
|
|
2377
|
+
}
|
|
2378
|
+
return type.isUnion() && type.types.some((member) => isNullishSemanticType(member));
|
|
2379
|
+
}
|
|
2380
|
+
function isStringLikeSemanticType(type) {
|
|
2381
|
+
if (type.flags & ts3.TypeFlags.StringLike) {
|
|
2382
|
+
return true;
|
|
2383
|
+
}
|
|
2384
|
+
if (type.isUnion()) {
|
|
2385
|
+
return type.types.length > 0 && type.types.every((member) => isStringLikeSemanticType(member));
|
|
2386
|
+
}
|
|
2387
|
+
return false;
|
|
2388
|
+
}
|
|
2389
|
+
function extractDiscriminatorDirective(node, file, diagnostics) {
|
|
2390
|
+
const discriminatorTags = getLeadingParsedTags(node).filter(
|
|
2391
|
+
(tag) => tag.normalizedTagName === "discriminator"
|
|
2392
|
+
);
|
|
2393
|
+
if (discriminatorTags.length === 0) {
|
|
2394
|
+
return null;
|
|
2395
|
+
}
|
|
2396
|
+
const [firstTag, ...duplicateTags] = discriminatorTags;
|
|
2397
|
+
for (const _duplicateTag of duplicateTags) {
|
|
2398
|
+
diagnostics.push(
|
|
2399
|
+
makeAnalysisDiagnostic(
|
|
2400
|
+
"DUPLICATE_TAG",
|
|
2401
|
+
'Duplicate "@discriminator" tag. Only one discriminator declaration is allowed per declaration.',
|
|
2402
|
+
provenanceForNode(node, file)
|
|
2403
|
+
)
|
|
2404
|
+
);
|
|
2405
|
+
}
|
|
2406
|
+
if (firstTag === void 0) {
|
|
2407
|
+
return null;
|
|
2408
|
+
}
|
|
2409
|
+
const firstTarget = firstTag.target;
|
|
2410
|
+
if (firstTarget?.path === null || firstTarget?.valid !== true) {
|
|
2411
|
+
diagnostics.push(
|
|
2412
|
+
makeAnalysisDiagnostic(
|
|
2413
|
+
"INVALID_TAG_ARGUMENT",
|
|
2414
|
+
'Tag "@discriminator" requires a direct path target like ":kind".',
|
|
2415
|
+
provenanceForNode(node, file)
|
|
2416
|
+
)
|
|
2417
|
+
);
|
|
2418
|
+
return null;
|
|
2419
|
+
}
|
|
2420
|
+
if (firstTarget.path.segments.length !== 1) {
|
|
2421
|
+
diagnostics.push(
|
|
2422
|
+
makeAnalysisDiagnostic(
|
|
2423
|
+
"INVALID_TAG_ARGUMENT",
|
|
2424
|
+
'Tag "@discriminator" only supports direct property targets in v1; nested paths are out of scope.',
|
|
2425
|
+
provenanceForNode(node, file)
|
|
2426
|
+
)
|
|
2427
|
+
);
|
|
2428
|
+
return null;
|
|
2429
|
+
}
|
|
2430
|
+
const typeParameterName = firstTag.argumentText.trim();
|
|
2431
|
+
if (!/^[A-Za-z_$][\w$]*$/u.test(typeParameterName)) {
|
|
2432
|
+
diagnostics.push(
|
|
2433
|
+
makeAnalysisDiagnostic(
|
|
2434
|
+
"INVALID_TAG_ARGUMENT",
|
|
2435
|
+
'Tag "@discriminator" requires a local type parameter name as its source operand.',
|
|
2436
|
+
provenanceForNode(node, file)
|
|
2437
|
+
)
|
|
2438
|
+
);
|
|
2439
|
+
return null;
|
|
2440
|
+
}
|
|
2441
|
+
return {
|
|
2442
|
+
fieldName: firstTarget.path.segments[0] ?? firstTarget.rawText,
|
|
2443
|
+
typeParameterName,
|
|
2444
|
+
provenance: provenanceForNode(node, file)
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
function validateDiscriminatorDirective(node, checker, file, diagnostics) {
|
|
2448
|
+
const directive = extractDiscriminatorDirective(node, file, diagnostics);
|
|
2449
|
+
if (directive === null) {
|
|
2450
|
+
return null;
|
|
2451
|
+
}
|
|
2452
|
+
if (!isLocalTypeParameterName(node, directive.typeParameterName)) {
|
|
2453
|
+
diagnostics.push(
|
|
2454
|
+
makeAnalysisDiagnostic(
|
|
2455
|
+
"INVALID_TAG_ARGUMENT",
|
|
2456
|
+
`Tag "@discriminator" references "${directive.typeParameterName}", but the source operand must be a type parameter declared on the same declaration.`,
|
|
2457
|
+
directive.provenance
|
|
2458
|
+
)
|
|
2459
|
+
);
|
|
2460
|
+
return null;
|
|
2461
|
+
}
|
|
2462
|
+
const propertyDecl = findDiscriminatorProperty(node, directive.fieldName);
|
|
2463
|
+
if (propertyDecl === null) {
|
|
2464
|
+
diagnostics.push(
|
|
2465
|
+
makeAnalysisDiagnostic(
|
|
2466
|
+
"UNKNOWN_PATH_TARGET",
|
|
2467
|
+
`Tag "@discriminator" targets "${directive.fieldName}", but no direct property with that name exists on this declaration.`,
|
|
2468
|
+
directive.provenance
|
|
2469
|
+
)
|
|
2470
|
+
);
|
|
2471
|
+
return null;
|
|
2472
|
+
}
|
|
2473
|
+
if (propertyDecl.questionToken !== void 0) {
|
|
2474
|
+
diagnostics.push(
|
|
2475
|
+
makeAnalysisDiagnostic(
|
|
2476
|
+
"TYPE_MISMATCH",
|
|
2477
|
+
`Discriminator field "${directive.fieldName}" must be required; optional discriminator fields are not supported.`,
|
|
2478
|
+
directive.provenance,
|
|
2479
|
+
[provenanceForNode(propertyDecl, file)]
|
|
2480
|
+
)
|
|
2481
|
+
);
|
|
2482
|
+
return null;
|
|
2483
|
+
}
|
|
2484
|
+
const propertyType = checker.getTypeAtLocation(propertyDecl);
|
|
2485
|
+
if (isNullishSemanticType(propertyType)) {
|
|
2486
|
+
diagnostics.push(
|
|
2487
|
+
makeAnalysisDiagnostic(
|
|
2488
|
+
"TYPE_MISMATCH",
|
|
2489
|
+
`Discriminator field "${directive.fieldName}" must not be nullable.`,
|
|
2490
|
+
directive.provenance,
|
|
2491
|
+
[provenanceForNode(propertyDecl, file)]
|
|
2492
|
+
)
|
|
2493
|
+
);
|
|
2494
|
+
return null;
|
|
2495
|
+
}
|
|
2496
|
+
if (!isStringLikeSemanticType(propertyType)) {
|
|
2497
|
+
diagnostics.push(
|
|
2498
|
+
makeAnalysisDiagnostic(
|
|
2499
|
+
"TYPE_MISMATCH",
|
|
2500
|
+
`Discriminator field "${directive.fieldName}" must be string-like.`,
|
|
2501
|
+
directive.provenance,
|
|
2502
|
+
[provenanceForNode(propertyDecl, file)]
|
|
2503
|
+
)
|
|
2504
|
+
);
|
|
2505
|
+
return null;
|
|
2506
|
+
}
|
|
2507
|
+
return directive;
|
|
2508
|
+
}
|
|
2509
|
+
function getConcreteTypeArgumentForDiscriminator(node, subjectType, checker, typeParameterName) {
|
|
2510
|
+
const typeParameterIndex = node.typeParameters?.findIndex(
|
|
2511
|
+
(typeParameter) => typeParameter.name.text === typeParameterName
|
|
2512
|
+
) ?? -1;
|
|
2513
|
+
if (typeParameterIndex < 0) {
|
|
2514
|
+
return null;
|
|
2515
|
+
}
|
|
2516
|
+
const referenceTypeArguments = (isTypeReference(subjectType) ? subjectType.typeArguments : void 0) ?? subjectType.aliasTypeArguments;
|
|
2517
|
+
if (referenceTypeArguments?.[typeParameterIndex] !== void 0) {
|
|
2518
|
+
return referenceTypeArguments[typeParameterIndex] ?? null;
|
|
2519
|
+
}
|
|
2520
|
+
const localTypeParameter = node.typeParameters?.[typeParameterIndex];
|
|
2521
|
+
return localTypeParameter === void 0 ? null : checker.getTypeAtLocation(localTypeParameter);
|
|
2522
|
+
}
|
|
2523
|
+
function extractDeclarationApiName(node) {
|
|
2524
|
+
for (const tag of getLeadingParsedTags(node)) {
|
|
2525
|
+
if (tag.normalizedTagName !== "apiName") {
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
if (tag.target === null && tag.argumentText.trim() !== "") {
|
|
2529
|
+
return tag.argumentText.trim();
|
|
2530
|
+
}
|
|
2531
|
+
if (tag.target?.kind === "variant" && tag.target.rawText === "singular") {
|
|
2532
|
+
const value = tag.argumentText.trim();
|
|
2533
|
+
if (value !== "") {
|
|
2534
|
+
return value;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
return null;
|
|
2539
|
+
}
|
|
2540
|
+
function inferJsonFacingName(name) {
|
|
2541
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
|
|
2542
|
+
}
|
|
2543
|
+
function resolveNamedDiscriminatorDeclaration(type, checker, seen = /* @__PURE__ */ new Set()) {
|
|
2544
|
+
if (seen.has(type)) {
|
|
2545
|
+
return null;
|
|
2546
|
+
}
|
|
2547
|
+
seen.add(type);
|
|
2548
|
+
const symbol = type.aliasSymbol ?? type.getSymbol();
|
|
2549
|
+
if (symbol !== void 0) {
|
|
2550
|
+
const aliased = symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : void 0;
|
|
2551
|
+
const targetSymbol = aliased ?? symbol;
|
|
2552
|
+
const declaration = targetSymbol.declarations?.find(
|
|
2553
|
+
(candidate) => ts3.isClassDeclaration(candidate) || ts3.isInterfaceDeclaration(candidate) || ts3.isTypeAliasDeclaration(candidate) || ts3.isEnumDeclaration(candidate)
|
|
2554
|
+
);
|
|
2555
|
+
if (declaration !== void 0) {
|
|
2556
|
+
if (ts3.isTypeAliasDeclaration(declaration) && ts3.isTypeReferenceNode(declaration.type) && checker.getTypeFromTypeNode(declaration.type) !== type) {
|
|
2557
|
+
return resolveNamedDiscriminatorDeclaration(
|
|
2558
|
+
checker.getTypeFromTypeNode(declaration.type),
|
|
2559
|
+
checker,
|
|
2560
|
+
seen
|
|
2561
|
+
);
|
|
2562
|
+
}
|
|
2563
|
+
return declaration;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
function resolveDiscriminatorValue(boundType, checker, provenance, diagnostics) {
|
|
2569
|
+
if (boundType === null) {
|
|
2570
|
+
diagnostics.push(
|
|
2571
|
+
makeAnalysisDiagnostic(
|
|
2572
|
+
"INVALID_TAG_ARGUMENT",
|
|
2573
|
+
"Discriminator resolution failed because no concrete type argument is available for the referenced type parameter.",
|
|
2574
|
+
provenance
|
|
2575
|
+
)
|
|
2576
|
+
);
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
if (boundType.isStringLiteral()) {
|
|
2580
|
+
return boundType.value;
|
|
2581
|
+
}
|
|
2582
|
+
if (boundType.isUnion()) {
|
|
2583
|
+
const nonNullMembers = boundType.types.filter(
|
|
2584
|
+
(member) => !(member.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
|
|
2585
|
+
);
|
|
2586
|
+
if (nonNullMembers.every((member) => member.isStringLiteral())) {
|
|
2587
|
+
diagnostics.push(
|
|
2588
|
+
makeAnalysisDiagnostic(
|
|
2589
|
+
"INVALID_TAG_ARGUMENT",
|
|
2590
|
+
"Discriminator resolution for unions of string literals is out of scope for v1.",
|
|
2591
|
+
provenance
|
|
2592
|
+
)
|
|
2593
|
+
);
|
|
2594
|
+
return null;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
const declaration = resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
2598
|
+
if (declaration !== null) {
|
|
2599
|
+
return extractDeclarationApiName(declaration) ?? inferJsonFacingName(getDeclarationName(declaration));
|
|
2600
|
+
}
|
|
2601
|
+
diagnostics.push(
|
|
2602
|
+
makeAnalysisDiagnostic(
|
|
2603
|
+
"INVALID_TAG_ARGUMENT",
|
|
2604
|
+
"Discriminator resolution could not derive a JSON-facing discriminator value from the referenced type argument.",
|
|
2605
|
+
provenance
|
|
2606
|
+
)
|
|
2607
|
+
);
|
|
2608
|
+
return null;
|
|
2609
|
+
}
|
|
2610
|
+
function getDeclarationName(node) {
|
|
2611
|
+
if (ts3.isClassDeclaration(node) || ts3.isInterfaceDeclaration(node) || ts3.isTypeAliasDeclaration(node) || ts3.isEnumDeclaration(node)) {
|
|
2612
|
+
return node.name?.text ?? "anonymous";
|
|
2613
|
+
}
|
|
2614
|
+
return "anonymous";
|
|
2615
|
+
}
|
|
2616
|
+
function applyDeclarationDiscriminatorToFields(fields, node, subjectType, checker, file, diagnostics) {
|
|
2617
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
2618
|
+
if (directive === null) {
|
|
2619
|
+
return [...fields];
|
|
2620
|
+
}
|
|
2621
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
2622
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
2623
|
+
node,
|
|
2624
|
+
subjectType,
|
|
2625
|
+
checker,
|
|
2626
|
+
directive.typeParameterName
|
|
2627
|
+
),
|
|
2628
|
+
checker,
|
|
2629
|
+
directive.provenance,
|
|
2630
|
+
diagnostics
|
|
2631
|
+
);
|
|
2632
|
+
if (discriminatorValue === null) {
|
|
2633
|
+
return [...fields];
|
|
2634
|
+
}
|
|
2635
|
+
return fields.map(
|
|
2636
|
+
(field) => field.name === directive.fieldName ? {
|
|
2637
|
+
...field,
|
|
2638
|
+
type: {
|
|
2639
|
+
kind: "enum",
|
|
2640
|
+
members: [{ value: discriminatorValue }]
|
|
2641
|
+
}
|
|
2642
|
+
} : field
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2645
|
+
function buildInstantiatedReferenceName(baseName, typeArguments, checker) {
|
|
2646
|
+
const renderedArguments = typeArguments.map(
|
|
2647
|
+
(typeArgument) => checker.typeToString(typeArgument).replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "")
|
|
2648
|
+
).filter((value) => value !== "");
|
|
2649
|
+
return renderedArguments.length === 0 ? baseName : `${baseName}__${renderedArguments.join("__")}`;
|
|
2650
|
+
}
|
|
2651
|
+
function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
2652
|
+
const typeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
2653
|
+
if (typeNode === void 0) {
|
|
2654
|
+
return [];
|
|
2655
|
+
}
|
|
2656
|
+
const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
|
|
2657
|
+
if (!ts3.isTypeReferenceNode(resolvedTypeNode) || resolvedTypeNode.typeArguments === void 0) {
|
|
2658
|
+
return [];
|
|
2659
|
+
}
|
|
2660
|
+
return resolvedTypeNode.typeArguments.map((argumentNode) => {
|
|
2661
|
+
const argumentType = checker.getTypeFromTypeNode(argumentNode);
|
|
2662
|
+
return {
|
|
2663
|
+
tsType: argumentType,
|
|
2664
|
+
typeNode: resolveTypeNode(
|
|
2665
|
+
argumentType,
|
|
2666
|
+
checker,
|
|
2667
|
+
file,
|
|
2668
|
+
typeRegistry,
|
|
2669
|
+
visiting,
|
|
2670
|
+
argumentNode,
|
|
2671
|
+
extensionRegistry,
|
|
2672
|
+
diagnostics
|
|
2673
|
+
)
|
|
2674
|
+
};
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
function applyDiscriminatorToObjectProperties(properties, node, subjectType, checker, file, diagnostics) {
|
|
2678
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
2679
|
+
if (directive === null) {
|
|
2680
|
+
return properties;
|
|
2681
|
+
}
|
|
2682
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
2683
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
2684
|
+
node,
|
|
2685
|
+
subjectType,
|
|
2686
|
+
checker,
|
|
2687
|
+
directive.typeParameterName
|
|
2688
|
+
),
|
|
2689
|
+
checker,
|
|
2690
|
+
directive.provenance,
|
|
2691
|
+
diagnostics
|
|
2692
|
+
);
|
|
2693
|
+
if (discriminatorValue === null) {
|
|
2694
|
+
return properties;
|
|
2695
|
+
}
|
|
2696
|
+
return properties.map(
|
|
2697
|
+
(property) => property.name === directive.fieldName ? {
|
|
2698
|
+
...property,
|
|
2699
|
+
type: {
|
|
2700
|
+
kind: "enum",
|
|
2701
|
+
members: [{ value: discriminatorValue }]
|
|
2702
|
+
}
|
|
2703
|
+
} : property
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2223
2706
|
function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, extensionRegistry) {
|
|
2224
2707
|
if (!ts3.isIdentifier(prop.name)) {
|
|
2225
2708
|
return null;
|
|
@@ -2508,6 +2991,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2508
2991
|
file,
|
|
2509
2992
|
typeRegistry,
|
|
2510
2993
|
visiting,
|
|
2994
|
+
sourceNode,
|
|
2511
2995
|
extensionRegistry,
|
|
2512
2996
|
diagnostics
|
|
2513
2997
|
);
|
|
@@ -2771,35 +3255,60 @@ function typeNodeContainsReference(type, targetName) {
|
|
|
2771
3255
|
}
|
|
2772
3256
|
}
|
|
2773
3257
|
}
|
|
2774
|
-
function resolveObjectType(type, checker, file, typeRegistry, visiting, extensionRegistry, diagnostics) {
|
|
3258
|
+
function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3259
|
+
const collectedDiagnostics = diagnostics ?? [];
|
|
2775
3260
|
const typeName = getNamedTypeName(type);
|
|
2776
3261
|
const namedTypeName = typeName ?? void 0;
|
|
2777
3262
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2778
|
-
const
|
|
3263
|
+
const referenceTypeArguments = extractReferenceTypeArguments(
|
|
3264
|
+
type,
|
|
3265
|
+
checker,
|
|
3266
|
+
file,
|
|
3267
|
+
typeRegistry,
|
|
3268
|
+
visiting,
|
|
3269
|
+
sourceNode,
|
|
3270
|
+
extensionRegistry,
|
|
3271
|
+
collectedDiagnostics
|
|
3272
|
+
);
|
|
3273
|
+
const instantiatedTypeName = namedTypeName !== void 0 && referenceTypeArguments.length > 0 ? buildInstantiatedReferenceName(
|
|
3274
|
+
namedTypeName,
|
|
3275
|
+
referenceTypeArguments.map((argument) => argument.tsType),
|
|
3276
|
+
checker
|
|
3277
|
+
) : void 0;
|
|
3278
|
+
const registryTypeName = instantiatedTypeName ?? namedTypeName;
|
|
3279
|
+
const shouldRegisterNamedType = registryTypeName !== void 0 && !(registryTypeName === "Record" && namedDecl?.getSourceFile().fileName !== file);
|
|
2779
3280
|
const clearNamedTypeRegistration = () => {
|
|
2780
|
-
if (
|
|
3281
|
+
if (registryTypeName === void 0 || !shouldRegisterNamedType) {
|
|
2781
3282
|
return;
|
|
2782
3283
|
}
|
|
2783
|
-
Reflect.deleteProperty(typeRegistry,
|
|
3284
|
+
Reflect.deleteProperty(typeRegistry, registryTypeName);
|
|
2784
3285
|
};
|
|
2785
3286
|
if (visiting.has(type)) {
|
|
2786
|
-
if (
|
|
2787
|
-
return {
|
|
3287
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
3288
|
+
return {
|
|
3289
|
+
kind: "reference",
|
|
3290
|
+
name: registryTypeName,
|
|
3291
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
3292
|
+
};
|
|
2788
3293
|
}
|
|
2789
3294
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
2790
3295
|
}
|
|
2791
|
-
if (
|
|
2792
|
-
typeRegistry[
|
|
2793
|
-
name:
|
|
3296
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && !typeRegistry[registryTypeName]) {
|
|
3297
|
+
typeRegistry[registryTypeName] = {
|
|
3298
|
+
name: registryTypeName,
|
|
2794
3299
|
type: RESOLVING_TYPE_PLACEHOLDER,
|
|
2795
3300
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2796
3301
|
};
|
|
2797
3302
|
}
|
|
2798
3303
|
visiting.add(type);
|
|
2799
|
-
if (
|
|
2800
|
-
if (typeRegistry[
|
|
3304
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && typeRegistry[registryTypeName]?.type !== void 0) {
|
|
3305
|
+
if (typeRegistry[registryTypeName].type !== RESOLVING_TYPE_PLACEHOLDER) {
|
|
2801
3306
|
visiting.delete(type);
|
|
2802
|
-
return {
|
|
3307
|
+
return {
|
|
3308
|
+
kind: "reference",
|
|
3309
|
+
name: registryTypeName,
|
|
3310
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
3311
|
+
};
|
|
2803
3312
|
}
|
|
2804
3313
|
}
|
|
2805
3314
|
const recordNode = tryResolveRecordType(
|
|
@@ -2809,24 +3318,28 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2809
3318
|
typeRegistry,
|
|
2810
3319
|
visiting,
|
|
2811
3320
|
extensionRegistry,
|
|
2812
|
-
|
|
3321
|
+
collectedDiagnostics
|
|
2813
3322
|
);
|
|
2814
3323
|
if (recordNode) {
|
|
2815
3324
|
visiting.delete(type);
|
|
2816
|
-
if (
|
|
2817
|
-
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType,
|
|
3325
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
3326
|
+
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType, registryTypeName);
|
|
2818
3327
|
if (!isRecursiveRecord) {
|
|
2819
3328
|
clearNamedTypeRegistration();
|
|
2820
3329
|
return recordNode;
|
|
2821
3330
|
}
|
|
2822
3331
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2823
|
-
typeRegistry[
|
|
2824
|
-
name:
|
|
3332
|
+
typeRegistry[registryTypeName] = {
|
|
3333
|
+
name: registryTypeName,
|
|
2825
3334
|
type: recordNode,
|
|
2826
3335
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2827
3336
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2828
3337
|
};
|
|
2829
|
-
return {
|
|
3338
|
+
return {
|
|
3339
|
+
kind: "reference",
|
|
3340
|
+
name: registryTypeName,
|
|
3341
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
3342
|
+
};
|
|
2830
3343
|
}
|
|
2831
3344
|
return recordNode;
|
|
2832
3345
|
}
|
|
@@ -2837,7 +3350,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2837
3350
|
file,
|
|
2838
3351
|
typeRegistry,
|
|
2839
3352
|
visiting,
|
|
2840
|
-
|
|
3353
|
+
collectedDiagnostics,
|
|
2841
3354
|
extensionRegistry
|
|
2842
3355
|
);
|
|
2843
3356
|
for (const prop of type.getProperties()) {
|
|
@@ -2853,7 +3366,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2853
3366
|
visiting,
|
|
2854
3367
|
declaration,
|
|
2855
3368
|
extensionRegistry,
|
|
2856
|
-
|
|
3369
|
+
collectedDiagnostics
|
|
2857
3370
|
);
|
|
2858
3371
|
const fieldNodeInfo = fieldInfoMap?.get(prop.name);
|
|
2859
3372
|
properties.push({
|
|
@@ -2868,18 +3381,29 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2868
3381
|
visiting.delete(type);
|
|
2869
3382
|
const objectNode = {
|
|
2870
3383
|
kind: "object",
|
|
2871
|
-
properties
|
|
3384
|
+
properties: namedDecl !== void 0 && (ts3.isClassDeclaration(namedDecl) || ts3.isInterfaceDeclaration(namedDecl) || ts3.isTypeAliasDeclaration(namedDecl)) ? applyDiscriminatorToObjectProperties(
|
|
3385
|
+
properties,
|
|
3386
|
+
namedDecl,
|
|
3387
|
+
type,
|
|
3388
|
+
checker,
|
|
3389
|
+
file,
|
|
3390
|
+
collectedDiagnostics
|
|
3391
|
+
) : properties,
|
|
2872
3392
|
additionalProperties: true
|
|
2873
3393
|
};
|
|
2874
|
-
if (
|
|
3394
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
2875
3395
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2876
|
-
typeRegistry[
|
|
2877
|
-
name:
|
|
3396
|
+
typeRegistry[registryTypeName] = {
|
|
3397
|
+
name: registryTypeName,
|
|
2878
3398
|
type: objectNode,
|
|
2879
3399
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2880
3400
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2881
3401
|
};
|
|
2882
|
-
return {
|
|
3402
|
+
return {
|
|
3403
|
+
kind: "reference",
|
|
3404
|
+
name: registryTypeName,
|
|
3405
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
3406
|
+
};
|
|
2883
3407
|
}
|
|
2884
3408
|
return objectNode;
|
|
2885
3409
|
}
|
|
@@ -3140,6 +3664,18 @@ function detectFormSpecReference(typeNode) {
|
|
|
3140
3664
|
}
|
|
3141
3665
|
|
|
3142
3666
|
// src/analyzer/program.ts
|
|
3667
|
+
function createProgramContextFromProgram(program, filePath) {
|
|
3668
|
+
const absolutePath = path.resolve(filePath);
|
|
3669
|
+
const sourceFile = program.getSourceFile(absolutePath) ?? program.getSourceFile(filePath);
|
|
3670
|
+
if (!sourceFile) {
|
|
3671
|
+
throw new Error(`Could not find source file in provided program: ${absolutePath}`);
|
|
3672
|
+
}
|
|
3673
|
+
return {
|
|
3674
|
+
program,
|
|
3675
|
+
checker: program.getTypeChecker(),
|
|
3676
|
+
sourceFile
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3143
3679
|
function createProgramContext(filePath) {
|
|
3144
3680
|
const absolutePath = path.resolve(filePath);
|
|
3145
3681
|
const fileDir = path.dirname(absolutePath);
|
|
@@ -3210,31 +3746,40 @@ function findTypeAliasByName(sourceFile, aliasName) {
|
|
|
3210
3746
|
}
|
|
3211
3747
|
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry) {
|
|
3212
3748
|
const ctx = createProgramContext(filePath);
|
|
3749
|
+
return analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry);
|
|
3750
|
+
}
|
|
3751
|
+
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry) {
|
|
3752
|
+
const analysisFilePath = path.resolve(filePath);
|
|
3213
3753
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
3214
3754
|
if (classDecl !== null) {
|
|
3215
|
-
return analyzeClassToIR(classDecl, ctx.checker,
|
|
3755
|
+
return analyzeClassToIR(classDecl, ctx.checker, analysisFilePath, extensionRegistry);
|
|
3216
3756
|
}
|
|
3217
3757
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
|
|
3218
3758
|
if (interfaceDecl !== null) {
|
|
3219
|
-
return analyzeInterfaceToIR(interfaceDecl, ctx.checker,
|
|
3759
|
+
return analyzeInterfaceToIR(interfaceDecl, ctx.checker, analysisFilePath, extensionRegistry);
|
|
3220
3760
|
}
|
|
3221
3761
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
|
|
3222
3762
|
if (typeAlias !== null) {
|
|
3223
|
-
const result = analyzeTypeAliasToIR(
|
|
3763
|
+
const result = analyzeTypeAliasToIR(
|
|
3764
|
+
typeAlias,
|
|
3765
|
+
ctx.checker,
|
|
3766
|
+
analysisFilePath,
|
|
3767
|
+
extensionRegistry
|
|
3768
|
+
);
|
|
3224
3769
|
if (result.ok) {
|
|
3225
3770
|
return result.analysis;
|
|
3226
3771
|
}
|
|
3227
3772
|
throw new Error(result.error);
|
|
3228
3773
|
}
|
|
3229
3774
|
throw new Error(
|
|
3230
|
-
`Type "${typeName}" not found as a class, interface, or type alias in ${
|
|
3775
|
+
`Type "${typeName}" not found as a class, interface, or type alias in ${analysisFilePath}`
|
|
3231
3776
|
);
|
|
3232
3777
|
}
|
|
3233
3778
|
|
|
3234
3779
|
// src/validate/constraint-validator.ts
|
|
3235
|
-
var
|
|
3780
|
+
var import_internal3 = require("@formspec/analysis/internal");
|
|
3236
3781
|
function validateFieldNode(ctx, field) {
|
|
3237
|
-
const analysis = (0,
|
|
3782
|
+
const analysis = (0, import_internal3.analyzeConstraintTargets)(
|
|
3238
3783
|
field.name,
|
|
3239
3784
|
field.type,
|
|
3240
3785
|
field.constraints,
|
|
@@ -3252,7 +3797,7 @@ function validateFieldNode(ctx, field) {
|
|
|
3252
3797
|
}
|
|
3253
3798
|
function validateObjectProperty(ctx, parentName, property) {
|
|
3254
3799
|
const qualifiedName = `${parentName}.${property.name}`;
|
|
3255
|
-
const analysis = (0,
|
|
3800
|
+
const analysis = (0, import_internal3.analyzeConstraintTargets)(
|
|
3256
3801
|
qualifiedName,
|
|
3257
3802
|
property.type,
|
|
3258
3803
|
property.constraints,
|
|
@@ -3361,12 +3906,28 @@ function generateSchemasFromClass(options) {
|
|
|
3361
3906
|
);
|
|
3362
3907
|
}
|
|
3363
3908
|
function generateSchemas(options) {
|
|
3364
|
-
const
|
|
3909
|
+
const ctx = createProgramContext(options.filePath);
|
|
3910
|
+
return generateSchemasFromProgram({
|
|
3911
|
+
...options,
|
|
3912
|
+
program: ctx.program
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
function generateSchemasFromProgram(options) {
|
|
3916
|
+
const ctx = createProgramContextFromProgram(options.program, options.filePath);
|
|
3917
|
+
const analysis = analyzeNamedTypeToIRFromProgramContext(
|
|
3918
|
+
ctx,
|
|
3365
3919
|
options.filePath,
|
|
3366
3920
|
options.typeName,
|
|
3367
3921
|
options.extensionRegistry
|
|
3368
3922
|
);
|
|
3369
|
-
return generateClassSchemas(
|
|
3923
|
+
return generateClassSchemas(
|
|
3924
|
+
analysis,
|
|
3925
|
+
{ file: options.filePath },
|
|
3926
|
+
{
|
|
3927
|
+
extensionRegistry: options.extensionRegistry,
|
|
3928
|
+
vendorPrefix: options.vendorPrefix
|
|
3929
|
+
}
|
|
3930
|
+
);
|
|
3370
3931
|
}
|
|
3371
3932
|
|
|
3372
3933
|
// src/generators/mixed-authoring.ts
|
|
@@ -3573,7 +4134,10 @@ function writeSchemas(form, options) {
|
|
|
3573
4134
|
generateJsonSchema,
|
|
3574
4135
|
generateSchemas,
|
|
3575
4136
|
generateSchemasFromClass,
|
|
4137
|
+
generateSchemasFromProgram,
|
|
3576
4138
|
generateUiSchema,
|
|
4139
|
+
jsonSchema7Schema,
|
|
4140
|
+
uiSchemaSchema,
|
|
3577
4141
|
writeSchemas
|
|
3578
4142
|
});
|
|
3579
4143
|
//# sourceMappingURL=index.cjs.map
|