@formspec/build 0.1.0-alpha.16 → 0.1.0-alpha.17
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/__tests__/fixtures/example-numeric-extension.d.ts +20 -0
- package/dist/__tests__/fixtures/example-numeric-extension.d.ts.map +1 -0
- package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts +1 -0
- package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts.map +1 -1
- package/dist/__tests__/numeric-extension.integration.test.d.ts +2 -0
- package/dist/__tests__/numeric-extension.integration.test.d.ts.map +1 -0
- package/dist/analyzer/class-analyzer.d.ts +5 -4
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/jsdoc-constraints.d.ts +3 -2
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +18 -2
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +199 -4
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +199 -4
- package/dist/browser.js.map +1 -1
- package/dist/build.d.ts +28 -2
- package/dist/cli.cjs +547 -84
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +547 -84
- package/dist/cli.js.map +1 -1
- package/dist/extensions/registry.d.ts +25 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/generators/class-schema.d.ts +4 -4
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/index.cjs +546 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +546 -84
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +645 -73
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +643 -71
- package/dist/internals.js.map +1 -1
- package/dist/validate/constraint-validator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/cli.cjs
CHANGED
|
@@ -829,7 +829,12 @@ function applyCustomConstraint(schema, constraint, ctx) {
|
|
|
829
829
|
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
830
830
|
);
|
|
831
831
|
}
|
|
832
|
-
|
|
832
|
+
assignVendorPrefixedExtensionKeywords(
|
|
833
|
+
schema,
|
|
834
|
+
registration.toJsonSchema(constraint.payload, ctx.vendorPrefix),
|
|
835
|
+
ctx.vendorPrefix,
|
|
836
|
+
`custom constraint "${constraint.constraintId}"`
|
|
837
|
+
);
|
|
833
838
|
}
|
|
834
839
|
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
835
840
|
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
@@ -841,7 +846,22 @@ function applyCustomAnnotation(schema, annotation, ctx) {
|
|
|
841
846
|
if (registration.toJsonSchema === void 0) {
|
|
842
847
|
return;
|
|
843
848
|
}
|
|
844
|
-
|
|
849
|
+
assignVendorPrefixedExtensionKeywords(
|
|
850
|
+
schema,
|
|
851
|
+
registration.toJsonSchema(annotation.value, ctx.vendorPrefix),
|
|
852
|
+
ctx.vendorPrefix,
|
|
853
|
+
`custom annotation "${annotation.annotationId}"`
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPrefix, source) {
|
|
857
|
+
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
858
|
+
if (!key.startsWith(`${vendorPrefix}-`)) {
|
|
859
|
+
throw new Error(
|
|
860
|
+
`Cannot apply ${source}: extension hooks may only emit "${vendorPrefix}-*" JSON Schema keywords`
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
schema[key] = value;
|
|
864
|
+
}
|
|
845
865
|
}
|
|
846
866
|
var init_ir_generator = __esm({
|
|
847
867
|
"src/json-schema/ir-generator.ts"() {
|
|
@@ -1127,7 +1147,10 @@ var init_types = __esm({
|
|
|
1127
1147
|
// src/extensions/registry.ts
|
|
1128
1148
|
function createExtensionRegistry(extensions) {
|
|
1129
1149
|
const typeMap = /* @__PURE__ */ new Map();
|
|
1150
|
+
const typeNameMap = /* @__PURE__ */ new Map();
|
|
1130
1151
|
const constraintMap = /* @__PURE__ */ new Map();
|
|
1152
|
+
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
1153
|
+
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
1131
1154
|
const annotationMap = /* @__PURE__ */ new Map();
|
|
1132
1155
|
for (const ext of extensions) {
|
|
1133
1156
|
if (ext.types !== void 0) {
|
|
@@ -1137,6 +1160,27 @@ function createExtensionRegistry(extensions) {
|
|
|
1137
1160
|
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
1138
1161
|
}
|
|
1139
1162
|
typeMap.set(qualifiedId, type);
|
|
1163
|
+
for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
|
|
1164
|
+
if (typeNameMap.has(sourceTypeName)) {
|
|
1165
|
+
throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
|
|
1166
|
+
}
|
|
1167
|
+
typeNameMap.set(sourceTypeName, {
|
|
1168
|
+
extensionId: ext.extensionId,
|
|
1169
|
+
registration: type
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
if (type.builtinConstraintBroadenings !== void 0) {
|
|
1173
|
+
for (const broadening of type.builtinConstraintBroadenings) {
|
|
1174
|
+
const key = `${qualifiedId}:${broadening.tagName}`;
|
|
1175
|
+
if (builtinBroadeningMap.has(key)) {
|
|
1176
|
+
throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
|
|
1177
|
+
}
|
|
1178
|
+
builtinBroadeningMap.set(key, {
|
|
1179
|
+
extensionId: ext.extensionId,
|
|
1180
|
+
registration: broadening
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1140
1184
|
}
|
|
1141
1185
|
}
|
|
1142
1186
|
if (ext.constraints !== void 0) {
|
|
@@ -1148,6 +1192,17 @@ function createExtensionRegistry(extensions) {
|
|
|
1148
1192
|
constraintMap.set(qualifiedId, constraint);
|
|
1149
1193
|
}
|
|
1150
1194
|
}
|
|
1195
|
+
if (ext.constraintTags !== void 0) {
|
|
1196
|
+
for (const tag of ext.constraintTags) {
|
|
1197
|
+
if (constraintTagMap.has(tag.tagName)) {
|
|
1198
|
+
throw new Error(`Duplicate custom constraint tag: "@${tag.tagName}"`);
|
|
1199
|
+
}
|
|
1200
|
+
constraintTagMap.set(tag.tagName, {
|
|
1201
|
+
extensionId: ext.extensionId,
|
|
1202
|
+
registration: tag
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1151
1206
|
if (ext.annotations !== void 0) {
|
|
1152
1207
|
for (const annotation of ext.annotations) {
|
|
1153
1208
|
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
@@ -1161,7 +1216,10 @@ function createExtensionRegistry(extensions) {
|
|
|
1161
1216
|
return {
|
|
1162
1217
|
extensions,
|
|
1163
1218
|
findType: (typeId) => typeMap.get(typeId),
|
|
1219
|
+
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
1164
1220
|
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1221
|
+
findConstraintTag: (tagName) => constraintTagMap.get(tagName),
|
|
1222
|
+
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
1165
1223
|
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1166
1224
|
};
|
|
1167
1225
|
}
|
|
@@ -1340,7 +1398,7 @@ var init_json_utils = __esm({
|
|
|
1340
1398
|
});
|
|
1341
1399
|
|
|
1342
1400
|
// src/analyzer/tsdoc-parser.ts
|
|
1343
|
-
function createFormSpecTSDocConfig() {
|
|
1401
|
+
function createFormSpecTSDocConfig(extensionTagNames = []) {
|
|
1344
1402
|
const config = new import_tsdoc.TSDocConfiguration();
|
|
1345
1403
|
for (const tagName of Object.keys(import_core3.BUILTIN_CONSTRAINT_DEFINITIONS)) {
|
|
1346
1404
|
config.addTagDefinition(
|
|
@@ -1360,13 +1418,33 @@ function createFormSpecTSDocConfig() {
|
|
|
1360
1418
|
})
|
|
1361
1419
|
);
|
|
1362
1420
|
}
|
|
1421
|
+
for (const tagName of extensionTagNames) {
|
|
1422
|
+
config.addTagDefinition(
|
|
1423
|
+
new import_tsdoc.TSDocTagDefinition({
|
|
1424
|
+
tagName: "@" + tagName,
|
|
1425
|
+
syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
|
|
1426
|
+
allowMultiple: true
|
|
1427
|
+
})
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1363
1430
|
return config;
|
|
1364
1431
|
}
|
|
1365
|
-
function getParser() {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1432
|
+
function getParser(options) {
|
|
1433
|
+
const extensionTagNames = [
|
|
1434
|
+
...options?.extensionRegistry?.extensions.flatMap(
|
|
1435
|
+
(extension) => (extension.constraintTags ?? []).map((tag) => tag.tagName)
|
|
1436
|
+
) ?? []
|
|
1437
|
+
].sort();
|
|
1438
|
+
const cacheKey = extensionTagNames.join("|");
|
|
1439
|
+
const existing = parserCache.get(cacheKey);
|
|
1440
|
+
if (existing) {
|
|
1441
|
+
return existing;
|
|
1442
|
+
}
|
|
1443
|
+
const parser = new import_tsdoc.TSDocParser(createFormSpecTSDocConfig(extensionTagNames));
|
|
1444
|
+
parserCache.set(cacheKey, parser);
|
|
1445
|
+
return parser;
|
|
1446
|
+
}
|
|
1447
|
+
function parseTSDocTags(node, file = "", options) {
|
|
1370
1448
|
const constraints = [];
|
|
1371
1449
|
const annotations = [];
|
|
1372
1450
|
let displayName;
|
|
@@ -1387,7 +1465,7 @@ function parseTSDocTags(node, file = "") {
|
|
|
1387
1465
|
if (!commentText.startsWith("/**")) {
|
|
1388
1466
|
continue;
|
|
1389
1467
|
}
|
|
1390
|
-
const parser = getParser();
|
|
1468
|
+
const parser = getParser(options);
|
|
1391
1469
|
const parserContext = parser.parseRange(
|
|
1392
1470
|
import_tsdoc.TextRange.fromStringRange(sourceText, range.pos, range.end)
|
|
1393
1471
|
);
|
|
@@ -1426,7 +1504,7 @@ function parseTSDocTags(node, file = "") {
|
|
|
1426
1504
|
const expectedType = (0, import_core3.isBuiltinConstraintName)(tagName) ? import_core3.BUILTIN_CONSTRAINT_DEFINITIONS[tagName] : void 0;
|
|
1427
1505
|
if (text === "" && expectedType !== "boolean") continue;
|
|
1428
1506
|
const provenance = provenanceForComment(range, sourceFile, file, tagName);
|
|
1429
|
-
const constraintNode = parseConstraintValue(tagName, text, provenance);
|
|
1507
|
+
const constraintNode = parseConstraintValue(tagName, text, provenance, options);
|
|
1430
1508
|
if (constraintNode) {
|
|
1431
1509
|
constraints.push(constraintNode);
|
|
1432
1510
|
}
|
|
@@ -1486,7 +1564,7 @@ function parseTSDocTags(node, file = "") {
|
|
|
1486
1564
|
annotations.push(defaultValueNode);
|
|
1487
1565
|
continue;
|
|
1488
1566
|
}
|
|
1489
|
-
const constraintNode = parseConstraintValue(tagName, text, provenance);
|
|
1567
|
+
const constraintNode = parseConstraintValue(tagName, text, provenance, options);
|
|
1490
1568
|
if (constraintNode) {
|
|
1491
1569
|
constraints.push(constraintNode);
|
|
1492
1570
|
}
|
|
@@ -1542,7 +1620,11 @@ function extractPlainText(node) {
|
|
|
1542
1620
|
}
|
|
1543
1621
|
return result;
|
|
1544
1622
|
}
|
|
1545
|
-
function parseConstraintValue(tagName, text, provenance) {
|
|
1623
|
+
function parseConstraintValue(tagName, text, provenance, options) {
|
|
1624
|
+
const customConstraint = parseExtensionConstraintValue(tagName, text, provenance, options);
|
|
1625
|
+
if (customConstraint) {
|
|
1626
|
+
return customConstraint;
|
|
1627
|
+
}
|
|
1546
1628
|
if (!(0, import_core3.isBuiltinConstraintName)(tagName)) {
|
|
1547
1629
|
return null;
|
|
1548
1630
|
}
|
|
@@ -1647,6 +1729,83 @@ function parseConstraintValue(tagName, text, provenance) {
|
|
|
1647
1729
|
provenance
|
|
1648
1730
|
};
|
|
1649
1731
|
}
|
|
1732
|
+
function parseExtensionConstraintValue(tagName, text, provenance, options) {
|
|
1733
|
+
const pathResult = extractPathTarget(text);
|
|
1734
|
+
const effectiveText = pathResult ? pathResult.remainingText : text;
|
|
1735
|
+
const path4 = pathResult?.path;
|
|
1736
|
+
const registry = options?.extensionRegistry;
|
|
1737
|
+
if (registry === void 0) {
|
|
1738
|
+
return null;
|
|
1739
|
+
}
|
|
1740
|
+
const directTag = registry.findConstraintTag(tagName);
|
|
1741
|
+
if (directTag !== void 0) {
|
|
1742
|
+
return makeCustomConstraintNode(
|
|
1743
|
+
directTag.extensionId,
|
|
1744
|
+
directTag.registration.constraintName,
|
|
1745
|
+
directTag.registration.parseValue(effectiveText),
|
|
1746
|
+
provenance,
|
|
1747
|
+
path4,
|
|
1748
|
+
registry
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
if (!(0, import_core3.isBuiltinConstraintName)(tagName)) {
|
|
1752
|
+
return null;
|
|
1753
|
+
}
|
|
1754
|
+
const broadenedTypeId = getBroadenedCustomTypeId(options?.fieldType);
|
|
1755
|
+
if (broadenedTypeId === void 0) {
|
|
1756
|
+
return null;
|
|
1757
|
+
}
|
|
1758
|
+
const broadened = registry.findBuiltinConstraintBroadening(broadenedTypeId, tagName);
|
|
1759
|
+
if (broadened === void 0) {
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
return makeCustomConstraintNode(
|
|
1763
|
+
broadened.extensionId,
|
|
1764
|
+
broadened.registration.constraintName,
|
|
1765
|
+
broadened.registration.parseValue(effectiveText),
|
|
1766
|
+
provenance,
|
|
1767
|
+
path4,
|
|
1768
|
+
registry
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
function getBroadenedCustomTypeId(fieldType) {
|
|
1772
|
+
if (fieldType?.kind === "custom") {
|
|
1773
|
+
return fieldType.typeId;
|
|
1774
|
+
}
|
|
1775
|
+
if (fieldType?.kind !== "union") {
|
|
1776
|
+
return void 0;
|
|
1777
|
+
}
|
|
1778
|
+
const customMembers = fieldType.members.filter(
|
|
1779
|
+
(member) => member.kind === "custom"
|
|
1780
|
+
);
|
|
1781
|
+
if (customMembers.length !== 1) {
|
|
1782
|
+
return void 0;
|
|
1783
|
+
}
|
|
1784
|
+
const nonCustomMembers = fieldType.members.filter((member) => member.kind !== "custom");
|
|
1785
|
+
const allOtherMembersAreNull = nonCustomMembers.every(
|
|
1786
|
+
(member) => member.kind === "primitive" && member.primitiveKind === "null"
|
|
1787
|
+
);
|
|
1788
|
+
const customMember = customMembers[0];
|
|
1789
|
+
return allOtherMembersAreNull && customMember !== void 0 ? customMember.typeId : void 0;
|
|
1790
|
+
}
|
|
1791
|
+
function makeCustomConstraintNode(extensionId, constraintName, payload, provenance, path4, registry) {
|
|
1792
|
+
const constraintId = `${extensionId}/${constraintName}`;
|
|
1793
|
+
const registration = registry.findConstraint(constraintId);
|
|
1794
|
+
if (registration === void 0) {
|
|
1795
|
+
throw new Error(
|
|
1796
|
+
`Custom TSDoc tag resolved to unregistered constraint "${constraintId}". Register the constraint before using its tag.`
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
return {
|
|
1800
|
+
kind: "constraint",
|
|
1801
|
+
constraintKind: "custom",
|
|
1802
|
+
constraintId,
|
|
1803
|
+
payload,
|
|
1804
|
+
compositionRule: registration.compositionRule,
|
|
1805
|
+
...path4 && { path: path4 },
|
|
1806
|
+
provenance
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1650
1809
|
function parseDefaultValueValue(text, provenance) {
|
|
1651
1810
|
const trimmed = text.trim();
|
|
1652
1811
|
let value;
|
|
@@ -1705,7 +1864,7 @@ function getTagCommentText(tag) {
|
|
|
1705
1864
|
}
|
|
1706
1865
|
return ts2.getTextOfJSDocComment(tag.comment);
|
|
1707
1866
|
}
|
|
1708
|
-
var ts2, import_tsdoc, import_core3, NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT,
|
|
1867
|
+
var ts2, import_tsdoc, import_core3, NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT, parserCache;
|
|
1709
1868
|
var init_tsdoc_parser = __esm({
|
|
1710
1869
|
"src/analyzer/tsdoc-parser.ts"() {
|
|
1711
1870
|
"use strict";
|
|
@@ -1727,16 +1886,17 @@ var init_tsdoc_parser = __esm({
|
|
|
1727
1886
|
maxItems: "maxItems"
|
|
1728
1887
|
};
|
|
1729
1888
|
TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["pattern", "enumOptions", "defaultValue"]);
|
|
1889
|
+
parserCache = /* @__PURE__ */ new Map();
|
|
1730
1890
|
}
|
|
1731
1891
|
});
|
|
1732
1892
|
|
|
1733
1893
|
// src/analyzer/jsdoc-constraints.ts
|
|
1734
|
-
function extractJSDocConstraintNodes(node, file = "") {
|
|
1735
|
-
const result = parseTSDocTags(node, file);
|
|
1894
|
+
function extractJSDocConstraintNodes(node, file = "", options) {
|
|
1895
|
+
const result = parseTSDocTags(node, file, options);
|
|
1736
1896
|
return [...result.constraints];
|
|
1737
1897
|
}
|
|
1738
|
-
function extractJSDocAnnotationNodes(node, file = "") {
|
|
1739
|
-
const result = parseTSDocTags(node, file);
|
|
1898
|
+
function extractJSDocAnnotationNodes(node, file = "", options) {
|
|
1899
|
+
const result = parseTSDocTags(node, file, options);
|
|
1740
1900
|
return [...result.annotations];
|
|
1741
1901
|
}
|
|
1742
1902
|
function extractDefaultValueAnnotation(initializer, file = "") {
|
|
@@ -1788,18 +1948,38 @@ function isObjectType(type) {
|
|
|
1788
1948
|
function isTypeReference(type) {
|
|
1789
1949
|
return !!(type.flags & ts4.TypeFlags.Object) && !!(type.objectFlags & ts4.ObjectFlags.Reference);
|
|
1790
1950
|
}
|
|
1791
|
-
function
|
|
1951
|
+
function makeParseOptions(extensionRegistry, fieldType) {
|
|
1952
|
+
if (extensionRegistry === void 0 && fieldType === void 0) {
|
|
1953
|
+
return void 0;
|
|
1954
|
+
}
|
|
1955
|
+
return {
|
|
1956
|
+
...extensionRegistry !== void 0 && { extensionRegistry },
|
|
1957
|
+
...fieldType !== void 0 && { fieldType }
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
1792
1961
|
const name = classDecl.name?.text ?? "AnonymousClass";
|
|
1793
1962
|
const fields = [];
|
|
1794
1963
|
const fieldLayouts = [];
|
|
1795
1964
|
const typeRegistry = {};
|
|
1796
|
-
const annotations = extractJSDocAnnotationNodes(
|
|
1965
|
+
const annotations = extractJSDocAnnotationNodes(
|
|
1966
|
+
classDecl,
|
|
1967
|
+
file,
|
|
1968
|
+
makeParseOptions(extensionRegistry)
|
|
1969
|
+
);
|
|
1797
1970
|
const visiting = /* @__PURE__ */ new Set();
|
|
1798
1971
|
const instanceMethods = [];
|
|
1799
1972
|
const staticMethods = [];
|
|
1800
1973
|
for (const member of classDecl.members) {
|
|
1801
1974
|
if (ts4.isPropertyDeclaration(member)) {
|
|
1802
|
-
const fieldNode = analyzeFieldToIR(
|
|
1975
|
+
const fieldNode = analyzeFieldToIR(
|
|
1976
|
+
member,
|
|
1977
|
+
checker,
|
|
1978
|
+
file,
|
|
1979
|
+
typeRegistry,
|
|
1980
|
+
visiting,
|
|
1981
|
+
extensionRegistry
|
|
1982
|
+
);
|
|
1803
1983
|
if (fieldNode) {
|
|
1804
1984
|
fields.push(fieldNode);
|
|
1805
1985
|
fieldLayouts.push({});
|
|
@@ -1826,15 +2006,26 @@ function analyzeClassToIR(classDecl, checker, file = "") {
|
|
|
1826
2006
|
staticMethods
|
|
1827
2007
|
};
|
|
1828
2008
|
}
|
|
1829
|
-
function analyzeInterfaceToIR(interfaceDecl, checker, file = "") {
|
|
2009
|
+
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry) {
|
|
1830
2010
|
const name = interfaceDecl.name.text;
|
|
1831
2011
|
const fields = [];
|
|
1832
2012
|
const typeRegistry = {};
|
|
1833
|
-
const annotations = extractJSDocAnnotationNodes(
|
|
2013
|
+
const annotations = extractJSDocAnnotationNodes(
|
|
2014
|
+
interfaceDecl,
|
|
2015
|
+
file,
|
|
2016
|
+
makeParseOptions(extensionRegistry)
|
|
2017
|
+
);
|
|
1834
2018
|
const visiting = /* @__PURE__ */ new Set();
|
|
1835
2019
|
for (const member of interfaceDecl.members) {
|
|
1836
2020
|
if (ts4.isPropertySignature(member)) {
|
|
1837
|
-
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2021
|
+
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2022
|
+
member,
|
|
2023
|
+
checker,
|
|
2024
|
+
file,
|
|
2025
|
+
typeRegistry,
|
|
2026
|
+
visiting,
|
|
2027
|
+
extensionRegistry
|
|
2028
|
+
);
|
|
1838
2029
|
if (fieldNode) {
|
|
1839
2030
|
fields.push(fieldNode);
|
|
1840
2031
|
}
|
|
@@ -1851,7 +2042,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "") {
|
|
|
1851
2042
|
staticMethods: []
|
|
1852
2043
|
};
|
|
1853
2044
|
}
|
|
1854
|
-
function analyzeTypeAliasToIR(typeAlias, checker, file = "") {
|
|
2045
|
+
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
|
|
1855
2046
|
if (!ts4.isTypeLiteralNode(typeAlias.type)) {
|
|
1856
2047
|
const sourceFile = typeAlias.getSourceFile();
|
|
1857
2048
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
@@ -1864,11 +2055,22 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "") {
|
|
|
1864
2055
|
const name = typeAlias.name.text;
|
|
1865
2056
|
const fields = [];
|
|
1866
2057
|
const typeRegistry = {};
|
|
1867
|
-
const annotations = extractJSDocAnnotationNodes(
|
|
2058
|
+
const annotations = extractJSDocAnnotationNodes(
|
|
2059
|
+
typeAlias,
|
|
2060
|
+
file,
|
|
2061
|
+
makeParseOptions(extensionRegistry)
|
|
2062
|
+
);
|
|
1868
2063
|
const visiting = /* @__PURE__ */ new Set();
|
|
1869
2064
|
for (const member of typeAlias.type.members) {
|
|
1870
2065
|
if (ts4.isPropertySignature(member)) {
|
|
1871
|
-
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2066
|
+
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2067
|
+
member,
|
|
2068
|
+
checker,
|
|
2069
|
+
file,
|
|
2070
|
+
typeRegistry,
|
|
2071
|
+
visiting,
|
|
2072
|
+
extensionRegistry
|
|
2073
|
+
);
|
|
1872
2074
|
if (fieldNode) {
|
|
1873
2075
|
fields.push(fieldNode);
|
|
1874
2076
|
}
|
|
@@ -1887,7 +2089,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "") {
|
|
|
1887
2089
|
}
|
|
1888
2090
|
};
|
|
1889
2091
|
}
|
|
1890
|
-
function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
2092
|
+
function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
1891
2093
|
if (!ts4.isIdentifier(prop.name)) {
|
|
1892
2094
|
return null;
|
|
1893
2095
|
}
|
|
@@ -1895,14 +2097,26 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
|
1895
2097
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1896
2098
|
const optional = prop.questionToken !== void 0;
|
|
1897
2099
|
const provenance = provenanceForNode(prop, file);
|
|
1898
|
-
let type = resolveTypeNode(
|
|
2100
|
+
let type = resolveTypeNode(
|
|
2101
|
+
tsType,
|
|
2102
|
+
checker,
|
|
2103
|
+
file,
|
|
2104
|
+
typeRegistry,
|
|
2105
|
+
visiting,
|
|
2106
|
+
prop,
|
|
2107
|
+
extensionRegistry
|
|
2108
|
+
);
|
|
1899
2109
|
const constraints = [];
|
|
1900
2110
|
if (prop.type) {
|
|
1901
|
-
constraints.push(
|
|
2111
|
+
constraints.push(
|
|
2112
|
+
...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
|
|
2113
|
+
);
|
|
1902
2114
|
}
|
|
1903
|
-
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
2115
|
+
constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
|
|
1904
2116
|
let annotations = [];
|
|
1905
|
-
annotations.push(
|
|
2117
|
+
annotations.push(
|
|
2118
|
+
...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
|
|
2119
|
+
);
|
|
1906
2120
|
const defaultAnnotation = extractDefaultValueAnnotation(prop.initializer, file);
|
|
1907
2121
|
if (defaultAnnotation && !annotations.some((a) => a.annotationKind === "defaultValue")) {
|
|
1908
2122
|
annotations.push(defaultAnnotation);
|
|
@@ -1918,7 +2132,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
|
1918
2132
|
provenance
|
|
1919
2133
|
};
|
|
1920
2134
|
}
|
|
1921
|
-
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting) {
|
|
2135
|
+
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
1922
2136
|
if (!ts4.isIdentifier(prop.name)) {
|
|
1923
2137
|
return null;
|
|
1924
2138
|
}
|
|
@@ -1926,14 +2140,26 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1926
2140
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1927
2141
|
const optional = prop.questionToken !== void 0;
|
|
1928
2142
|
const provenance = provenanceForNode(prop, file);
|
|
1929
|
-
let type = resolveTypeNode(
|
|
2143
|
+
let type = resolveTypeNode(
|
|
2144
|
+
tsType,
|
|
2145
|
+
checker,
|
|
2146
|
+
file,
|
|
2147
|
+
typeRegistry,
|
|
2148
|
+
visiting,
|
|
2149
|
+
prop,
|
|
2150
|
+
extensionRegistry
|
|
2151
|
+
);
|
|
1930
2152
|
const constraints = [];
|
|
1931
2153
|
if (prop.type) {
|
|
1932
|
-
constraints.push(
|
|
2154
|
+
constraints.push(
|
|
2155
|
+
...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
|
|
2156
|
+
);
|
|
1933
2157
|
}
|
|
1934
|
-
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
2158
|
+
constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
|
|
1935
2159
|
let annotations = [];
|
|
1936
|
-
annotations.push(
|
|
2160
|
+
annotations.push(
|
|
2161
|
+
...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
|
|
2162
|
+
);
|
|
1937
2163
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1938
2164
|
return {
|
|
1939
2165
|
kind: "field",
|
|
@@ -2007,7 +2233,66 @@ function parseEnumMemberDisplayName(value) {
|
|
|
2007
2233
|
if (label === "") return null;
|
|
2008
2234
|
return { value: match[1], label };
|
|
2009
2235
|
}
|
|
2010
|
-
function
|
|
2236
|
+
function resolveRegisteredCustomType(sourceNode, extensionRegistry, checker) {
|
|
2237
|
+
if (sourceNode === void 0 || extensionRegistry === void 0) {
|
|
2238
|
+
return null;
|
|
2239
|
+
}
|
|
2240
|
+
const typeNode = extractTypeNodeFromSource(sourceNode);
|
|
2241
|
+
if (typeNode === void 0) {
|
|
2242
|
+
return null;
|
|
2243
|
+
}
|
|
2244
|
+
return resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker);
|
|
2245
|
+
}
|
|
2246
|
+
function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker) {
|
|
2247
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
2248
|
+
return resolveRegisteredCustomTypeFromTypeNode(typeNode.type, extensionRegistry, checker);
|
|
2249
|
+
}
|
|
2250
|
+
const typeName = getTypeNodeRegistrationName(typeNode);
|
|
2251
|
+
if (typeName === null) {
|
|
2252
|
+
return null;
|
|
2253
|
+
}
|
|
2254
|
+
const registration = extensionRegistry.findTypeByName(typeName);
|
|
2255
|
+
if (registration !== void 0) {
|
|
2256
|
+
return {
|
|
2257
|
+
kind: "custom",
|
|
2258
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
2259
|
+
payload: null
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
|
|
2263
|
+
const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts4.isTypeAliasDeclaration);
|
|
2264
|
+
if (aliasDecl !== void 0) {
|
|
2265
|
+
return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
return null;
|
|
2269
|
+
}
|
|
2270
|
+
function extractTypeNodeFromSource(sourceNode) {
|
|
2271
|
+
if (ts4.isPropertyDeclaration(sourceNode) || ts4.isPropertySignature(sourceNode) || ts4.isParameter(sourceNode) || ts4.isTypeAliasDeclaration(sourceNode)) {
|
|
2272
|
+
return sourceNode.type;
|
|
2273
|
+
}
|
|
2274
|
+
if (ts4.isTypeNode(sourceNode)) {
|
|
2275
|
+
return sourceNode;
|
|
2276
|
+
}
|
|
2277
|
+
return void 0;
|
|
2278
|
+
}
|
|
2279
|
+
function getTypeNodeRegistrationName(typeNode) {
|
|
2280
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
2281
|
+
return ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
|
|
2282
|
+
}
|
|
2283
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
2284
|
+
return getTypeNodeRegistrationName(typeNode.type);
|
|
2285
|
+
}
|
|
2286
|
+
if (typeNode.kind === ts4.SyntaxKind.BigIntKeyword || typeNode.kind === ts4.SyntaxKind.StringKeyword || typeNode.kind === ts4.SyntaxKind.NumberKeyword || typeNode.kind === ts4.SyntaxKind.BooleanKeyword) {
|
|
2287
|
+
return typeNode.getText();
|
|
2288
|
+
}
|
|
2289
|
+
return null;
|
|
2290
|
+
}
|
|
2291
|
+
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
|
|
2292
|
+
const customType = resolveRegisteredCustomType(sourceNode, extensionRegistry, checker);
|
|
2293
|
+
if (customType) {
|
|
2294
|
+
return customType;
|
|
2295
|
+
}
|
|
2011
2296
|
if (type.flags & ts4.TypeFlags.String) {
|
|
2012
2297
|
return { kind: "primitive", primitiveKind: "string" };
|
|
2013
2298
|
}
|
|
@@ -2036,26 +2321,50 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2036
2321
|
};
|
|
2037
2322
|
}
|
|
2038
2323
|
if (type.isUnion()) {
|
|
2039
|
-
return resolveUnionType(
|
|
2324
|
+
return resolveUnionType(
|
|
2325
|
+
type,
|
|
2326
|
+
checker,
|
|
2327
|
+
file,
|
|
2328
|
+
typeRegistry,
|
|
2329
|
+
visiting,
|
|
2330
|
+
sourceNode,
|
|
2331
|
+
extensionRegistry
|
|
2332
|
+
);
|
|
2040
2333
|
}
|
|
2041
2334
|
if (checker.isArrayType(type)) {
|
|
2042
|
-
return resolveArrayType(
|
|
2335
|
+
return resolveArrayType(
|
|
2336
|
+
type,
|
|
2337
|
+
checker,
|
|
2338
|
+
file,
|
|
2339
|
+
typeRegistry,
|
|
2340
|
+
visiting,
|
|
2341
|
+
sourceNode,
|
|
2342
|
+
extensionRegistry
|
|
2343
|
+
);
|
|
2043
2344
|
}
|
|
2044
2345
|
if (isObjectType(type)) {
|
|
2045
|
-
return resolveObjectType(type, checker, file, typeRegistry, visiting);
|
|
2346
|
+
return resolveObjectType(type, checker, file, typeRegistry, visiting, extensionRegistry);
|
|
2046
2347
|
}
|
|
2047
2348
|
return { kind: "primitive", primitiveKind: "string" };
|
|
2048
2349
|
}
|
|
2049
|
-
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode) {
|
|
2350
|
+
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
|
|
2050
2351
|
const typeName = getNamedTypeName(type);
|
|
2051
2352
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2052
2353
|
if (typeName && typeName in typeRegistry) {
|
|
2053
2354
|
return { kind: "reference", name: typeName, typeArguments: [] };
|
|
2054
2355
|
}
|
|
2055
2356
|
const allTypes = type.types;
|
|
2357
|
+
const unionMemberTypeNodes = extractUnionMemberTypeNodes(sourceNode, checker);
|
|
2358
|
+
const nonNullSourceNodes = unionMemberTypeNodes.filter(
|
|
2359
|
+
(memberTypeNode) => !isNullishTypeNode(resolveAliasedTypeNode(memberTypeNode, checker))
|
|
2360
|
+
);
|
|
2056
2361
|
const nonNullTypes = allTypes.filter(
|
|
2057
|
-
(
|
|
2362
|
+
(memberType) => !(memberType.flags & (ts4.TypeFlags.Null | ts4.TypeFlags.Undefined))
|
|
2058
2363
|
);
|
|
2364
|
+
const nonNullMembers = nonNullTypes.map((memberType, index) => ({
|
|
2365
|
+
memberType,
|
|
2366
|
+
sourceNode: nonNullSourceNodes.length === nonNullTypes.length ? nonNullSourceNodes[index] : void 0
|
|
2367
|
+
}));
|
|
2059
2368
|
const hasNull = allTypes.some((t) => t.flags & ts4.TypeFlags.Null);
|
|
2060
2369
|
const memberDisplayNames = /* @__PURE__ */ new Map();
|
|
2061
2370
|
if (namedDecl) {
|
|
@@ -2072,7 +2381,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2072
2381
|
if (!typeName) {
|
|
2073
2382
|
return result;
|
|
2074
2383
|
}
|
|
2075
|
-
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file) : void 0;
|
|
2384
|
+
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2076
2385
|
typeRegistry[typeName] = {
|
|
2077
2386
|
name: typeName,
|
|
2078
2387
|
type: result,
|
|
@@ -2120,14 +2429,15 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2120
2429
|
} : enumNode;
|
|
2121
2430
|
return registerNamed(result);
|
|
2122
2431
|
}
|
|
2123
|
-
if (
|
|
2432
|
+
if (nonNullMembers.length === 1 && nonNullMembers[0]) {
|
|
2124
2433
|
const inner = resolveTypeNode(
|
|
2125
|
-
|
|
2434
|
+
nonNullMembers[0].memberType,
|
|
2126
2435
|
checker,
|
|
2127
2436
|
file,
|
|
2128
2437
|
typeRegistry,
|
|
2129
2438
|
visiting,
|
|
2130
|
-
sourceNode
|
|
2439
|
+
nonNullMembers[0].sourceNode ?? sourceNode,
|
|
2440
|
+
extensionRegistry
|
|
2131
2441
|
);
|
|
2132
2442
|
const result = hasNull ? {
|
|
2133
2443
|
kind: "union",
|
|
@@ -2135,21 +2445,38 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2135
2445
|
} : inner;
|
|
2136
2446
|
return registerNamed(result);
|
|
2137
2447
|
}
|
|
2138
|
-
const members =
|
|
2139
|
-
(
|
|
2448
|
+
const members = nonNullMembers.map(
|
|
2449
|
+
({ memberType, sourceNode: memberSourceNode }) => resolveTypeNode(
|
|
2450
|
+
memberType,
|
|
2451
|
+
checker,
|
|
2452
|
+
file,
|
|
2453
|
+
typeRegistry,
|
|
2454
|
+
visiting,
|
|
2455
|
+
memberSourceNode ?? sourceNode,
|
|
2456
|
+
extensionRegistry
|
|
2457
|
+
)
|
|
2140
2458
|
);
|
|
2141
2459
|
if (hasNull) {
|
|
2142
2460
|
members.push({ kind: "primitive", primitiveKind: "null" });
|
|
2143
2461
|
}
|
|
2144
2462
|
return registerNamed({ kind: "union", members });
|
|
2145
2463
|
}
|
|
2146
|
-
function resolveArrayType(type, checker, file, typeRegistry, visiting) {
|
|
2464
|
+
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
|
|
2147
2465
|
const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
|
|
2148
2466
|
const elementType = typeArgs?.[0];
|
|
2149
|
-
const
|
|
2467
|
+
const elementSourceNode = extractArrayElementTypeNode(sourceNode, checker);
|
|
2468
|
+
const items = elementType ? resolveTypeNode(
|
|
2469
|
+
elementType,
|
|
2470
|
+
checker,
|
|
2471
|
+
file,
|
|
2472
|
+
typeRegistry,
|
|
2473
|
+
visiting,
|
|
2474
|
+
elementSourceNode,
|
|
2475
|
+
extensionRegistry
|
|
2476
|
+
) : { kind: "primitive", primitiveKind: "string" };
|
|
2150
2477
|
return { kind: "array", items };
|
|
2151
2478
|
}
|
|
2152
|
-
function tryResolveRecordType(type, checker, file, typeRegistry, visiting) {
|
|
2479
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
2153
2480
|
if (type.getProperties().length > 0) {
|
|
2154
2481
|
return null;
|
|
2155
2482
|
}
|
|
@@ -2157,7 +2484,15 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting) {
|
|
|
2157
2484
|
if (!indexInfo) {
|
|
2158
2485
|
return null;
|
|
2159
2486
|
}
|
|
2160
|
-
const valueType = resolveTypeNode(
|
|
2487
|
+
const valueType = resolveTypeNode(
|
|
2488
|
+
indexInfo.type,
|
|
2489
|
+
checker,
|
|
2490
|
+
file,
|
|
2491
|
+
typeRegistry,
|
|
2492
|
+
visiting,
|
|
2493
|
+
void 0,
|
|
2494
|
+
extensionRegistry
|
|
2495
|
+
);
|
|
2161
2496
|
return { kind: "record", valueType };
|
|
2162
2497
|
}
|
|
2163
2498
|
function typeNodeContainsReference(type, targetName) {
|
|
@@ -2185,7 +2520,7 @@ function typeNodeContainsReference(type, targetName) {
|
|
|
2185
2520
|
}
|
|
2186
2521
|
}
|
|
2187
2522
|
}
|
|
2188
|
-
function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
2523
|
+
function resolveObjectType(type, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
2189
2524
|
const typeName = getNamedTypeName(type);
|
|
2190
2525
|
const namedTypeName = typeName ?? void 0;
|
|
2191
2526
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
@@ -2216,7 +2551,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2216
2551
|
return { kind: "reference", name: namedTypeName, typeArguments: [] };
|
|
2217
2552
|
}
|
|
2218
2553
|
}
|
|
2219
|
-
const recordNode = tryResolveRecordType(
|
|
2554
|
+
const recordNode = tryResolveRecordType(
|
|
2555
|
+
type,
|
|
2556
|
+
checker,
|
|
2557
|
+
file,
|
|
2558
|
+
typeRegistry,
|
|
2559
|
+
visiting,
|
|
2560
|
+
extensionRegistry
|
|
2561
|
+
);
|
|
2220
2562
|
if (recordNode) {
|
|
2221
2563
|
visiting.delete(type);
|
|
2222
2564
|
if (namedTypeName !== void 0 && shouldRegisterNamedType) {
|
|
@@ -2225,7 +2567,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2225
2567
|
clearNamedTypeRegistration();
|
|
2226
2568
|
return recordNode;
|
|
2227
2569
|
}
|
|
2228
|
-
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file) : void 0;
|
|
2570
|
+
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2229
2571
|
typeRegistry[namedTypeName] = {
|
|
2230
2572
|
name: namedTypeName,
|
|
2231
2573
|
type: recordNode,
|
|
@@ -2237,7 +2579,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2237
2579
|
return recordNode;
|
|
2238
2580
|
}
|
|
2239
2581
|
const properties = [];
|
|
2240
|
-
const fieldInfoMap = getNamedTypeFieldNodeInfoMap(
|
|
2582
|
+
const fieldInfoMap = getNamedTypeFieldNodeInfoMap(
|
|
2583
|
+
type,
|
|
2584
|
+
checker,
|
|
2585
|
+
file,
|
|
2586
|
+
typeRegistry,
|
|
2587
|
+
visiting,
|
|
2588
|
+
extensionRegistry
|
|
2589
|
+
);
|
|
2241
2590
|
for (const prop of type.getProperties()) {
|
|
2242
2591
|
const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
2243
2592
|
if (!declaration) continue;
|
|
@@ -2249,7 +2598,8 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2249
2598
|
file,
|
|
2250
2599
|
typeRegistry,
|
|
2251
2600
|
visiting,
|
|
2252
|
-
declaration
|
|
2601
|
+
declaration,
|
|
2602
|
+
extensionRegistry
|
|
2253
2603
|
);
|
|
2254
2604
|
const fieldNodeInfo = fieldInfoMap?.get(prop.name);
|
|
2255
2605
|
properties.push({
|
|
@@ -2268,7 +2618,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2268
2618
|
additionalProperties: true
|
|
2269
2619
|
};
|
|
2270
2620
|
if (namedTypeName !== void 0 && shouldRegisterNamedType) {
|
|
2271
|
-
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file) : void 0;
|
|
2621
|
+
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2272
2622
|
typeRegistry[namedTypeName] = {
|
|
2273
2623
|
name: namedTypeName,
|
|
2274
2624
|
type: objectNode,
|
|
@@ -2279,7 +2629,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
2279
2629
|
}
|
|
2280
2630
|
return objectNode;
|
|
2281
2631
|
}
|
|
2282
|
-
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting) {
|
|
2632
|
+
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
2283
2633
|
const symbols = [type.getSymbol(), type.aliasSymbol].filter(
|
|
2284
2634
|
(s) => s?.declarations != null && s.declarations.length > 0
|
|
2285
2635
|
);
|
|
@@ -2291,7 +2641,14 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
2291
2641
|
const map = /* @__PURE__ */ new Map();
|
|
2292
2642
|
for (const member of classDecl.members) {
|
|
2293
2643
|
if (ts4.isPropertyDeclaration(member) && ts4.isIdentifier(member.name)) {
|
|
2294
|
-
const fieldNode = analyzeFieldToIR(
|
|
2644
|
+
const fieldNode = analyzeFieldToIR(
|
|
2645
|
+
member,
|
|
2646
|
+
checker,
|
|
2647
|
+
file,
|
|
2648
|
+
typeRegistry,
|
|
2649
|
+
visiting,
|
|
2650
|
+
extensionRegistry
|
|
2651
|
+
);
|
|
2295
2652
|
if (fieldNode) {
|
|
2296
2653
|
map.set(fieldNode.name, {
|
|
2297
2654
|
constraints: [...fieldNode.constraints],
|
|
@@ -2305,7 +2662,14 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
2305
2662
|
}
|
|
2306
2663
|
const interfaceDecl = declarations.find(ts4.isInterfaceDeclaration);
|
|
2307
2664
|
if (interfaceDecl) {
|
|
2308
|
-
return buildFieldNodeInfoMap(
|
|
2665
|
+
return buildFieldNodeInfoMap(
|
|
2666
|
+
interfaceDecl.members,
|
|
2667
|
+
checker,
|
|
2668
|
+
file,
|
|
2669
|
+
typeRegistry,
|
|
2670
|
+
visiting,
|
|
2671
|
+
extensionRegistry
|
|
2672
|
+
);
|
|
2309
2673
|
}
|
|
2310
2674
|
const typeAliasDecl = declarations.find(ts4.isTypeAliasDeclaration);
|
|
2311
2675
|
if (typeAliasDecl && ts4.isTypeLiteralNode(typeAliasDecl.type)) {
|
|
@@ -2314,17 +2678,68 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
2314
2678
|
checker,
|
|
2315
2679
|
file,
|
|
2316
2680
|
typeRegistry,
|
|
2317
|
-
visiting
|
|
2681
|
+
visiting,
|
|
2682
|
+
extensionRegistry
|
|
2318
2683
|
);
|
|
2319
2684
|
}
|
|
2320
2685
|
}
|
|
2321
2686
|
return null;
|
|
2322
2687
|
}
|
|
2323
|
-
function
|
|
2688
|
+
function extractArrayElementTypeNode(sourceNode, checker) {
|
|
2689
|
+
const typeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
2690
|
+
if (typeNode === void 0) {
|
|
2691
|
+
return void 0;
|
|
2692
|
+
}
|
|
2693
|
+
const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
|
|
2694
|
+
if (ts4.isArrayTypeNode(resolvedTypeNode)) {
|
|
2695
|
+
return resolvedTypeNode.elementType;
|
|
2696
|
+
}
|
|
2697
|
+
if (ts4.isTypeReferenceNode(resolvedTypeNode) && ts4.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
|
|
2698
|
+
return resolvedTypeNode.typeArguments[0];
|
|
2699
|
+
}
|
|
2700
|
+
return void 0;
|
|
2701
|
+
}
|
|
2702
|
+
function extractUnionMemberTypeNodes(sourceNode, checker) {
|
|
2703
|
+
const typeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
2704
|
+
if (!typeNode) {
|
|
2705
|
+
return [];
|
|
2706
|
+
}
|
|
2707
|
+
const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
|
|
2708
|
+
return ts4.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
|
|
2709
|
+
}
|
|
2710
|
+
function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
|
|
2711
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
2712
|
+
return resolveAliasedTypeNode(typeNode.type, checker, visited);
|
|
2713
|
+
}
|
|
2714
|
+
if (!ts4.isTypeReferenceNode(typeNode) || !ts4.isIdentifier(typeNode.typeName)) {
|
|
2715
|
+
return typeNode;
|
|
2716
|
+
}
|
|
2717
|
+
const symbol = checker.getSymbolAtLocation(typeNode.typeName);
|
|
2718
|
+
const aliasDecl = symbol?.declarations?.find(ts4.isTypeAliasDeclaration);
|
|
2719
|
+
if (aliasDecl === void 0 || visited.has(aliasDecl)) {
|
|
2720
|
+
return typeNode;
|
|
2721
|
+
}
|
|
2722
|
+
visited.add(aliasDecl);
|
|
2723
|
+
return resolveAliasedTypeNode(aliasDecl.type, checker, visited);
|
|
2724
|
+
}
|
|
2725
|
+
function isNullishTypeNode(typeNode) {
|
|
2726
|
+
if (typeNode.kind === ts4.SyntaxKind.NullKeyword || typeNode.kind === ts4.SyntaxKind.UndefinedKeyword) {
|
|
2727
|
+
return true;
|
|
2728
|
+
}
|
|
2729
|
+
return ts4.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts4.SyntaxKind.NullKeyword || typeNode.literal.kind === ts4.SyntaxKind.UndefinedKeyword);
|
|
2730
|
+
}
|
|
2731
|
+
function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, extensionRegistry) {
|
|
2324
2732
|
const map = /* @__PURE__ */ new Map();
|
|
2325
2733
|
for (const member of members) {
|
|
2326
2734
|
if (ts4.isPropertySignature(member)) {
|
|
2327
|
-
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2735
|
+
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2736
|
+
member,
|
|
2737
|
+
checker,
|
|
2738
|
+
file,
|
|
2739
|
+
typeRegistry,
|
|
2740
|
+
visiting,
|
|
2741
|
+
extensionRegistry
|
|
2742
|
+
);
|
|
2328
2743
|
if (fieldNode) {
|
|
2329
2744
|
map.set(fieldNode.name, {
|
|
2330
2745
|
constraints: [...fieldNode.constraints],
|
|
@@ -2336,7 +2751,7 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting) {
|
|
|
2336
2751
|
}
|
|
2337
2752
|
return map;
|
|
2338
2753
|
}
|
|
2339
|
-
function extractTypeAliasConstraintNodes(typeNode, checker, file, depth = 0) {
|
|
2754
|
+
function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegistry, depth = 0) {
|
|
2340
2755
|
if (!ts4.isTypeReferenceNode(typeNode)) return [];
|
|
2341
2756
|
if (depth >= MAX_ALIAS_CHAIN_DEPTH) {
|
|
2342
2757
|
const aliasName = typeNode.typeName.getText();
|
|
@@ -2349,8 +2764,29 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, depth = 0) {
|
|
|
2349
2764
|
const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
|
|
2350
2765
|
if (!aliasDecl) return [];
|
|
2351
2766
|
if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2767
|
+
const aliasFieldType = resolveTypeNode(
|
|
2768
|
+
checker.getTypeAtLocation(aliasDecl.type),
|
|
2769
|
+
checker,
|
|
2770
|
+
file,
|
|
2771
|
+
{},
|
|
2772
|
+
/* @__PURE__ */ new Set(),
|
|
2773
|
+
aliasDecl.type,
|
|
2774
|
+
extensionRegistry
|
|
2775
|
+
);
|
|
2776
|
+
const constraints = extractJSDocConstraintNodes(
|
|
2777
|
+
aliasDecl,
|
|
2778
|
+
file,
|
|
2779
|
+
makeParseOptions(extensionRegistry, aliasFieldType)
|
|
2780
|
+
);
|
|
2781
|
+
constraints.push(
|
|
2782
|
+
...extractTypeAliasConstraintNodes(
|
|
2783
|
+
aliasDecl.type,
|
|
2784
|
+
checker,
|
|
2785
|
+
file,
|
|
2786
|
+
extensionRegistry,
|
|
2787
|
+
depth + 1
|
|
2788
|
+
)
|
|
2789
|
+
);
|
|
2354
2790
|
return constraints;
|
|
2355
2791
|
}
|
|
2356
2792
|
function provenanceForNode(node, file) {
|
|
@@ -2461,10 +2897,10 @@ var init_class_analyzer = __esm({
|
|
|
2461
2897
|
});
|
|
2462
2898
|
|
|
2463
2899
|
// src/generators/class-schema.ts
|
|
2464
|
-
function generateClassSchemas(analysis, source) {
|
|
2900
|
+
function generateClassSchemas(analysis, source, options) {
|
|
2465
2901
|
const ir = canonicalizeTSDoc(analysis, source);
|
|
2466
2902
|
return {
|
|
2467
|
-
jsonSchema: generateJsonSchemaFromIR(ir),
|
|
2903
|
+
jsonSchema: generateJsonSchemaFromIR(ir, options),
|
|
2468
2904
|
uiSchema: generateUiSchemaFromIR(ir)
|
|
2469
2905
|
};
|
|
2470
2906
|
}
|
|
@@ -2474,27 +2910,54 @@ function generateSchemasFromClass(options) {
|
|
|
2474
2910
|
if (!classDecl) {
|
|
2475
2911
|
throw new Error(`Class "${options.className}" not found in ${options.filePath}`);
|
|
2476
2912
|
}
|
|
2477
|
-
const analysis = analyzeClassToIR(
|
|
2478
|
-
|
|
2913
|
+
const analysis = analyzeClassToIR(
|
|
2914
|
+
classDecl,
|
|
2915
|
+
ctx.checker,
|
|
2916
|
+
options.filePath,
|
|
2917
|
+
options.extensionRegistry
|
|
2918
|
+
);
|
|
2919
|
+
return generateClassSchemas(
|
|
2920
|
+
analysis,
|
|
2921
|
+
{ file: options.filePath },
|
|
2922
|
+
{
|
|
2923
|
+
extensionRegistry: options.extensionRegistry,
|
|
2924
|
+
vendorPrefix: options.vendorPrefix
|
|
2925
|
+
}
|
|
2926
|
+
);
|
|
2479
2927
|
}
|
|
2480
2928
|
function generateSchemas(options) {
|
|
2481
2929
|
const ctx = createProgramContext(options.filePath);
|
|
2482
2930
|
const source = { file: options.filePath };
|
|
2483
2931
|
const classDecl = findClassByName(ctx.sourceFile, options.typeName);
|
|
2484
2932
|
if (classDecl) {
|
|
2485
|
-
const analysis = analyzeClassToIR(
|
|
2486
|
-
|
|
2933
|
+
const analysis = analyzeClassToIR(
|
|
2934
|
+
classDecl,
|
|
2935
|
+
ctx.checker,
|
|
2936
|
+
options.filePath,
|
|
2937
|
+
options.extensionRegistry
|
|
2938
|
+
);
|
|
2939
|
+
return generateClassSchemas(analysis, source, options);
|
|
2487
2940
|
}
|
|
2488
2941
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, options.typeName);
|
|
2489
2942
|
if (interfaceDecl) {
|
|
2490
|
-
const analysis = analyzeInterfaceToIR(
|
|
2491
|
-
|
|
2943
|
+
const analysis = analyzeInterfaceToIR(
|
|
2944
|
+
interfaceDecl,
|
|
2945
|
+
ctx.checker,
|
|
2946
|
+
options.filePath,
|
|
2947
|
+
options.extensionRegistry
|
|
2948
|
+
);
|
|
2949
|
+
return generateClassSchemas(analysis, source, options);
|
|
2492
2950
|
}
|
|
2493
2951
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, options.typeName);
|
|
2494
2952
|
if (typeAlias) {
|
|
2495
|
-
const result = analyzeTypeAliasToIR(
|
|
2953
|
+
const result = analyzeTypeAliasToIR(
|
|
2954
|
+
typeAlias,
|
|
2955
|
+
ctx.checker,
|
|
2956
|
+
options.filePath,
|
|
2957
|
+
options.extensionRegistry
|
|
2958
|
+
);
|
|
2496
2959
|
if (result.ok) {
|
|
2497
|
-
return generateClassSchemas(result.analysis, source);
|
|
2960
|
+
return generateClassSchemas(result.analysis, source, options);
|
|
2498
2961
|
}
|
|
2499
2962
|
throw new Error(result.error);
|
|
2500
2963
|
}
|
|
@@ -2516,7 +2979,7 @@ var init_class_schema = __esm({
|
|
|
2516
2979
|
// src/generators/mixed-authoring.ts
|
|
2517
2980
|
function buildMixedAuthoringSchemas(options) {
|
|
2518
2981
|
const { filePath, typeName, overlays, ...schemaOptions } = options;
|
|
2519
|
-
const analysis = analyzeNamedType(filePath, typeName);
|
|
2982
|
+
const analysis = analyzeNamedType(filePath, typeName, schemaOptions.extensionRegistry);
|
|
2520
2983
|
const composedAnalysis = composeAnalysisWithOverlays(analysis, overlays);
|
|
2521
2984
|
const ir = canonicalizeTSDoc(composedAnalysis, { file: filePath });
|
|
2522
2985
|
return {
|
|
@@ -2524,20 +2987,20 @@ function buildMixedAuthoringSchemas(options) {
|
|
|
2524
2987
|
uiSchema: generateUiSchemaFromIR(ir)
|
|
2525
2988
|
};
|
|
2526
2989
|
}
|
|
2527
|
-
function analyzeNamedType(filePath, typeName) {
|
|
2990
|
+
function analyzeNamedType(filePath, typeName, extensionRegistry) {
|
|
2528
2991
|
const ctx = createProgramContext(filePath);
|
|
2529
2992
|
const source = { file: filePath };
|
|
2530
2993
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
2531
2994
|
if (classDecl !== null) {
|
|
2532
|
-
return analyzeClassToIR(classDecl, ctx.checker, source.file);
|
|
2995
|
+
return analyzeClassToIR(classDecl, ctx.checker, source.file, extensionRegistry);
|
|
2533
2996
|
}
|
|
2534
2997
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
|
|
2535
2998
|
if (interfaceDecl !== null) {
|
|
2536
|
-
return analyzeInterfaceToIR(interfaceDecl, ctx.checker, source.file);
|
|
2999
|
+
return analyzeInterfaceToIR(interfaceDecl, ctx.checker, source.file, extensionRegistry);
|
|
2537
3000
|
}
|
|
2538
3001
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
|
|
2539
3002
|
if (typeAlias !== null) {
|
|
2540
|
-
const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, source.file);
|
|
3003
|
+
const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, source.file, extensionRegistry);
|
|
2541
3004
|
if (result.ok) {
|
|
2542
3005
|
return result.analysis;
|
|
2543
3006
|
}
|
|
@@ -2616,7 +3079,7 @@ function assertSupportedOverlayField(baseField, overlayField) {
|
|
|
2616
3079
|
`Mixed-authoring overlay for "${baseField.name}" cannot define constraints; keep constraints on the static model`
|
|
2617
3080
|
);
|
|
2618
3081
|
}
|
|
2619
|
-
if (overlayField.required) {
|
|
3082
|
+
if (overlayField.required && !baseField.required) {
|
|
2620
3083
|
throw new Error(
|
|
2621
3084
|
`Mixed-authoring overlay for "${baseField.name}" cannot change requiredness; keep requiredness on the static model`
|
|
2622
3085
|
);
|
|
@@ -2706,7 +3169,7 @@ function mergeAnnotations(baseAnnotations, overlayAnnotations) {
|
|
|
2706
3169
|
const overlayOnly = overlayAnnotations.filter(
|
|
2707
3170
|
(annotation) => !baseKeys.has(annotationKey(annotation))
|
|
2708
3171
|
);
|
|
2709
|
-
return [...
|
|
3172
|
+
return [...baseAnnotations, ...overlayOnly];
|
|
2710
3173
|
}
|
|
2711
3174
|
function annotationKey(annotation) {
|
|
2712
3175
|
return annotation.annotationKind === "custom" ? `${annotation.annotationKind}:${annotation.annotationId}` : annotation.annotationKind;
|